mirror of
https://github.com/torvalds/linux.git
synced 2026-10-25 16:45:02 +01:00
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>
This commit is contained in:
parent
2f00ba93cc
commit
b630929bcc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user