Move the INTO=>#OF test, along with its more precise checking of the exit interrupt info, to the generic nVMX exceptions test. Move the helper that generates #OF to processor.h so that it can be reused by nSVM for an identical test. Note, this effectively adds new checks for all other vectors, i.e. affects more vectors than just #OF. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/processor.h | 35 +++++++++++++++++++++++ x86/vmx_tests.c | 67 +++++++++------------------------------------ 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index c3d112f..5865933 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -834,6 +834,41 @@ static inline uint64_t generate_usermode_ac(void) return 0; } +/* + * Switch from 64-bit to 32-bit mode and generate #OF via INTO. Note, if RIP + * or RSP holds a 64-bit value, this helper will NOT generate #OF. + */ +static inline void generate_of(void) +{ + struct far_pointer32 fp = { + .offset = (uintptr_t)&&into, + .selector = KERNEL_CS32, + }; + uintptr_t rsp; + + asm volatile ("mov %%rsp, %0" : "=r"(rsp)); + + if (fp.offset != (uintptr_t)&&into) { + printf("Code address too high.\n"); + return; + } + if ((u32)rsp != rsp) { + printf("Stack address too high.\n"); + return; + } + + asm goto ("lcall *%0" : : "m" (fp) : "rax" : into); + return; +into: + asm volatile (".code32;" + "movl $0x7fffffff, %eax;" + "addl %eax, %eax;" + "into;" + "lret;" + ".code64"); + __builtin_unreachable(); +} + static inline u8 pmu_version(void) { return cpuid(10).a & 0xff; diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 2ed20ec..edb8062 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -2161,57 +2161,6 @@ static int int3_exit_handler(union exit_reason exit_reason) return VMX_TEST_VMEXIT; } -static int into_init(struct vmcs *vmcs) -{ - vmcs_write(EXC_BITMAP, ~0u); - return VMX_TEST_START; -} - -static void into_guest_main(void) -{ - struct far_pointer32 fp = { - .offset = (uintptr_t)&&into, - .selector = KERNEL_CS32, - }; - uintptr_t rsp; - - asm volatile ("mov %%rsp, %0" : "=r"(rsp)); - - if (fp.offset != (uintptr_t)&&into) { - printf("Code address too high.\n"); - return; - } - if ((u32)rsp != rsp) { - printf("Stack address too high.\n"); - return; - } - - asm goto ("lcall *%0" : : "m" (fp) : "rax" : into); - return; -into: - asm volatile (".code32;" - "movl $0x7fffffff, %eax;" - "addl %eax, %eax;" - "into;" - "lret;" - ".code64"); - __builtin_unreachable(); -} - -static int into_exit_handler(union exit_reason exit_reason) -{ - u32 intr_info = vmcs_read(EXI_INTR_INFO); - - report(exit_reason.basic == VMX_EXC_NMI && - (intr_info & INTR_INFO_VALID_MASK) && - (intr_info & INTR_INFO_VECTOR_MASK) == OF_VECTOR && - ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> - INTR_INFO_INTR_TYPE_SHIFT) == VMX_INTR_TYPE_SOFT_EXCEPTION, - "L1 intercepts #OF"); - - return VMX_TEST_VMEXIT; -} - static void exit_monitor_from_l2_main(void) { printf("Calling exit(0) from l2...\n"); @@ -10741,6 +10690,7 @@ struct vmx_exception_test vmx_exception_tests[] = { { DB_VECTOR, generate_single_step_db }, { BP_VECTOR, generate_bp }, { AC_VECTOR, vmx_l2_ac_test }, + { OF_VECTOR, generate_of }, }; static u8 vmx_exception_test_vector; @@ -10769,14 +10719,24 @@ static void handle_exception_in_l2(u8 vector) static void handle_exception_in_l1(u32 vector) { u32 old_eb = vmcs_read(EXC_BITMAP); + u32 intr_type; + u32 intr_info; vmcs_write(EXC_BITMAP, old_eb | (1u << vector)); enter_guest(); + if (vector == BP_VECTOR || vector == OF_VECTOR) + intr_type = VMX_INTR_TYPE_SOFT_EXCEPTION; + else + intr_type = VMX_INTR_TYPE_HARD_EXCEPTION; + + intr_info = vmcs_read(EXI_INTR_INFO); report((vmcs_read(EXI_REASON) == VMX_EXC_NMI) && - ((vmcs_read(EXI_INTR_INFO) & 0xff) == vector), - "%s handled by L1", exception_mnemonic(vector)); + (intr_info & INTR_INFO_VALID_MASK) && + (intr_info & INTR_INFO_VECTOR_MASK) == vector && + ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> INTR_INFO_INTR_TYPE_SHIFT) == intr_type, + "%s correctly routed to L1", exception_mnemonic(vector)); vmcs_write(EXC_BITMAP, old_eb); } @@ -10836,7 +10796,6 @@ struct vmx_test vmx_tests[] = { { "disable RDTSCP", disable_rdtscp_init, disable_rdtscp_main, disable_rdtscp_exit_handler, NULL, {0} }, { "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} }, - { "into", into_init, into_guest_main, into_exit_handler, NULL, {0} }, { "exit_monitor_from_l2_test", NULL, exit_monitor_from_l2_main, exit_monitor_from_l2_handler, NULL, {0} }, { "invalid_msr", invalid_msr_init, invalid_msr_main, -- 2.38.0.rc1.362.ged0d419d3c-goog