Track and handle SVM's exit_code as an unsigned 64-bit value. Per the APM, offset 0x70 is a single 64-bit value: 070h 63:0 EXITCODE And a sane reading of the error values defined in "Table C-1. SVM Intercept Codes" is that negative values use the full 64 bits: –1 VMEXIT_INVALID Invalid guest state in VMCB. –2 VMEXIT_BUSYBUSY bit was set in the VMSA –3 VMEXIT_IDLE_REQUIREDThe sibling thread is not in an idle state -4 VMEXIT_INVALID_PMC Invalid PMC state And that interpretation is confirmed by testing on Milan and Turin (by setting bits in CR0[63:32] to generate VMEXIT_INVALID on VMRUN). Furthermore, Xen has treated exitcode as a 64-bit value since HVM support was adding in 2006 (see Xen commit d1bd157fbc ("Big merge the HVM full-virtualisation abstractions.")). Note, the SVM tests will fail when on KVM builds without commit f402ecd7a8b6 ("KVM: nSVM: Set exit_code_hi to -1 when synthesizing SVM_EXIT_ERR (failed VMRUN)"). Link: https://lore.kernel.org/all/20251113225621.1688428-1-seanjc@google.com Signed-off-by: Sean Christopherson --- x86/svm.c | 4 +-- x86/svm.h | 9 +++---- x86/svm_npt.c | 4 +-- x86/svm_tests.c | 66 ++++++++++++++++++++++++------------------------- 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/x86/svm.c b/x86/svm.c index de9eb194..3f6d70dc 100644 --- a/x86/svm.c +++ b/x86/svm.c @@ -227,7 +227,7 @@ void svm_setup_vmrun(u64 rip) vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); } -int __svm_vmrun(u64 rip) +u64 __svm_vmrun(u64 rip) { svm_setup_vmrun(rip); regs.rdi = (ulong)v2_test; @@ -243,7 +243,7 @@ int __svm_vmrun(u64 rip) return (vmcb->control.exit_code); } -int svm_vmrun(void) +u64 svm_vmrun(void) { return __svm_vmrun((u64)test_thunk); } diff --git a/x86/svm.h b/x86/svm.h index 264583a6..02d9bac3 100644 --- a/x86/svm.h +++ b/x86/svm.h @@ -88,8 +88,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area { u32 int_vector; u32 int_state; u8 reserved_3[4]; - u32 exit_code; - u32 exit_code_hi; + u64 exit_code; u64 exit_info_1; u64 exit_info_2; u32 exit_int_info; @@ -354,7 +353,7 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_EXIT_MWAIT_COND 0x08c #define SVM_EXIT_NPF 0x400 -#define SVM_EXIT_ERR -1 +#define SVM_EXIT_ERR -1ull #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) @@ -435,8 +434,8 @@ void vmcb_ident(struct vmcb *vmcb); struct regs get_regs(void); void vmmcall(void); void svm_setup_vmrun(u64 rip); -int __svm_vmrun(u64 rip); -int svm_vmrun(void); +u64 __svm_vmrun(u64 rip); +u64 svm_vmrun(void); void test_set_guest(test_guest_func func); extern struct vmcb *vmcb; diff --git a/x86/svm_npt.c b/x86/svm_npt.c index bd5e8f35..24d7707b 100644 --- a/x86/svm_npt.c +++ b/x86/svm_npt.c @@ -219,7 +219,7 @@ static void __svm_npt_rsvd_bits_test(u64 * pxe, u64 rsvd_bits, u64 efer, ulong cr4, u64 guest_efer, ulong guest_cr4) { u64 pxe_orig = *pxe; - int exit_reason; + u64 exit_reason; u64 pfec; wrmsr(MSR_EFER, efer); @@ -233,7 +233,7 @@ static void __svm_npt_rsvd_bits_test(u64 * pxe, u64 rsvd_bits, u64 efer, exit_reason = svm_vmrun(); report(exit_reason == SVM_EXIT_NPF, - "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%x", rsvd_bits, + "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%lx", rsvd_bits, exit_reason); if (pxe == npt_get_pdpe((u64) basic_guest_main) || pxe == npt_get_pml4e()) { diff --git a/x86/svm_tests.c b/x86/svm_tests.c index 37616476..8ce3cc2e 100644 --- a/x86/svm_tests.c +++ b/x86/svm_tests.c @@ -103,7 +103,7 @@ static bool finished_rsm_intercept(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_RSM) { - report_fail("VMEXIT not due to rsm. Exit reason 0x%x", + report_fail("VMEXIT not due to rsm. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -113,7 +113,7 @@ static bool finished_rsm_intercept(struct svm_test *test) case 1: if (vmcb->control.exit_code != SVM_EXIT_EXCP_BASE + UD_VECTOR) { - report_fail("VMEXIT not due to #UD. Exit reason 0x%x", + report_fail("VMEXIT not due to #UD. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -971,7 +971,7 @@ static void svm_tsc_scale_run_testcase(u64 duration, start_tsc = rdtsc(); if (svm_vmrun() != SVM_EXIT_VMMCALL) - report_fail("unexpected vm exit code 0x%x", vmcb->control.exit_code); + report_fail("unexpected vm exit code 0x%lx", vmcb->control.exit_code); actual_duration = (rdtsc() - start_tsc) >> TSC_SHIFT; @@ -1190,7 +1190,7 @@ static bool pending_event_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_INTR) { - report_fail("VMEXIT not due to pending interrupt. Exit reason 0x%x", + report_fail("VMEXIT not due to pending interrupt. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1271,7 +1271,7 @@ static void pending_event_cli_test(struct svm_test *test) static bool pending_event_cli_finished(struct svm_test *test) { report_svm_guest(vmcb->control.exit_code == SVM_EXIT_VMMCALL, test, - "Wanted VMMCALL VM-Exit, got exit reason 0x%x", + "Wanted VMMCALL VM-Exit, got exit reason 0x%lx", vmcb->control.exit_code); switch (get_test_stage(test)) { @@ -1394,7 +1394,7 @@ static bool interrupt_finished(struct svm_test *test) case 0: case 2: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1407,7 +1407,7 @@ static bool interrupt_finished(struct svm_test *test) case 1: case 3: if (vmcb->control.exit_code != SVM_EXIT_INTR) { - report_fail("VMEXIT not due to intr intercept. Exit reason 0x%x", + report_fail("VMEXIT not due to intr intercept. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1470,7 +1470,7 @@ static bool nmi_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1481,7 +1481,7 @@ static bool nmi_finished(struct svm_test *test) case 1: if (vmcb->control.exit_code != SVM_EXIT_NMI) { - report_fail("VMEXIT not due to NMI intercept. Exit reason 0x%x", + report_fail("VMEXIT not due to NMI intercept. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1563,7 +1563,7 @@ static bool nmi_hlt_finished(struct svm_test *test) switch (get_test_stage(test)) { case 1: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1574,7 +1574,7 @@ static bool nmi_hlt_finished(struct svm_test *test) case 2: if (vmcb->control.exit_code != SVM_EXIT_NMI) { - report_fail("VMEXIT not due to NMI intercept. Exit reason 0x%x", + report_fail("VMEXIT not due to NMI intercept. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1624,7 +1624,7 @@ static bool vnmi_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_ERR) { - report_fail("Wanted ERR VM-Exit, got 0x%x", + report_fail("Wanted ERR VM-Exit, got 0x%lx", vmcb->control.exit_code); return true; } @@ -1635,7 +1635,7 @@ static bool vnmi_finished(struct svm_test *test) case 1: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("Wanted VMMCALL VM-Exit, got 0x%x", + report_fail("Wanted VMMCALL VM-Exit, got 0x%lx", vmcb->control.exit_code); return true; } @@ -1646,7 +1646,7 @@ static bool vnmi_finished(struct svm_test *test) case 2: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("Wanted VMMCALL VM-Exit, got 0x%x", + report_fail("Wanted VMMCALL VM-Exit, got 0x%lx", vmcb->control.exit_code); return true; } @@ -1697,7 +1697,7 @@ static bool exc_inject_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1707,7 +1707,7 @@ static bool exc_inject_finished(struct svm_test *test) case 1: if (vmcb->control.exit_code != SVM_EXIT_ERR) { - report_fail("VMEXIT not due to error. Exit reason 0x%x", + report_fail("VMEXIT not due to error. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1717,7 +1717,7 @@ static bool exc_inject_finished(struct svm_test *test) case 2: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1795,7 +1795,7 @@ static bool virq_inject_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1811,7 +1811,7 @@ static bool virq_inject_finished(struct svm_test *test) case 1: if (vmcb->control.exit_code != SVM_EXIT_VINTR) { - report_fail("VMEXIT not due to vintr. Exit reason 0x%x", + report_fail("VMEXIT not due to vintr. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1824,7 +1824,7 @@ static bool virq_inject_finished(struct svm_test *test) case 2: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1838,7 +1838,7 @@ static bool virq_inject_finished(struct svm_test *test) case 3: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1848,7 +1848,7 @@ static bool virq_inject_finished(struct svm_test *test) case 4: // INTERCEPT_VINTR should be ignored because V_INTR_PRIO < V_TPR if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -1886,7 +1886,7 @@ static void virq_inject_within_shadow_prepare_gif_clear(struct svm_test *test) static bool virq_inject_within_shadow_finished(struct svm_test *test) { if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) - report_fail("VMEXIT not due to vmmcall. Exit reason 0x%x", + report_fail("VMEXIT not due to vmmcall. Exit reason 0x%lx", vmcb->control.exit_code); if (!virq_fired) report_fail("V_IRQ did not fire"); @@ -2063,7 +2063,7 @@ static bool init_intercept_finished(struct svm_test *test) vmcb->save.rip += 3; if (vmcb->control.exit_code != SVM_EXIT_INIT) { - report_fail("VMEXIT not due to init intercept. Exit reason 0x%x", + report_fail("VMEXIT not due to init intercept. Exit reason 0x%lx", vmcb->control.exit_code); return true; @@ -2165,7 +2165,7 @@ static bool host_rflags_finished(struct svm_test *test) switch (get_test_stage(test)) { case 0: if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report_fail("Unexpected VMEXIT. Exit reason 0x%x", + report_fail("Unexpected VMEXIT. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -2180,7 +2180,7 @@ static bool host_rflags_finished(struct svm_test *test) if (vmcb->control.exit_code != SVM_EXIT_VMMCALL || host_rflags_guest_main_flag != 1) { report_fail("Unexpected VMEXIT or #DB handler" - " invoked before guest main. Exit reason 0x%x", + " invoked before guest main. Exit reason 0x%lx", vmcb->control.exit_code); return true; } @@ -2196,7 +2196,7 @@ static bool host_rflags_finished(struct svm_test *test) if (vmcb->control.exit_code != SVM_EXIT_VMMCALL || rip_detected != (u64)&vmrun_rip + 3) { report_fail("Unexpected VMEXIT or RIP mismatch." - " Exit reason 0x%x, RIP actual: %lx, RIP expected: " + " Exit reason 0x%lx, RIP actual: %lx, RIP expected: " "%lx", vmcb->control.exit_code, (u64)&vmrun_rip + 3, rip_detected); return true; @@ -2214,7 +2214,7 @@ static bool host_rflags_finished(struct svm_test *test) read_rflags() & X86_EFLAGS_RF) { report_fail("Unexpected VMEXIT or RIP mismatch or " "EFLAGS.RF not cleared." - " Exit reason 0x%x, RIP actual: %lx, RIP expected: " + " Exit reason 0x%lx, RIP actual: %lx, RIP expected: " "%lx", vmcb->control.exit_code, (u64)&vmrun_rip, rip_detected); return true; @@ -2301,7 +2301,7 @@ static void basic_guest_main(struct svm_test *test) exit_code, test_name) \ { \ u64 tmp, mask; \ - u32 r; \ + u64 r; \ int i; \ \ for (i = start; i <= end; i = i + inc) { \ @@ -2320,8 +2320,8 @@ static void basic_guest_main(struct svm_test *test) vmcb->save.cr4 = tmp; \ } \ r = svm_vmrun(); \ - report(r == exit_code, "Test CR%d %s%d:%d: %lx, wanted exit 0x%x, got 0x%x", \ - cr, test_name, end, start, tmp, exit_code, r); \ + report(r == exit_code, "Test CR%d %s%d:%d: %lx, wanted exit 0x%lx, got 0x%lx", \ + cr, test_name, end, start, tmp, (u64)exit_code, r); \ } \ } @@ -3316,7 +3316,7 @@ static void dummy_nmi_handler(struct ex_regs *regs) } -static void svm_intr_intercept_mix_run_guest(volatile int *counter, int expected_vmexit) +static void svm_intr_intercept_mix_run_guest(volatile int *counter, u64 expected_vmexit) { if (counter) *counter = 0; @@ -3335,7 +3335,7 @@ static void svm_intr_intercept_mix_run_guest(volatile int *counter, int expected report(*counter == 1, "Interrupt is expected"); report(vmcb->control.exit_code == expected_vmexit, - "Wanted VM-Exit reason 0x%x, got 0x%x", + "Wanted VM-Exit reason 0x%lx, got 0x%lx", expected_vmexit, vmcb->control.exit_code); report(vmcb->save.rflags & X86_EFLAGS_IF, "Guest should have EFLAGS.IF set now"); cli(); base-commit: 31d91f5c9b7546471b729491664b05c933d64a7a -- 2.52.0.351.gbe84eed79e-goog