From 7eac2ceab8f72a7d286236d7b2a6dbc385987531 Mon Sep 17 00:00:00 2001 From: Bill Nguyen Date: Mon, 25 May 2026 13:05:00 +1000 Subject: [PATCH] x86/c_traps.c: add clobbers in 32-bit VMX restore The inline assembly blocks for vmlaunch and vmresume in the 32-bit restore_vmx() function manually pop guest state into all general-purpose registers. Previously, these registers were not included in the inline assembly clobber list. If a VM entry fails, execution falls through to the vmlaunch_failed() C function. Because the compiler is unaware that the registers were overwritten, it may generate code for the failure handler that relies on destroyed state. Signed-off-by: Bill Nguyen --- src/arch/x86/32/c_traps.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/arch/x86/32/c_traps.c b/src/arch/x86/32/c_traps.c index 68b4dc0e8..7d27325b5 100644 --- a/src/arch/x86/32/c_traps.c +++ b/src/arch/x86/32/c_traps.c @@ -36,11 +36,12 @@ static void NORETURN restore_vmx(tcb_t *cur_thread, vcpu_t *vcpu) /* Do not support breakpoints in VMs, so just disable all breakpoints */ loadAllDisabledBreakpointState(cur_thread); #endif + word_t *guest_regs_ptr = vcpu->gp_registers; if (vcpu->launched) { /* attempt to do a vmresume */ asm volatile( // Set our stack pointer to the top of the tcb so we can efficiently pop - "movl %0, %%esp\n" + "movl %[guest_regs], %%esp\n" "popl %%eax\n" "popl %%ebx\n" "popl %%ecx\n" @@ -57,18 +58,17 @@ static void NORETURN restore_vmx(tcb_t *cur_thread, vcpu_t *vcpu) "leal kernel_stack_alloc + %c1, %%esp\n" #endif "call vmlaunch_failed\n" - : - : "r"(&vcpu->gp_registers[VCPU_EAX]), - "i"(BIT(CONFIG_KERNEL_STACK_BITS) - sizeof(word_t)) + : [guest_regs] "+a"(guest_regs_ptr) + : "i"(BIT(CONFIG_KERNEL_STACK_BITS) - sizeof(word_t)) // Clobber memory so the compiler is forced to complete all stores // before running this assembler - : "memory" + : "ebx", "ecx", "edx", "esi", "edi", "ebp", "memory" ); } else { /* attempt to do a vmlaunch */ asm volatile( // Set our stack pointer to the top of the tcb so we can efficiently pop - "movl %0, %%esp\n" + "movl %[guest_regs], %%esp\n" "popl %%eax\n" "popl %%ebx\n" "popl %%ecx\n" @@ -85,12 +85,11 @@ static void NORETURN restore_vmx(tcb_t *cur_thread, vcpu_t *vcpu) "leal kernel_stack_alloc + %c1, %%esp\n" #endif "call vmlaunch_failed\n" - : - : "r"(&vcpu->gp_registers[VCPU_EAX]), - "i"(BIT(CONFIG_KERNEL_STACK_BITS) - sizeof(word_t)) + : [guest_regs] "+a"(guest_regs_ptr) + : "i"(BIT(CONFIG_KERNEL_STACK_BITS) - sizeof(word_t)) // Clobber memory so the compiler is forced to complete all stores // before running this assembler - : "memory" + : "ebx", "ecx", "edx", "esi", "edi", "ebp", "memory" ); } UNREACHABLE();