1 // SPDX-License-Identifier: GPL-2.0-only 2 #include "test_util.h" 3 #include "kvm_util.h" 4 #include "processor.h" 5 #include "vmx.h" 6 #include "svm_util.h" 7 8 /* 9 * Use the kernel's posted interrupt vectors to minimize the risk of crashing 10 * the host if KVM is buggy. Note, the vectors aren't set in stone, ideally 11 * these will be kept up-to-date if the kernel vectors change, but it's "fine" 12 * if they are stale. 13 */ 14 #define POSTED_INTR_VECTOR 0xf2 15 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 16 #define POSTED_INTR_NESTED_VECTOR 0xf0 17 18 static bool inhibit_apicv; 19 static volatile unsigned int nr_irqs; 20 21 static void guest_irq_handler(struct ex_regs *regs) 22 { 23 nr_irqs++; 24 x2apic_write_reg(APIC_EOI, 0); 25 } 26 27 static void l2_guest_code(void) 28 { 29 if (inhibit_apicv) 30 wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & GENMASK_ULL(11, 0)); 31 32 for (;;) { 33 x2apic_write_reg(APIC_TASKPRI, 0xf0); 34 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xf0); 35 36 asm volatile("cpuid" ::: "eax", "ebx", "ecx", "edx"); 37 } 38 } 39 40 static void l1_svm_code(struct svm_test_data *svm) 41 { 42 struct vmcb_control_area *ctrl = &svm->vmcb->control; 43 44 generic_svm_setup(svm, l2_guest_code); 45 ctrl->intercept |= BIT_ULL(INTERCEPT_CPUID) | BIT_ULL(INTERCEPT_MSR_PROT); 46 47 run_guest(svm->vmcb, svm->vmcb_gpa); 48 GUEST_ASSERT_EQ(ctrl->exit_code, SVM_EXIT_CPUID); 49 50 stgi(); 51 x2apic_write_reg(APIC_TASKPRI, 0); 52 } 53 54 static void l1_vmx_code(struct vmx_pages *vmx) 55 { 56 u64 control; 57 58 GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); 59 GUEST_ASSERT_EQ(load_vmcs(vmx), true); 60 61 prepare_vmcs(vmx, NULL); 62 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, (unsigned long)l2_guest_code), 0); 63 64 control = vmreadz(PIN_BASED_VM_EXEC_CONTROL); 65 control |= PIN_BASED_EXT_INTR_MASK; 66 vmwrite(PIN_BASED_VM_EXEC_CONTROL, control); 67 68 control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); 69 control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW; 70 GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); 71 72 control = vmreadz(SECONDARY_VM_EXEC_CONTROL); 73 control |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | 74 SECONDARY_EXEC_APIC_REGISTER_VIRT | 75 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; 76 control &= (rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32); 77 GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); 78 79 GUEST_ASSERT(!vmlaunch()); 80 GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); 81 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, 82 vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); 83 } 84 85 static void l1_vmx_code_part2(void) 86 { 87 u64 control; 88 89 control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); 90 control &= ~CPU_BASED_TPR_SHADOW; 91 GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); 92 93 control = vmreadz(SECONDARY_VM_EXEC_CONTROL); 94 control &= ~(SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | 95 SECONDARY_EXEC_APIC_REGISTER_VIRT | 96 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); 97 GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); 98 99 GUEST_ASSERT(!vmresume()); 100 GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); 101 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, 102 vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); 103 } 104 105 static void l1_test_x2apic_intercepts(void) 106 { 107 GUEST_ASSERT_EQ(nr_irqs, 0); 108 109 sti_nop(); 110 111 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xf0); 112 113 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_VECTOR); 114 GUEST_ASSERT_EQ(nr_irqs, 0); 115 116 x2apic_write_reg(APIC_TASKPRI, 0xff); 117 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xff); 118 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_WAKEUP_VECTOR); 119 GUEST_ASSERT_EQ(nr_irqs, 0); 120 121 x2apic_write_reg(APIC_TASKPRI, 0); 122 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0); 123 124 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_NESTED_VECTOR); 125 GUEST_ASSERT_EQ(nr_irqs, 3); 126 127 nr_irqs = 0; 128 } 129 130 static void l1_guest_code(void *test_data) 131 { 132 x2apic_enable(); 133 134 if (this_cpu_has(X86_FEATURE_SVM)) 135 l1_svm_code(test_data); 136 else 137 l1_vmx_code(test_data); 138 139 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0); 140 x2apic_write_reg(APIC_TASKPRI, 0xf0); 141 142 l1_test_x2apic_intercepts(); 143 144 if (this_cpu_has(X86_FEATURE_VMX)) { 145 l1_vmx_code_part2(); 146 l1_test_x2apic_intercepts(); 147 } 148 149 GUEST_DONE(); 150 } 151 152 static void __test_x2apic_intercepts(bool with_inhibit_apicv) 153 { 154 gva_t nested_test_data_gva; 155 struct kvm_vcpu *vcpu; 156 struct kvm_vm *vm; 157 struct ucall uc; 158 159 inhibit_apicv = with_inhibit_apicv; 160 161 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); 162 vm_install_exception_handler(vm, POSTED_INTR_VECTOR, guest_irq_handler); 163 vm_install_exception_handler(vm, POSTED_INTR_WAKEUP_VECTOR, guest_irq_handler); 164 vm_install_exception_handler(vm, POSTED_INTR_NESTED_VECTOR, guest_irq_handler); 165 166 sync_global_to_guest(vm, inhibit_apicv); 167 168 if (kvm_cpu_has(X86_FEATURE_SVM)) 169 vcpu_alloc_svm(vm, &nested_test_data_gva); 170 else 171 vcpu_alloc_vmx(vm, &nested_test_data_gva); 172 173 vcpu_args_set(vcpu, 1, nested_test_data_gva); 174 175 vcpu_run(vcpu); 176 177 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 178 179 switch (get_ucall(vcpu, &uc)) { 180 case UCALL_DONE: 181 break; 182 case UCALL_ABORT: 183 REPORT_GUEST_ASSERT(uc); 184 break; 185 default: 186 TEST_FAIL("Expected DONE, got unexpected ucall %lu", uc.cmd); 187 } 188 189 kvm_vm_free(vm); 190 } 191 192 int main(int argc, char *argv[]) 193 { 194 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM) || kvm_cpu_has(X86_FEATURE_VMX)); 195 196 test_x2apic_intercepts(true); 197 test_x2apic_intercepts(false); 198 } 199