Implement prepare/restore logic for the nSVM/nNPT APIC MMIO passthrough tests to ensure the CPU is actually running with xAPIC enabled. As is, the test is effectively validating KVM's KVM_X86_QUIRK_LAPIC_MMIO_HOLE, or if x2AVIC is support, CPU behavior. The latter (x2AVIC enabled) is especially problematic, as AMD CPUs appear to return '0' for xAPIC reads when x2AVIC is enabled. And because KVM disables/inhibits AVIC and x2AVIC when running L2, the divergence in behavior (KVM provies 0xffs, CPU provides 0s) results in test failures. Opportunistically make the hardcoded APIC base pointer (eww) an unsigned long literal. Note, svm_test.finished() is invoked *before* svm_test.succeeded(), i.e. restoring x2APIC (if it was enabled) must be done in the "check" code. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- x86/svm_npt.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/x86/svm_npt.c b/x86/svm_npt.c index b791f1ac..bd5e8f35 100644 --- a/x86/svm_npt.c +++ b/x86/svm_npt.c @@ -1,3 +1,4 @@ +#include "apic.h" #include "svm.h" #include "vm.h" #include "alloc_page.h" @@ -134,8 +135,27 @@ static bool npt_rw_pfwalk_check(struct svm_test *test) && (vmcb->control.exit_info_2 == read_cr3()); } +static bool was_x2apic; + +static void npt_apic_prepare(void) +{ + was_x2apic = is_x2apic_enabled(); + + if (was_x2apic) + reset_apic(); +} + +static void npt_apic_restore(void) +{ + if (was_x2apic) + enable_x2apic(); + + was_x2apic = false; +} + static void npt_l1mmio_prepare(struct svm_test *test) { + npt_apic_prepare(); } u32 nested_apic_version1; @@ -154,6 +174,9 @@ static bool npt_l1mmio_check(struct svm_test *test) volatile u32 *data = (volatile void *)(0xfee00030); u32 lvr = *data; + /* Restore APIC state *after* reading LVR. */ + npt_apic_restore(); + return nested_apic_version1 == lvr && nested_apic_version2 == lvr; } @@ -162,6 +185,8 @@ static void npt_rw_l1mmio_prepare(struct svm_test *test) u64 *pte; + npt_apic_prepare(); + pte = npt_get_pte(0xfee00080); *pte &= ~(1ULL << 1); @@ -180,6 +205,8 @@ static bool npt_rw_l1mmio_check(struct svm_test *test) *pte |= (1ULL << 1); + npt_apic_restore(); + return (vmcb->control.exit_code == SVM_EXIT_NPF) && (vmcb->control.exit_info_1 == 0x100000007ULL); } -- 2.48.1.711.g2feabab25a-goog