xref: /linux/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c (revision 4d256d00e44e02fae84851729d70df2bc2ebe6e9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2025, Google LLC.
4  *
5  * This test verifies that L1 fails to enter L2 with an invalid CR3, and
6  * succeeds otherwise.
7  */
8 #include "kvm_util.h"
9 #include "vmx.h"
10 #include "kselftest.h"
11 
12 
13 #define L2_GUEST_STACK_SIZE 64
14 
15 static void l2_guest_code(void)
16 {
17 	vmcall();
18 }
19 
20 static void l1_vmx_code(struct vmx_pages *vmx_pages)
21 {
22 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
23 	uintptr_t save_cr3;
24 
25 	GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
26 	GUEST_ASSERT(load_vmcs(vmx_pages));
27 
28 	prepare_vmcs(vmx_pages, l2_guest_code,
29 		     &l2_guest_stack[L2_GUEST_STACK_SIZE]);
30 
31 	/* Try to run L2 with invalid CR3 and make sure it fails */
32 	save_cr3 = vmreadz(GUEST_CR3);
33 	vmwrite(GUEST_CR3, -1ull);
34 	GUEST_ASSERT(!vmlaunch());
35 	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) ==
36 		     (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE));
37 
38 	/* Now restore CR3 and make sure L2 runs successfully */
39 	vmwrite(GUEST_CR3, save_cr3);
40 	GUEST_ASSERT(!vmlaunch());
41 	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
42 
43 	GUEST_DONE();
44 }
45 
46 int main(int argc, char *argv[])
47 {
48 	struct kvm_vcpu *vcpu;
49 	struct kvm_vm *vm;
50 	vm_vaddr_t guest_gva = 0;
51 
52 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
53 
54 	vm = vm_create_with_one_vcpu(&vcpu, l1_vmx_code);
55 	vcpu_alloc_vmx(vm, &guest_gva);
56 	vcpu_args_set(vcpu, 1, guest_gva);
57 
58 	for (;;) {
59 		struct ucall uc;
60 
61 		vcpu_run(vcpu);
62 		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
63 
64 		switch (get_ucall(vcpu, &uc)) {
65 		case UCALL_ABORT:
66 			REPORT_GUEST_ASSERT(uc);
67 		case UCALL_SYNC:
68 			break;
69 		case UCALL_DONE:
70 			goto done;
71 		default:
72 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
73 		}
74 	}
75 
76 done:
77 	kvm_vm_free(vm);
78 	return 0;
79 }
80