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, struct hyperv_test_pages *hv_pages) 55 { 56 u64 control; 57 58 if (hv_pages) { 59 wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID); 60 enable_vp_assist(hv_pages->vp_assist_gpa, hv_pages->vp_assist); 61 evmcs_enable(); 62 } 63 64 GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); 65 66 if (hv_pages) { 67 GUEST_ASSERT(load_evmcs(hv_pages)); 68 current_evmcs->hv_enlightenments_control.msr_bitmap = 1; 69 } else { 70 GUEST_ASSERT(load_vmcs(vmx)); 71 } 72 73 prepare_vmcs(vmx, NULL); 74 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, (unsigned long)l2_guest_code), 0); 75 76 control = vmreadz(PIN_BASED_VM_EXEC_CONTROL); 77 control |= PIN_BASED_EXT_INTR_MASK; 78 vmwrite(PIN_BASED_VM_EXEC_CONTROL, control); 79 80 control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); 81 control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW; 82 GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); 83 84 control = vmreadz(SECONDARY_VM_EXEC_CONTROL); 85 control |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | 86 SECONDARY_EXEC_APIC_REGISTER_VIRT | 87 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; 88 control &= (rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32); 89 GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); 90 91 GUEST_ASSERT(!vmlaunch()); 92 GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); 93 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, 94 vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); 95 } 96 97 static void l1_vmx_code_part2(void) 98 { 99 u64 control; 100 101 control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); 102 control &= ~CPU_BASED_TPR_SHADOW; 103 GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); 104 105 control = vmreadz(SECONDARY_VM_EXEC_CONTROL); 106 control &= ~(SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | 107 SECONDARY_EXEC_APIC_REGISTER_VIRT | 108 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); 109 GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); 110 111 GUEST_ASSERT(!vmresume()); 112 GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); 113 GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, 114 vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); 115 } 116 117 static void l1_test_x2apic_intercepts(void) 118 { 119 GUEST_ASSERT_EQ(nr_irqs, 0); 120 121 sti_nop(); 122 123 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xf0); 124 125 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_VECTOR); 126 GUEST_ASSERT_EQ(nr_irqs, 0); 127 128 x2apic_write_reg(APIC_TASKPRI, 0xff); 129 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0xff); 130 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_WAKEUP_VECTOR); 131 GUEST_ASSERT_EQ(nr_irqs, 0); 132 133 x2apic_write_reg(APIC_TASKPRI, 0); 134 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0); 135 136 x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | POSTED_INTR_NESTED_VECTOR); 137 GUEST_ASSERT_EQ(nr_irqs, 3); 138 139 nr_irqs = 0; 140 } 141 142 static void l1_guest_code(void *test_data, void *hv_pages) 143 { 144 x2apic_enable(); 145 146 if (this_cpu_has(X86_FEATURE_SVM)) 147 l1_svm_code(test_data); 148 else 149 l1_vmx_code(test_data, hv_pages); 150 151 GUEST_ASSERT_EQ(x2apic_read_reg(APIC_TASKPRI), 0); 152 x2apic_write_reg(APIC_TASKPRI, 0xf0); 153 154 l1_test_x2apic_intercepts(); 155 156 if (this_cpu_has(X86_FEATURE_VMX)) { 157 l1_vmx_code_part2(); 158 l1_test_x2apic_intercepts(); 159 } 160 161 GUEST_DONE(); 162 } 163 164 static void test_x2apic_intercepts(bool with_inhibit_apicv, bool use_evmcs) 165 { 166 gva_t nested_test_data_gva, hv_pages_gva = 0; 167 struct kvm_vcpu *vcpu; 168 struct kvm_vm *vm; 169 struct ucall uc; 170 171 inhibit_apicv = with_inhibit_apicv; 172 173 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); 174 vm_install_exception_handler(vm, POSTED_INTR_VECTOR, guest_irq_handler); 175 vm_install_exception_handler(vm, POSTED_INTR_WAKEUP_VECTOR, guest_irq_handler); 176 vm_install_exception_handler(vm, POSTED_INTR_NESTED_VECTOR, guest_irq_handler); 177 178 sync_global_to_guest(vm, inhibit_apicv); 179 180 if (kvm_cpu_has(X86_FEATURE_SVM)) 181 vcpu_alloc_svm(vm, &nested_test_data_gva); 182 else 183 vcpu_alloc_vmx(vm, &nested_test_data_gva); 184 185 if (use_evmcs) { 186 vcpu_set_hv_cpuid(vcpu); 187 vcpu_enable_evmcs(vcpu); 188 189 vcpu_alloc_hyperv_test_pages(vm, &hv_pages_gva); 190 } 191 192 vcpu_args_set(vcpu, 2, nested_test_data_gva, hv_pages_gva); 193 194 vcpu_run(vcpu); 195 196 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 197 198 switch (get_ucall(vcpu, &uc)) { 199 case UCALL_DONE: 200 break; 201 case UCALL_ABORT: 202 REPORT_GUEST_ASSERT(uc); 203 break; 204 default: 205 TEST_FAIL("Expected DONE, got unexpected ucall %lu", uc.cmd); 206 } 207 208 kvm_vm_free(vm); 209 } 210 211 int main(int argc, char *argv[]) 212 { 213 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM) || kvm_cpu_has(X86_FEATURE_VMX)); 214 215 test_x2apic_intercepts(true, false); 216 test_x2apic_intercepts(false, false); 217 218 if (kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { 219 test_x2apic_intercepts(true, true); 220 test_x2apic_intercepts(false, true); 221 } 222 } 223