fix vm entry/exit

This commit is contained in:
Masato Imai
2025-05-15 17:37:56 +00:00
parent 6c4849d1af
commit c186f86c81
3 changed files with 244 additions and 184 deletions

View File

@ -29,12 +29,13 @@ run-args = [
"-display", "-display",
"none", "none",
"-m", "-m",
"512M", "256M",
"-cpu", "-cpu",
"host", "host",
"-enable-kvm", "-enable-kvm",
"-monitor", "-monitor",
"telnet:127.0.0.1:5555,server,nowait" "telnet:127.0.0.1:5555,server,nowait",
"-s"
] ]
test-args = [ test-args = [
"-device", "-device",

View File

@ -5,133 +5,120 @@ use super::{register::GuestRegisters, vcpu::VCpu};
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
extern "C" { extern "C" {
pub fn asm_vm_entry(vcpu: *mut VCpu) -> u16; pub fn asm_vm_entry(vcpu: *mut VCpu) -> u16;
pub fn asm_vm_entry_resume(vcpu: *mut VCpu) -> u16; pub fn asm_vmexit_handler() -> !;
pub fn guest_entry() -> !;
pub fn vmexit_handler_asm() -> !;
} }
const GUEST_REGS_OFFSET: usize = offset_of!(VCpu, guest_registers);
const LAUNCH_DONE_OFFSET: usize = offset_of!(VCpu, launch_done);
const RAX_OFFSET: usize = offset_of!(GuestRegisters, rax);
const RCX_OFFSET: usize = offset_of!(GuestRegisters, rcx);
const RDX_OFFSET: usize = offset_of!(GuestRegisters, rdx);
const RBX_OFFSET: usize = offset_of!(GuestRegisters, rbx);
const RSI_OFFSET: usize = offset_of!(GuestRegisters, rsi);
const RDI_OFFSET: usize = offset_of!(GuestRegisters, rdi);
const RBP_OFFSET: usize = offset_of!(GuestRegisters, rbp);
const R8_OFFSET: usize = offset_of!(GuestRegisters, r8);
const R9_OFFSET: usize = offset_of!(GuestRegisters, r9);
const R10_OFFSET: usize = offset_of!(GuestRegisters, r10);
const R11_OFFSET: usize = offset_of!(GuestRegisters, r11);
const R12_OFFSET: usize = offset_of!(GuestRegisters, r12);
const R13_OFFSET: usize = offset_of!(GuestRegisters, r13);
const R14_OFFSET: usize = offset_of!(GuestRegisters, r14);
const R15_OFFSET: usize = offset_of!(GuestRegisters, r15);
const XMM0_OFFSET: usize = offset_of!(GuestRegisters, xmm0);
const XMM1_OFFSET: usize = offset_of!(GuestRegisters, xmm1);
const XMM2_OFFSET: usize = offset_of!(GuestRegisters, xmm2);
const XMM3_OFFSET: usize = offset_of!(GuestRegisters, xmm3);
const XMM4_OFFSET: usize = offset_of!(GuestRegisters, xmm4);
const XMM5_OFFSET: usize = offset_of!(GuestRegisters, xmm5);
const XMM6_OFFSET: usize = offset_of!(GuestRegisters, xmm6);
const XMM7_OFFSET: usize = offset_of!(GuestRegisters, xmm7);
global_asm!( global_asm!(
".global asm_vm_entry_resume",
".type asm_vm_entry_resume, @function",
"asm_vm_entry_resume:",
"push rbp",
"push r15",
"push r14",
"push r13",
"push r12",
"push rbx",
"lea rbx, [rdi + {0}]",
"push rbx",
"push rdi",
"lea rdi, [rsp + 8]",
"call set_host_stack",
"pop rdi",
"mov rax, rdi",
"mov rcx, [rax+{2}]",
"mov rdx, [rax+{3}]",
"mov rbx, [rax+{4}]",
"mov rsi, [rax+{5}]",
"mov rdi, [rax+{6}]",
"mov rbp, [rax+{7}]",
"mov r8, [rax+{8}]",
"mov r9, [rax+{9}]",
"mov r10, [rax+{10}]",
"mov r11, [rax+{11}]",
"mov r12, [rax+{12}]",
"mov r13, [rax+{13}]",
"mov r14, [rax+{14}]",
"mov r15, [rax+{15}]",
"movaps xmm0, [rax+{17}]",
"movaps xmm1, [rax+{18}]",
"movaps xmm2, [rax+{19}]",
"movaps xmm3, [rax+{20}]",
"movaps xmm4, [rax+{21}]",
"movaps xmm5, [rax+{22}]",
"movaps xmm6, [rax+{23}]",
"movaps xmm7, [rax+{24}]",
"mov rax, [rax+{16}]",
"vmresume",
"mov ax, 1",
"add rsp, 8",
"pop rbx",
"pop r12",
"pop r13",
"pop r14",
"pop r15",
"pop rbp",
"ret",
".size asm_vm_entry_resume, . - asm_vm_entry_resume",
".global asm_vm_entry", ".global asm_vm_entry",
".type asm_vm_entry, @function", ".type asm_vm_entry, @function",
"asm_vm_entry:", "asm_vm_entry:", // rdi = *VCpu
"push rbp", "push rbp",
"push r15", "push r15",
"push r14", "push r14",
"push r13", "push r13",
"push r12", "push r12",
"push rbx", "push rbx",
"lea rbx, [rdi + {0}]", /*
"push rbx", stack:
"push rdi", +-----+
"lea rdi, [rsp + 8]", | RBX |
+-----+
| R12 |
+-----+
| R13 |
+-----+
| R14 |
+-----+
| R15 |
+-----+
| RBP |
+-----+
| RIP |
+-----+
regs:
RDI = *VCpu
*/
"lea rbx, [rdi + {guest_regs_offset}]", // rbx = *guest_regs
"push rbx", // push *guest_regs
"push rdi", // push *VCpu
"lea rdi, [rsp + 8]", // rdi = rsp + 8 = *guest_regs
"call set_host_stack", "call set_host_stack",
"pop rdi", "pop rdi", // rdi = *VCpu
"test byte ptr [rdi + {1}], 1", "test byte ptr [rdi + {launch_done_offset}], 1", // flag = launch_done ? 1 : 0
"mov rax, rdi", /*
"mov rcx, [rax+{2}]", stack:
"mov rdx, [rax+{3}]", +-------------+
"mov rbx, [rax+{4}]", | *guest_regs |
"mov rsi, [rax+{5}]", +-------------+
"mov rdi, [rax+{6}]", | RBX |
"mov rbp, [rax+{7}]", +-------------+
"mov r8, [rax+{8}]", | R12 |
"mov r9, [rax+{9}]", +-------------+
"mov r10, [rax+{10}]", | R13 |
"mov r11, [rax+{11}]", +-------------+
"mov r12, [rax+{12}]", | R14 |
"mov r13, [rax+{13}]", +-------------+
"mov r14, [rax+{14}]", | R15 |
"mov r15, [rax+{15}]", +-------------+
"mov rax, [rax+{16}]", | RBP |
"movaps xmm0, [rax+{17}]", +-------------+
"movaps xmm1, [rax+{18}]", | RIP |
"movaps xmm2, [rax+{19}]", +-------------+
"movaps xmm3, [rax+{20}]", regs:
"movaps xmm4, [rax+{21}]", RDI = *VCpu
"movaps xmm5, [rax+{22}]", RBX = *guest_regs
"movaps xmm6, [rax+{23}]", */
"movaps xmm7, [rax+{24}]", "mov rax, rbx", // rax = *guest_regs
"mov rcx, [rax+{reg_offset_rcx}]", // rcx = guest_regs.rcx
"mov rdx, [rax+{reg_offset_rdx}]", // rdx = guest_regs.rdx
"mov rbx, [rax+{reg_offset_rbx}]", // rbx = guest_regs.rbx
"mov rsi, [rax+{reg_offset_rsi}] ", // rsi = guest_regs.rsi
"mov rdi, [rax+{reg_offset_rdi}]", // rdi = guest_regs.rdi
"mov rbp, [rax+{reg_offset_rbp}]", // rbp = guest_regs.rbp
"mov r8, [rax+{reg_offset_r8}]", // r8 = guest_regs.r8
"mov r9, [rax+{reg_offset_r9}]", // r9 = guest_regs.r9
"mov r10, [rax+{reg_offset_r10}]", // r10 = guest_regs.r10
"mov r11, [rax+{reg_offset_r11}]", // r11 = guest_regs.r11
"mov r12, [rax+{reg_offset_r12}]", // r12 = guest_regs.r12
"mov r13, [rax+{reg_offset_r13}]", // r13 = guest_regs.r13
"mov r14, [rax+{reg_offset_r14}]", // r14 = guest_regs.r14
"mov r15, [rax+{reg_offset_r15}]", // r15 = guest_regs.r15
"movaps xmm0, [rax+{reg_offset_xmm0}]", // xmm0 = guest_regs.xmm0
"movaps xmm1, [rax+{reg_offset_xmm1}]", // xmm1 = guest_regs.xmm1
"movaps xmm2, [rax+{reg_offset_xmm2}]", // xmm2 = guest_regs.xmm2
"movaps xmm3, [rax+{reg_offset_xmm3}]", // xmm3 = guest_regs.xmm3
"movaps xmm4, [rax+{reg_offset_xmm4}]", // xmm4 = guest_regs.xmm4
"movaps xmm5, [rax+{reg_offset_xmm5}]", // xmm5 = guest_regs.xmm5
"movaps xmm6, [rax+{reg_offset_xmm6}]", // xmm6 = guest_regs.xmm6
"movaps xmm7, [rax+{reg_offset_xmm7}]", // xmm7 = guest_regs.xmm7
"mov rax, [rax+{reg_offset_rax}]", // rax = guest_regs.rax
/*
stack:
+-------------+
| *guest_regs |
+-------------+
| RBX |
+-------------+
| R12 |
+-------------+
| R13 |
+-------------+
| R14 |
+-------------+
| R15 |
+-------------+
| RBP |
+-------------+
| RIP |
+-------------+
*/
"jz 2f",
"vmresume",
"2:",
"vmlaunch", "vmlaunch",
"mov ax, 1", "mov ax, 1",
"add rsp, 8", "add rsp, 0x8",
"pop rbx", "pop rbx",
"pop r12", "pop r12",
"pop r13", "pop r13",
@ -139,70 +126,144 @@ global_asm!(
"pop r15", "pop r15",
"pop rbp", "pop rbp",
"ret", "ret",
".size asm_vm_entry, . - asm_vm_entry", ".size asm_vm_entry, . - asm_vm_entry",
".global vmexit_handler_asm", ".global asm_vmexit_handler",
".type vmexit_handler_asm, @function", ".type asm_vmexit_handler, @function",
"vmexit_handler_asm:", "asm_vmexit_handler:",
"cli",
/*
stack:
+-------------+
| *guest_regs |
+-------------+
| RBX |
+-------------+
| R12 |
+-------------+
| R13 |
+-------------+
| R14 |
+-------------+
| R15 |
+-------------+
| RBP |
+-------------+
| RIP |
+-------------+
regs:
RAX = guest CPU's rax
*/
"push rax", "push rax",
"mov rax, [rsp+8]", "mov rax, qword ptr [rsp + 0x8]", // rax = *guest_regs
"pop [rax+{16}]", /*
"add rsp, 8", stack:
"mov [rax+{2}], rcx", +-------------+
"mov [rax+{3}], rdx", | guest RAX |
"mov [rax+{4}], rbx", +-------------+
"mov [rax+{5}], rsi", | *guest_regs |
"mov [rax+{6}], rdi", +-------------+
"mov [rax+{7}], rbp", | RBX |
"mov [rax+{8}], r8", +-------------+
"mov [rax+{9}], r9", | R12 |
"mov [rax+{10}], r10", +-------------+
"mov [rax+{11}], r11", | R13 |
"mov [rax+{12}], r12", +-------------+
"mov [rax+{13}], r13", | R14 |
"mov [rax+{14}], r14", +-------------+
"mov [rax+{15}], r15", | R15 |
"movaps [rax+{17}], xmm0", +-------------+
"movaps [rax+{18}], xmm1", | RBP |
"movaps [rax+{19}], xmm2", +-------------+
"movaps [rax+{20}], xmm3", | RIP |
"movaps [rax+{21}], xmm4", +-------------+
"movaps [rax+{22}], xmm5", */
"movaps [rax+{23}], xmm6",
"movaps [rax+{24}], xmm7", "pop [rax + {reg_offset_rax}]", // guest_regs.rax = guest CPU's rax
"add rsp, 0x8", // discard *guest_regs
/*
stack:
+-------------+
| RBX |
+-------------+
| R12 |
+-------------+
| R13 |
+-------------+
| R14 |
+-------------+
| R15 |
+-------------+
| RBP |
+-------------+
| RIP |
+-------------+
*/
// save rcx, rdx, rbx, rsi, rdi, rbp, r8~15, xmm0~7
"mov [rax + {reg_offset_rcx}], rcx",
"mov [rax + {reg_offset_rdx}], rdx",
"mov [rax + {reg_offset_rbx}], rbx",
"mov [rax + {reg_offset_rsi}], rsi",
"mov [rax + {reg_offset_rdi}], rdi",
"mov [rax + {reg_offset_rbp}], rbp",
"mov [rax + {reg_offset_r8}], r8",
"mov [rax + {reg_offset_r9}], r9",
"mov [rax + {reg_offset_r10}], r10",
"mov [rax + {reg_offset_r11}], r11",
"mov [rax + {reg_offset_r12}], r12",
"mov [rax + {reg_offset_r13}], r13",
"mov [rax + {reg_offset_r14}], r14",
"mov [rax + {reg_offset_r15}], r15",
"movaps [rax + {reg_offset_xmm0}], xmm0",
"movaps [rax + {reg_offset_xmm1}], xmm1",
"movaps [rax + {reg_offset_xmm2}], xmm2",
"movaps [rax + {reg_offset_xmm3}], xmm3",
"movaps [rax + {reg_offset_xmm4}], xmm4",
"movaps [rax + {reg_offset_xmm5}], xmm5",
"movaps [rax + {reg_offset_xmm6}], xmm6",
"movaps [rax + {reg_offset_xmm7}], xmm7",
"pop rbx", "pop rbx",
"pop r12", "pop r12",
"pop r13", "pop r13",
"pop r14", "pop r14",
"pop r15", "pop r15",
"pop rbp", "pop rbp",
"mov rax, 0", /*
stack:
+-------------+
| RIP |
+-------------+
*/
"mov rax, 0x0",
"ret", "ret",
".size vmexit_handler_asm, . - vmexit_handler_asm",
const GUEST_REGS_OFFSET, ".size asm_vmexit_handler, . - asm_vmexit_handler",
const LAUNCH_DONE_OFFSET,
const RCX_OFFSET, guest_regs_offset = const offset_of!(VCpu, guest_registers),
const RDX_OFFSET, launch_done_offset = const offset_of!(VCpu, launch_done),
const RBX_OFFSET, reg_offset_rax = const offset_of!(GuestRegisters, rax),
const RSI_OFFSET, reg_offset_rcx = const offset_of!(GuestRegisters, rcx),
const RDI_OFFSET, reg_offset_rdx = const offset_of!(GuestRegisters, rdx),
const RBP_OFFSET, reg_offset_rbx = const offset_of!(GuestRegisters, rbx),
const R8_OFFSET, reg_offset_rsi = const offset_of!(GuestRegisters, rsi),
const R9_OFFSET, reg_offset_rdi = const offset_of!(GuestRegisters, rdi),
const R10_OFFSET, reg_offset_rbp = const offset_of!(GuestRegisters, rbp),
const R11_OFFSET, reg_offset_r8 = const offset_of!(GuestRegisters, r8),
const R12_OFFSET, reg_offset_r9 = const offset_of!(GuestRegisters, r9),
const R13_OFFSET, reg_offset_r10 = const offset_of!(GuestRegisters, r10),
const R14_OFFSET, reg_offset_r11 = const offset_of!(GuestRegisters, r11),
const R15_OFFSET, reg_offset_r12 = const offset_of!(GuestRegisters, r12),
const RAX_OFFSET, reg_offset_r13 = const offset_of!(GuestRegisters, r13),
const XMM0_OFFSET, reg_offset_r14 = const offset_of!(GuestRegisters, r14),
const XMM1_OFFSET, reg_offset_r15 = const offset_of!(GuestRegisters, r15),
const XMM2_OFFSET, reg_offset_xmm0 = const offset_of!(GuestRegisters, xmm0),
const XMM3_OFFSET, reg_offset_xmm1 = const offset_of!(GuestRegisters, xmm1),
const XMM4_OFFSET, reg_offset_xmm2 = const offset_of!(GuestRegisters, xmm2),
const XMM5_OFFSET, reg_offset_xmm3 = const offset_of!(GuestRegisters, xmm3),
const XMM6_OFFSET, reg_offset_xmm4 = const offset_of!(GuestRegisters, xmm4),
const XMM7_OFFSET, reg_offset_xmm5 = const offset_of!(GuestRegisters, xmm5),
reg_offset_xmm6 = const offset_of!(GuestRegisters, xmm6),
reg_offset_xmm7 = const offset_of!(GuestRegisters, xmm7),
); );

View File

@ -29,11 +29,12 @@ use super::{
vmxon::Vmxon, vmxon::Vmxon,
}; };
#[repr(C)]
pub struct VCpu { pub struct VCpu {
pub guest_registers: GuestRegisters,
pub vmxon: Vmxon, pub vmxon: Vmxon,
pub vmcs: Vmcs, pub vmcs: Vmcs,
pub phys_mem_offset: u64, pub phys_mem_offset: u64,
pub guest_registers: GuestRegisters,
pub launch_done: bool, pub launch_done: bool,
pub ept: EPT, pub ept: EPT,
pub eptp: EPTP, pub eptp: EPTP,
@ -301,7 +302,7 @@ impl VCpu {
vmwrite(vmcs::host::CR3, cr3())?; vmwrite(vmcs::host::CR3, cr3())?;
vmwrite(vmcs::host::CR4, cr4().bits() as u64)?; vmwrite(vmcs::host::CR4, cr4().bits() as u64)?;
vmwrite(vmcs::host::RIP, crate::vmm::asm::vmexit_handler_asm as u64)?; vmwrite(vmcs::host::RIP, crate::vmm::asm::asm_vmexit_handler as u64)?;
vmwrite( vmwrite(
vmcs::host::RSP, vmcs::host::RSP,
VirtAddr::from_ptr(&raw mut TEMP_STACK).as_u64() + TEMP_STACK_SIZE as u64, VirtAddr::from_ptr(&raw mut TEMP_STACK).as_u64() + TEMP_STACK_SIZE as u64,
@ -359,7 +360,10 @@ impl VCpu {
vmwrite(vmcs::guest::CR3, cr3())?; vmwrite(vmcs::guest::CR3, cr3())?;
vmwrite( vmwrite(
vmcs::guest::CR4, vmcs::guest::CR4,
vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits(), vmread(vmcs::guest::CR4)?
| 1 << 5
| 1 << 7
| Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits(),
)?; )?;
vmwrite(vmcs::guest::CS_BASE, 0)?; vmwrite(vmcs::guest::CS_BASE, 0)?;
@ -512,17 +516,11 @@ impl VCpu {
let success = { let success = {
let result: u16; let result: u16;
self.print_guest_regs(); self.print_guest_regs();
if !self.launch_done {
unsafe { unsafe {
result = crate::vmm::asm::asm_vm_entry(self as *mut _); result = crate::vmm::asm::asm_vm_entry(self as *mut _);
}; };
result == 0 result == 0
} else {
unsafe {
result = crate::vmm::asm::asm_vm_entry_resume(self as *mut _);
};
result == 0
}
}; };
if !self.launch_done && success { if !self.launch_done && success {