x86_vcpu 0.6.2

x86 Virtual CPU implementation for the Arceos Hypervisor
Documentation
const VMX_VCPU: &str = include_str!("vmx/vcpu.rs");
const SVM_VCPU: &str = include_str!("svm/vcpu.rs");

fn section<'a>(source: &'a str, start: &str, end: &str) -> &'a str {
    source
        .split_once(start)
        .unwrap_or_else(|| panic!("missing section start {start:?}"))
        .1
        .split_once(end)
        .unwrap_or_else(|| panic!("missing section end {end:?}"))
        .0
}

fn assert_in_order(source: &str, operations: &[&str]) {
    let mut cursor = 0;
    for operation in operations {
        let offset = source[cursor..]
            .find(operation)
            .unwrap_or_else(|| panic!("missing ordered operation {operation:?}"));
        cursor += offset + operation.len();
    }
}

#[test]
fn vmx_refreshes_host_tls_before_guest_entry_and_returns_without_rust_calls() {
    let bind = section(
        VMX_VCPU,
        "pub fn bind_to_current_processor",
        "/// Unbind this [`VmxVcpu`]",
    );
    assert_in_order(bind, &["vmx::vmptrld", "self.setup_vmcs_host()?"]);

    let host = section(VMX_VCPU, "fn setup_vmcs_host", "fn setup_vmcs_guest");
    for register in [
        "VmcsHostNW::FS_BASE.write(Msr::IA32_FS_BASE.read() as _)?",
        "VmcsHostNW::GS_BASE.write(Msr::IA32_GS_BASE.read() as _)?",
        "VmcsHostNW::RIP.write(Self::vmx_exit as *const () as usize)?",
    ] {
        assert!(
            host.contains(register),
            "missing host register {register:?}"
        );
    }

    let exit = section(
        VMX_VCPU,
        "unsafe extern \"C\" fn vmx_exit",
        "fn vmx_entry_failed",
    );
    assert_in_order(
        exit,
        &[
            "save_regs_to_stack!()",
            "restore_regs_from_stack!()",
            "\"ret\"",
        ],
    );
    assert!(!exit.contains("\"call "));
}

#[test]
fn svm_restores_host_tls_inside_the_naked_world_switch() {
    let switch = section(
        SVM_VCPU,
        "unsafe extern \"C\" fn svm_world_switch",
        "/// Host save area used to restore CPU state touched by SVM VMLOAD/VMSAVE.",
    );
    assert!(switch.contains("naked_asm!"));
    assert_in_order(
        switch,
        &["vmload rax", "vmrun rax", "vmsave rax", "vmload rax", "ret"],
    );
    assert_eq!(switch.match_indices("vmload rax").count(), 2);
    assert!(!switch.contains("\"call "));

    let prepare = section(SVM_VCPU, "fn prepare_world_switch", "pub unsafe fn svm_run");
    assert!(!prepare.contains("instructions::vmload"));
    let run = section(SVM_VCPU, "pub unsafe fn svm_run", "\n    }\n}");
    assert!(run.contains("svm_world_switch("));
    assert!(!run.contains("instructions::vmload"));
    assert!(!run.contains("instructions::vmsave"));
}