0001
0002 #include "test_util.h"
0003 #include "kvm_util.h"
0004 #include "processor.h"
0005 #include "vmx.h"
0006
0007 #include <string.h>
0008 #include <sys/ioctl.h>
0009
0010 #include "kselftest.h"
0011
0012 #define ARBITRARY_IO_PORT 0x2000
0013
0014
0015 static struct kvm_vm *vm;
0016
0017 static void l2_guest_code(void)
0018 {
0019 asm volatile("inb %%dx, %%al"
0020 : : [port] "d" (ARBITRARY_IO_PORT) : "rax");
0021 }
0022
0023 void l1_guest_code(struct vmx_pages *vmx)
0024 {
0025 #define L2_GUEST_STACK_SIZE 64
0026 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
0027
0028 GUEST_ASSERT(vmx->vmcs_gpa);
0029 GUEST_ASSERT(prepare_for_vmx_operation(vmx));
0030 GUEST_ASSERT(load_vmcs(vmx));
0031
0032 prepare_vmcs(vmx, l2_guest_code,
0033 &l2_guest_stack[L2_GUEST_STACK_SIZE]);
0034
0035 GUEST_ASSERT(!vmlaunch());
0036
0037 GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT);
0038 GUEST_DONE();
0039 }
0040
0041 int main(void)
0042 {
0043 struct kvm_vcpu *vcpu;
0044 struct kvm_run *run;
0045 struct kvm_vcpu_events events;
0046 vm_vaddr_t vmx_pages_gva;
0047 struct ucall uc;
0048
0049 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
0050
0051 TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT));
0052
0053 vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
0054 vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1);
0055
0056 run = vcpu->run;
0057 vcpu_alloc_vmx(vm, &vmx_pages_gva);
0058 vcpu_args_set(vcpu, 1, vmx_pages_gva);
0059 vcpu_run(vcpu);
0060
0061 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0062 "Expected KVM_EXIT_IO, got: %u (%s)\n",
0063 run->exit_reason, exit_reason_str(run->exit_reason));
0064 TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT,
0065 "Expected IN from port %d from L2, got port %d",
0066 ARBITRARY_IO_PORT, run->io.port);
0067 vcpu_events_get(vcpu, &events);
0068 events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT;
0069 events.triple_fault.pending = true;
0070 vcpu_events_set(vcpu, &events);
0071 run->immediate_exit = true;
0072 vcpu_run_complete_io(vcpu);
0073
0074 vcpu_events_get(vcpu, &events);
0075 TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT,
0076 "Triple fault event invalid");
0077 TEST_ASSERT(events.triple_fault.pending,
0078 "No triple fault pending");
0079 vcpu_run(vcpu);
0080
0081 switch (get_ucall(vcpu, &uc)) {
0082 case UCALL_DONE:
0083 break;
0084 case UCALL_ABORT:
0085 REPORT_GUEST_ASSERT(uc);
0086 default:
0087 TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
0088 }
0089
0090 }