diff options
| author | Sean Christopherson <seanjc@google.com> | 2026-09-26 02:04:03 -0400 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2026-09-28 17:11:47 -0400 |
| commit | b630929bcc4c867c9abc8cd5a0ebee3bb5ce5dcd (patch) | |
| tree | 7d681e36418ec5b92592710e705165bcddd1448e | |
| parent | 2f00ba93cc285092cd3b7ffebbc9abb6004f55e7 (diff) | |
KVM: selftests: Extend nested x2APIC test to validate disabling x2APIC virt
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20260813223610.2043560-6-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
| -rw-r--r-- | tools/testing/selftests/kvm/x86/nested_x2apic_test.c | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/tools/testing/selftests/kvm/x86/nested_x2apic_test.c b/tools/testing/selftests/kvm/x86/nested_x2apic_test.c index 3b59ba3e3342..964937aefe39 100644 --- a/tools/testing/selftests/kvm/x86/nested_x2apic_test.c +++ b/tools/testing/selftests/kvm/x86/nested_x2apic_test.c @@ -29,10 +29,12 @@ static void l2_guest_code(void) if (inhibit_apicv) wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & GENMASK_ULL(11, 0)); - x2apic_write_reg(APIC_TASKPRI, 0xf0); - GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xf0); + for (;;) { + x2apic_write_reg(APIC_TASKPRI, 0xf0); + GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xf0); - asm volatile("cpuid" ::: "eax", "ebx", "ecx", "edx"); + asm volatile("cpuid" ::: "eax", "ebx", "ecx", "edx"); + } } static void l1_svm_code(struct svm_test_data *svm) @@ -46,6 +48,7 @@ static void l1_svm_code(struct svm_test_data *svm) GUEST_ASSERT_EQ(ctrl->exit_code, SVM_EXIT_CPUID); stgi(); + x2apic_write_reg(APIC_TASKPRI, 0); } static void l1_vmx_code(struct vmx_pages *vmx) @@ -58,22 +61,50 @@ static void l1_vmx_code(struct vmx_pages *vmx) prepare_vmcs(vmx, NULL); GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, (unsigned long)l2_guest_code), 0); + control = vmreadz(PIN_BASED_VM_EXEC_CONTROL); + control |= PIN_BASED_EXT_INTR_MASK; + vmwrite(PIN_BASED_VM_EXEC_CONTROL, control); + control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); - control |= CPU_BASED_USE_MSR_BITMAPS; + control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW; GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); + control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; + control &= (rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32); + GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); + GUEST_ASSERT(!vmlaunch()); GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); + GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, + vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); } -static void l1_guest_code(void *test_data) +static void l1_vmx_code_part2(void) { - x2apic_enable(); + u64 control; - if (this_cpu_has(X86_FEATURE_SVM)) - l1_svm_code(test_data); - else - l1_vmx_code(test_data); + control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control &= ~CPU_BASED_TPR_SHADOW; + GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); + + control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control &= ~(SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); + + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); + GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, + vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); +} + +static void l1_test_x2apic_intercepts(void) +{ + GUEST_ASSERT_EQ(nr_irqs, 0); sti_nop(); @@ -93,16 +124,40 @@ static void l1_guest_code(void *test_data) x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_NESTED_VECTOR); GUEST_ASSERT_EQ(nr_irqs, 3); + nr_irqs = 0; +} + +static void l1_guest_code(void *test_data) +{ + x2apic_enable(); + + if (this_cpu_has(X86_FEATURE_SVM)) + l1_svm_code(test_data); + else + l1_vmx_code(test_data); + + GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0); + x2apic_write_reg(APIC_TASKPRI, 0xf0); + + l1_test_x2apic_intercepts(); + + if (this_cpu_has(X86_FEATURE_VMX)) { + l1_vmx_code_part2(); + l1_test_x2apic_intercepts(); + } + GUEST_DONE(); } -static void __test_x2apic_intercepts(void) +static void __test_x2apic_intercepts(bool with_inhibit_apicv) { gva_t nested_test_data_gva; struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct ucall uc; + inhibit_apicv = with_inhibit_apicv; + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_install_exception_handler(vm, POSTED_INTR_VECTOR, guest_irq_handler); vm_install_exception_handler(vm, POSTED_INTR_WAKEUP_VECTOR, guest_irq_handler); @@ -134,17 +189,10 @@ static void __test_x2apic_intercepts(void) kvm_vm_free(vm); } -#define test_x2apic_intercepts(inhibit_apic_setting) \ -do { \ - inhibit_apic_setting; \ - \ - __test_x2apic_intercepts(); \ -} while (0) - int main(int argc, char *argv[]) { TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM) || kvm_cpu_has(X86_FEATURE_VMX)); - test_x2apic_intercepts(inhibit_apicv = true); - test_x2apic_intercepts(inhibit_apicv = false); + test_x2apic_intercepts(true); + test_x2apic_intercepts(false); } |
