aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/testing/selftests/kvm/x86/nested_x2apic_test.c88
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);
}