130267b43SChenyi Qiang // SPDX-License-Identifier: GPL-2.0-only
230267b43SChenyi Qiang #include "test_util.h"
330267b43SChenyi Qiang #include "kvm_util.h"
430267b43SChenyi Qiang #include "processor.h"
530267b43SChenyi Qiang #include "vmx.h"
630267b43SChenyi Qiang 
730267b43SChenyi Qiang #include <string.h>
830267b43SChenyi Qiang #include <sys/ioctl.h>
930267b43SChenyi Qiang 
1030267b43SChenyi Qiang #include "kselftest.h"
1130267b43SChenyi Qiang 
1230267b43SChenyi Qiang #define ARBITRARY_IO_PORT	0x2000
1330267b43SChenyi Qiang 
1430267b43SChenyi Qiang /* The virtual machine object. */
1530267b43SChenyi Qiang static struct kvm_vm *vm;
1630267b43SChenyi Qiang 
1730267b43SChenyi Qiang static void l2_guest_code(void)
1830267b43SChenyi Qiang {
1930267b43SChenyi Qiang 	asm volatile("inb %%dx, %%al"
2030267b43SChenyi Qiang 		     : : [port] "d" (ARBITRARY_IO_PORT) : "rax");
2130267b43SChenyi Qiang }
2230267b43SChenyi Qiang 
2330267b43SChenyi Qiang void l1_guest_code(struct vmx_pages *vmx)
2430267b43SChenyi Qiang {
2530267b43SChenyi Qiang #define L2_GUEST_STACK_SIZE 64
2630267b43SChenyi Qiang 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
2730267b43SChenyi Qiang 
2830267b43SChenyi Qiang 	GUEST_ASSERT(vmx->vmcs_gpa);
2930267b43SChenyi Qiang 	GUEST_ASSERT(prepare_for_vmx_operation(vmx));
3030267b43SChenyi Qiang 	GUEST_ASSERT(load_vmcs(vmx));
3130267b43SChenyi Qiang 
3230267b43SChenyi Qiang 	prepare_vmcs(vmx, l2_guest_code,
3330267b43SChenyi Qiang 		     &l2_guest_stack[L2_GUEST_STACK_SIZE]);
3430267b43SChenyi Qiang 
3530267b43SChenyi Qiang 	GUEST_ASSERT(!vmlaunch());
3630267b43SChenyi Qiang 	/* L2 should triple fault after a triple fault event injected. */
3730267b43SChenyi Qiang 	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT);
3830267b43SChenyi Qiang 	GUEST_DONE();
3930267b43SChenyi Qiang }
4030267b43SChenyi Qiang 
4130267b43SChenyi Qiang int main(void)
4230267b43SChenyi Qiang {
43f3443bedSSean Christopherson 	struct kvm_vcpu *vcpu;
4430267b43SChenyi Qiang 	struct kvm_run *run;
4530267b43SChenyi Qiang 	struct kvm_vcpu_events events;
4630267b43SChenyi Qiang 	vm_vaddr_t vmx_pages_gva;
4730267b43SChenyi Qiang 	struct ucall uc;
4830267b43SChenyi Qiang 
497ed397d1SSean Christopherson 	nested_vmx_check_supported();
5030267b43SChenyi Qiang 
517ed397d1SSean Christopherson 	TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT));
5230267b43SChenyi Qiang 
53f3443bedSSean Christopherson 	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
54a12c86c4SSean Christopherson 	vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1);
5530267b43SChenyi Qiang 
56f3443bedSSean Christopherson 	run = vcpu->run;
5730267b43SChenyi Qiang 	vcpu_alloc_vmx(vm, &vmx_pages_gva);
58768e9a61SSean Christopherson 	vcpu_args_set(vcpu, 1, vmx_pages_gva);
59768e9a61SSean Christopherson 	vcpu_run(vcpu);
6030267b43SChenyi Qiang 
6130267b43SChenyi Qiang 	TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
6230267b43SChenyi Qiang 		    "Expected KVM_EXIT_IO, got: %u (%s)\n",
6330267b43SChenyi Qiang 		    run->exit_reason, exit_reason_str(run->exit_reason));
6430267b43SChenyi Qiang 	TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT,
6530267b43SChenyi Qiang 		    "Expected IN from port %d from L2, got port %d",
6630267b43SChenyi Qiang 		    ARBITRARY_IO_PORT, run->io.port);
67768e9a61SSean Christopherson 	vcpu_events_get(vcpu, &events);
6830267b43SChenyi Qiang 	events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT;
6930267b43SChenyi Qiang 	events.triple_fault.pending = true;
70768e9a61SSean Christopherson 	vcpu_events_set(vcpu, &events);
7130267b43SChenyi Qiang 	run->immediate_exit = true;
72768e9a61SSean Christopherson 	vcpu_run_complete_io(vcpu);
7330267b43SChenyi Qiang 
74768e9a61SSean Christopherson 	vcpu_events_get(vcpu, &events);
7530267b43SChenyi Qiang 	TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT,
7630267b43SChenyi Qiang 		    "Triple fault event invalid");
7730267b43SChenyi Qiang 	TEST_ASSERT(events.triple_fault.pending,
7830267b43SChenyi Qiang 		    "No triple fault pending");
79768e9a61SSean Christopherson 	vcpu_run(vcpu);
8030267b43SChenyi Qiang 
81768e9a61SSean Christopherson 	switch (get_ucall(vcpu, &uc)) {
8230267b43SChenyi Qiang 	case UCALL_DONE:
8330267b43SChenyi Qiang 		break;
8430267b43SChenyi Qiang 	case UCALL_ABORT:
85*594a1c27SColton Lewis 		REPORT_GUEST_ASSERT(uc);
8630267b43SChenyi Qiang 	default:
8730267b43SChenyi Qiang 		TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
8830267b43SChenyi Qiang 	}
8930267b43SChenyi Qiang 
9030267b43SChenyi Qiang }
91