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 #include <string.h> 9 #include <sys/ioctl.h> 10 11 #include "kselftest.h" 12 13 #define ARBITRARY_IO_PORT 0x2000 14 15 /* The virtual machine object. */ 16 static struct kvm_vm *vm; 17 18 static void l2_guest_code(void) 19 { 20 asm volatile("inb %%dx, %%al" 21 : : [port] "d" (ARBITRARY_IO_PORT) : "rax"); 22 } 23 24 void l1_guest_code_vmx(struct vmx_pages *vmx) 25 { 26 27 GUEST_ASSERT(vmx->vmcs_gpa); 28 GUEST_ASSERT(prepare_for_vmx_operation(vmx)); 29 GUEST_ASSERT(load_vmcs(vmx)); 30 31 prepare_vmcs(vmx, l2_guest_code); 32 33 GUEST_ASSERT(!vmlaunch()); 34 /* L2 should triple fault after a triple fault event injected. */ 35 GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); 36 GUEST_DONE(); 37 } 38 39 void l1_guest_code_svm(struct svm_test_data *svm) 40 { 41 struct vmcb *vmcb = svm->vmcb; 42 43 generic_svm_setup(svm, l2_guest_code); 44 45 /* don't intercept shutdown to test the case of SVM allowing to do so */ 46 vmcb->control.intercept &= ~(BIT(INTERCEPT_SHUTDOWN)); 47 48 run_guest(vmcb, svm->vmcb_gpa); 49 50 /* should not reach here, L1 should crash */ 51 GUEST_ASSERT(0); 52 } 53 54 int main(void) 55 { 56 struct kvm_vcpu *vcpu; 57 struct kvm_run *run; 58 struct kvm_vcpu_events events; 59 struct ucall uc; 60 61 bool has_vmx = kvm_cpu_has(X86_FEATURE_VMX); 62 bool has_svm = kvm_cpu_has(X86_FEATURE_SVM); 63 64 TEST_REQUIRE(has_vmx || has_svm); 65 66 TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)); 67 68 69 if (has_vmx) { 70 gva_t vmx_pages_gva; 71 72 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code_vmx); 73 vcpu_alloc_vmx(vm, &vmx_pages_gva); 74 vcpu_args_set(vcpu, 1, vmx_pages_gva); 75 } else { 76 gva_t svm_gva; 77 78 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code_svm); 79 vcpu_alloc_svm(vm, &svm_gva); 80 vcpu_args_set(vcpu, 1, svm_gva); 81 } 82 83 vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1); 84 run = vcpu->run; 85 vcpu_run(vcpu); 86 87 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 88 TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT, 89 "Expected IN from port %d from L2, got port %d", 90 ARBITRARY_IO_PORT, run->io.port); 91 vcpu_events_get(vcpu, &events); 92 events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; 93 events.triple_fault.pending = true; 94 vcpu_events_set(vcpu, &events); 95 run->immediate_exit = true; 96 vcpu_run_complete_io(vcpu); 97 98 vcpu_events_get(vcpu, &events); 99 TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT, 100 "Triple fault event invalid"); 101 TEST_ASSERT(events.triple_fault.pending, 102 "No triple fault pending"); 103 vcpu_run(vcpu); 104 105 106 if (has_svm) { 107 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_SHUTDOWN); 108 } else { 109 switch (get_ucall(vcpu, &uc)) { 110 case UCALL_DONE: 111 break; 112 case UCALL_ABORT: 113 REPORT_GUEST_ASSERT(uc); 114 default: 115 TEST_FAIL("Unexpected ucall: %lu", uc.cmd); 116 } 117 } 118 return 0; 119 } 120