xref: /linux/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
1*0de1020fSKevin Cheng // SPDX-License-Identifier: GPL-2.0-only
2*0de1020fSKevin Cheng /*
3*0de1020fSKevin Cheng  * Copyright (C) 2025, Google, Inc.
4*0de1020fSKevin Cheng  */
5*0de1020fSKevin Cheng 
6*0de1020fSKevin Cheng #include "test_util.h"
7*0de1020fSKevin Cheng #include "kvm_util.h"
8*0de1020fSKevin Cheng #include "processor.h"
9*0de1020fSKevin Cheng #include "svm_util.h"
10*0de1020fSKevin Cheng #include "vmx.h"
11*0de1020fSKevin Cheng 
12*0de1020fSKevin Cheng #define L2_GUEST_STACK_SIZE 64
13*0de1020fSKevin Cheng 
14*0de1020fSKevin Cheng enum test_type {
15*0de1020fSKevin Cheng 	TEST_FINAL_PAGE_UNMAPPED,	    /* Final data page not present */
16*0de1020fSKevin Cheng 	TEST_PT_PAGE_UNMAPPED,		    /* Page table page not present */
17*0de1020fSKevin Cheng 	TEST_FINAL_PAGE_WRITE_PROTECTED,    /* Final data page read-only */
18*0de1020fSKevin Cheng 	TEST_PT_PAGE_WRITE_PROTECTED,	    /* Page table page read-only */
19*0de1020fSKevin Cheng };
20*0de1020fSKevin Cheng 
21*0de1020fSKevin Cheng static gva_t l2_test_page;
22*0de1020fSKevin Cheng static void (*l2_entry)(void);
23*0de1020fSKevin Cheng 
24*0de1020fSKevin Cheng #define TEST_IO_PORT 0x80
25*0de1020fSKevin Cheng #define TEST1_VADDR 0x8000000ULL
26*0de1020fSKevin Cheng #define TEST2_VADDR 0x10000000ULL
27*0de1020fSKevin Cheng #define TEST3_VADDR 0x18000000ULL
28*0de1020fSKevin Cheng #define TEST4_VADDR 0x20000000ULL
29*0de1020fSKevin Cheng 
30*0de1020fSKevin Cheng /*
31*0de1020fSKevin Cheng  * L2 executes OUTS reading from l2_test_page, triggering a nested page
32*0de1020fSKevin Cheng  * fault on the read access.
33*0de1020fSKevin Cheng  */
34*0de1020fSKevin Cheng static void l2_guest_code_outs(void)
35*0de1020fSKevin Cheng {
36*0de1020fSKevin Cheng 	asm volatile("outsb" ::"S"(l2_test_page), "d"(TEST_IO_PORT) : "memory");
37*0de1020fSKevin Cheng 	GUEST_FAIL("L2 should not reach here");
38*0de1020fSKevin Cheng }
39*0de1020fSKevin Cheng 
40*0de1020fSKevin Cheng /*
41*0de1020fSKevin Cheng  * L2 executes INS writing to l2_test_page, triggering a nested page
42*0de1020fSKevin Cheng  * fault on the write access.
43*0de1020fSKevin Cheng  */
44*0de1020fSKevin Cheng static void l2_guest_code_ins(void)
45*0de1020fSKevin Cheng {
46*0de1020fSKevin Cheng 	asm volatile("insb" ::"D"(l2_test_page), "d"(TEST_IO_PORT) : "memory");
47*0de1020fSKevin Cheng 	GUEST_FAIL("L2 should not reach here");
48*0de1020fSKevin Cheng }
49*0de1020fSKevin Cheng 
50*0de1020fSKevin Cheng #define GUEST_ASSERT_EXIT_QUAL(ac_eq, ex_eq)		\
51*0de1020fSKevin Cheng 	__GUEST_ASSERT((ac_eq) == (ex_eq),		\
52*0de1020fSKevin Cheng 		       "Wanted EXIT_QUAL '0x%lx', got '0x%lx'", ex_eq, ac_eq)
53*0de1020fSKevin Cheng 
54*0de1020fSKevin Cheng static void l1_vmx_code(struct vmx_pages *vmx, u64 expected_fault_gpa,
55*0de1020fSKevin Cheng 			u64 test_type)
56*0de1020fSKevin Cheng {
57*0de1020fSKevin Cheng 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
58*0de1020fSKevin Cheng 	u64 exit_qual;
59*0de1020fSKevin Cheng 
60*0de1020fSKevin Cheng 	GUEST_ASSERT(vmx->vmcs_gpa);
61*0de1020fSKevin Cheng 	GUEST_ASSERT(prepare_for_vmx_operation(vmx));
62*0de1020fSKevin Cheng 	GUEST_ASSERT(load_vmcs(vmx));
63*0de1020fSKevin Cheng 
64*0de1020fSKevin Cheng 	prepare_vmcs(vmx, l2_entry, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
65*0de1020fSKevin Cheng 
66*0de1020fSKevin Cheng 	GUEST_ASSERT(!vmlaunch());
67*0de1020fSKevin Cheng 
68*0de1020fSKevin Cheng 	/* Verify we got an EPT violation exit */
69*0de1020fSKevin Cheng 	__GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_EPT_VIOLATION,
70*0de1020fSKevin Cheng 		       "Expected EPT violation (0x%x), got 0x%lx",
71*0de1020fSKevin Cheng 		       EXIT_REASON_EPT_VIOLATION,
72*0de1020fSKevin Cheng 		       vmreadz(VM_EXIT_REASON));
73*0de1020fSKevin Cheng 
74*0de1020fSKevin Cheng 	__GUEST_ASSERT(vmreadz(GUEST_PHYSICAL_ADDRESS) == expected_fault_gpa,
75*0de1020fSKevin Cheng 		       "Expected guest_physical_address = 0x%lx, got 0x%lx",
76*0de1020fSKevin Cheng 		       expected_fault_gpa,
77*0de1020fSKevin Cheng 		       vmreadz(GUEST_PHYSICAL_ADDRESS));
78*0de1020fSKevin Cheng 
79*0de1020fSKevin Cheng 	exit_qual = vmreadz(EXIT_QUALIFICATION);
80*0de1020fSKevin Cheng 
81*0de1020fSKevin Cheng 	/*
82*0de1020fSKevin Cheng 	 * Note, EPT page table accesses are always read+write, e.g. so that
83*0de1020fSKevin Cheng 	 * the CPU can do A/D updates at-will.
84*0de1020fSKevin Cheng 	 */
85*0de1020fSKevin Cheng 	switch (test_type) {
86*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_UNMAPPED:
87*0de1020fSKevin Cheng 		GUEST_ASSERT_EXIT_QUAL(exit_qual, EPT_VIOLATION_ACC_READ |
88*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_IS_VALID |
89*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_TRANSLATED);
90*0de1020fSKevin Cheng 		break;
91*0de1020fSKevin Cheng 	case TEST_PT_PAGE_UNMAPPED:
92*0de1020fSKevin Cheng 		GUEST_ASSERT_EXIT_QUAL(exit_qual, EPT_VIOLATION_ACC_READ |
93*0de1020fSKevin Cheng 						  EPT_VIOLATION_ACC_WRITE |
94*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_IS_VALID);
95*0de1020fSKevin Cheng 		break;
96*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_WRITE_PROTECTED:
97*0de1020fSKevin Cheng 		GUEST_ASSERT_EXIT_QUAL(exit_qual, EPT_VIOLATION_ACC_WRITE |
98*0de1020fSKevin Cheng 						  EPT_VIOLATION_PROT_READ |
99*0de1020fSKevin Cheng 						  EPT_VIOLATION_PROT_EXEC |
100*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_IS_VALID |
101*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_TRANSLATED);
102*0de1020fSKevin Cheng 		break;
103*0de1020fSKevin Cheng 	case TEST_PT_PAGE_WRITE_PROTECTED:
104*0de1020fSKevin Cheng 		GUEST_ASSERT_EXIT_QUAL(exit_qual, EPT_VIOLATION_ACC_READ |
105*0de1020fSKevin Cheng 						  EPT_VIOLATION_ACC_WRITE |
106*0de1020fSKevin Cheng 						  EPT_VIOLATION_PROT_READ |
107*0de1020fSKevin Cheng 						  EPT_VIOLATION_PROT_EXEC |
108*0de1020fSKevin Cheng 						  EPT_VIOLATION_GVA_IS_VALID);
109*0de1020fSKevin Cheng 		break;
110*0de1020fSKevin Cheng 	}
111*0de1020fSKevin Cheng 
112*0de1020fSKevin Cheng 	GUEST_DONE();
113*0de1020fSKevin Cheng }
114*0de1020fSKevin Cheng 
115*0de1020fSKevin Cheng #define GUEST_ASSERT_NPF_EC(ac_ec, ex_ec)		\
116*0de1020fSKevin Cheng 	__GUEST_ASSERT((ac_ec) == (ex_ec),		\
117*0de1020fSKevin Cheng 		       "Wanted NPF error code '0x%lx', got '0x%lx'", (u64)(ex_ec), ac_ec)
118*0de1020fSKevin Cheng 
119*0de1020fSKevin Cheng 
120*0de1020fSKevin Cheng static void l1_svm_code(struct svm_test_data *svm, u64 expected_fault_gpa,
121*0de1020fSKevin Cheng 			 u64 test_type)
122*0de1020fSKevin Cheng {
123*0de1020fSKevin Cheng 	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
124*0de1020fSKevin Cheng 	struct vmcb *vmcb = svm->vmcb;
125*0de1020fSKevin Cheng 	u64 exit_info_1;
126*0de1020fSKevin Cheng 
127*0de1020fSKevin Cheng 	generic_svm_setup(svm, l2_entry,
128*0de1020fSKevin Cheng 			  &l2_guest_stack[L2_GUEST_STACK_SIZE]);
129*0de1020fSKevin Cheng 
130*0de1020fSKevin Cheng 	run_guest(vmcb, svm->vmcb_gpa);
131*0de1020fSKevin Cheng 
132*0de1020fSKevin Cheng 	/* Verify we got an NPF exit */
133*0de1020fSKevin Cheng 	__GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_NPF,
134*0de1020fSKevin Cheng 		       "Expected NPF exit (0x%x), got 0x%lx", SVM_EXIT_NPF,
135*0de1020fSKevin Cheng 		       vmcb->control.exit_code);
136*0de1020fSKevin Cheng 
137*0de1020fSKevin Cheng 	__GUEST_ASSERT(vmcb->control.exit_info_2 == expected_fault_gpa,
138*0de1020fSKevin Cheng 		       "Expected exit_info_2 = 0x%lx, got 0x%lx",
139*0de1020fSKevin Cheng 		       expected_fault_gpa,
140*0de1020fSKevin Cheng 		       vmcb->control.exit_info_2);
141*0de1020fSKevin Cheng 
142*0de1020fSKevin Cheng 	exit_info_1 = vmcb->control.exit_info_1;
143*0de1020fSKevin Cheng 
144*0de1020fSKevin Cheng 	/*
145*0de1020fSKevin Cheng 	 * Note, without GMET enabled, NPT walks are always user accesses.  And
146*0de1020fSKevin Cheng 	 * like EPT, page table accesses are always read+write.
147*0de1020fSKevin Cheng 	 */
148*0de1020fSKevin Cheng 	switch (test_type) {
149*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_UNMAPPED:
150*0de1020fSKevin Cheng 		GUEST_ASSERT_NPF_EC(exit_info_1, PFERR_USER_MASK |
151*0de1020fSKevin Cheng 						 PFERR_GUEST_FINAL_MASK);
152*0de1020fSKevin Cheng 		break;
153*0de1020fSKevin Cheng 	case TEST_PT_PAGE_UNMAPPED:
154*0de1020fSKevin Cheng 		GUEST_ASSERT_NPF_EC(exit_info_1, PFERR_WRITE_MASK |
155*0de1020fSKevin Cheng 						 PFERR_USER_MASK |
156*0de1020fSKevin Cheng 						 PFERR_GUEST_PAGE_MASK);
157*0de1020fSKevin Cheng 		break;
158*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_WRITE_PROTECTED:
159*0de1020fSKevin Cheng 		GUEST_ASSERT_NPF_EC(exit_info_1, PFERR_PRESENT_MASK |
160*0de1020fSKevin Cheng 						 PFERR_WRITE_MASK |
161*0de1020fSKevin Cheng 						 PFERR_USER_MASK |
162*0de1020fSKevin Cheng 						 PFERR_GUEST_FINAL_MASK);
163*0de1020fSKevin Cheng 		break;
164*0de1020fSKevin Cheng 	case TEST_PT_PAGE_WRITE_PROTECTED:
165*0de1020fSKevin Cheng 		GUEST_ASSERT_NPF_EC(exit_info_1, PFERR_PRESENT_MASK |
166*0de1020fSKevin Cheng 						 PFERR_WRITE_MASK |
167*0de1020fSKevin Cheng 						 PFERR_USER_MASK |
168*0de1020fSKevin Cheng 						 PFERR_GUEST_PAGE_MASK);
169*0de1020fSKevin Cheng 		break;
170*0de1020fSKevin Cheng 	}
171*0de1020fSKevin Cheng 
172*0de1020fSKevin Cheng 	GUEST_DONE();
173*0de1020fSKevin Cheng }
174*0de1020fSKevin Cheng 
175*0de1020fSKevin Cheng static void l1_guest_code(void *data, u64 expected_fault_gpa,
176*0de1020fSKevin Cheng 			  u64 test_type)
177*0de1020fSKevin Cheng {
178*0de1020fSKevin Cheng 	if (this_cpu_has(X86_FEATURE_VMX))
179*0de1020fSKevin Cheng 		l1_vmx_code(data, expected_fault_gpa, test_type);
180*0de1020fSKevin Cheng 	else
181*0de1020fSKevin Cheng 		l1_svm_code(data, expected_fault_gpa, test_type);
182*0de1020fSKevin Cheng }
183*0de1020fSKevin Cheng 
184*0de1020fSKevin Cheng /* Returns the GPA of the PT page that maps @vaddr. */
185*0de1020fSKevin Cheng static u64 get_pt_gpa_for_vaddr(struct kvm_vm *vm, u64 vaddr)
186*0de1020fSKevin Cheng {
187*0de1020fSKevin Cheng 	u64 *pte;
188*0de1020fSKevin Cheng 
189*0de1020fSKevin Cheng 	pte = vm_get_pte(vm, vaddr);
190*0de1020fSKevin Cheng 	TEST_ASSERT(pte && (*pte & 0x1), "PTE not present for vaddr 0x%lx",
191*0de1020fSKevin Cheng 		    (unsigned long)vaddr);
192*0de1020fSKevin Cheng 
193*0de1020fSKevin Cheng 	return addr_hva2gpa(vm, (void *)((u64)pte & ~0xFFFULL));
194*0de1020fSKevin Cheng }
195*0de1020fSKevin Cheng 
196*0de1020fSKevin Cheng static void run_test(enum test_type type)
197*0de1020fSKevin Cheng {
198*0de1020fSKevin Cheng 	gpa_t expected_fault_gpa;
199*0de1020fSKevin Cheng 	gva_t nested_gva;
200*0de1020fSKevin Cheng 
201*0de1020fSKevin Cheng 	struct kvm_vcpu *vcpu;
202*0de1020fSKevin Cheng 	struct kvm_vm *vm;
203*0de1020fSKevin Cheng 	struct ucall uc;
204*0de1020fSKevin Cheng 
205*0de1020fSKevin Cheng 	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
206*0de1020fSKevin Cheng 	vm_enable_tdp(vm);
207*0de1020fSKevin Cheng 
208*0de1020fSKevin Cheng 	if (kvm_cpu_has(X86_FEATURE_VMX))
209*0de1020fSKevin Cheng 		vcpu_alloc_vmx(vm, &nested_gva);
210*0de1020fSKevin Cheng 	else
211*0de1020fSKevin Cheng 		vcpu_alloc_svm(vm, &nested_gva);
212*0de1020fSKevin Cheng 
213*0de1020fSKevin Cheng 	switch (type) {
214*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_UNMAPPED:
215*0de1020fSKevin Cheng 		/*
216*0de1020fSKevin Cheng 		 * Unmap the final data page from NPT/EPT. The guest page
217*0de1020fSKevin Cheng 		 * table walk succeeds, but the final GPA->HPA translation
218*0de1020fSKevin Cheng 		 * fails. L2 reads from the page via OUTS.
219*0de1020fSKevin Cheng 		 */
220*0de1020fSKevin Cheng 		l2_entry = l2_guest_code_outs;
221*0de1020fSKevin Cheng 		l2_test_page = vm_alloc(vm, vm->page_size, TEST1_VADDR);
222*0de1020fSKevin Cheng 		expected_fault_gpa = addr_gva2gpa(vm, l2_test_page);
223*0de1020fSKevin Cheng 		break;
224*0de1020fSKevin Cheng 	case TEST_PT_PAGE_UNMAPPED:
225*0de1020fSKevin Cheng 		/*
226*0de1020fSKevin Cheng 		 * Unmap a page table page from NPT/EPT. The hardware page
227*0de1020fSKevin Cheng 		 * table walk fails when translating the PT page's GPA
228*0de1020fSKevin Cheng 		 * through NPT/EPT. L2 reads from the page via OUTS.
229*0de1020fSKevin Cheng 		 */
230*0de1020fSKevin Cheng 		l2_entry = l2_guest_code_outs;
231*0de1020fSKevin Cheng 		l2_test_page = vm_alloc(vm, vm->page_size, TEST2_VADDR);
232*0de1020fSKevin Cheng 		expected_fault_gpa = get_pt_gpa_for_vaddr(vm, l2_test_page);
233*0de1020fSKevin Cheng 		break;
234*0de1020fSKevin Cheng 	case TEST_FINAL_PAGE_WRITE_PROTECTED:
235*0de1020fSKevin Cheng 		/*
236*0de1020fSKevin Cheng 		 * Write-protect the final data page in NPT/EPT.  The page
237*0de1020fSKevin Cheng 		 * is present and readable, but not writable.  L2 writes to
238*0de1020fSKevin Cheng 		 * the page via INS, triggering a protection violation.
239*0de1020fSKevin Cheng 		 */
240*0de1020fSKevin Cheng 		l2_entry = l2_guest_code_ins;
241*0de1020fSKevin Cheng 		l2_test_page = vm_alloc(vm, vm->page_size, TEST3_VADDR);
242*0de1020fSKevin Cheng 		expected_fault_gpa = addr_gva2gpa(vm, l2_test_page);
243*0de1020fSKevin Cheng 		break;
244*0de1020fSKevin Cheng 	case TEST_PT_PAGE_WRITE_PROTECTED:
245*0de1020fSKevin Cheng 		/*
246*0de1020fSKevin Cheng 		 * Write-protect a page table page in NPT/EPT.  The page is
247*0de1020fSKevin Cheng 		 * present and readable, but not writable.  The guest page
248*0de1020fSKevin Cheng 		 * table walk needs write access to set A/D bits, so it
249*0de1020fSKevin Cheng 		 * triggers a protection violation on the PT page.
250*0de1020fSKevin Cheng 		 * L2 reads from the page via OUTS.
251*0de1020fSKevin Cheng 		 */
252*0de1020fSKevin Cheng 		l2_entry = l2_guest_code_outs;
253*0de1020fSKevin Cheng 		l2_test_page = vm_alloc(vm, vm->page_size, TEST4_VADDR);
254*0de1020fSKevin Cheng 		expected_fault_gpa = get_pt_gpa_for_vaddr(vm, l2_test_page);
255*0de1020fSKevin Cheng 		break;
256*0de1020fSKevin Cheng 	}
257*0de1020fSKevin Cheng 
258*0de1020fSKevin Cheng 	tdp_identity_map_default_memslots(vm);
259*0de1020fSKevin Cheng 
260*0de1020fSKevin Cheng 	if (type == TEST_FINAL_PAGE_WRITE_PROTECTED ||
261*0de1020fSKevin Cheng 	    type == TEST_PT_PAGE_WRITE_PROTECTED)
262*0de1020fSKevin Cheng 		*tdp_get_pte(vm, expected_fault_gpa) &= ~PTE_WRITABLE_MASK(&vm->stage2_mmu);
263*0de1020fSKevin Cheng 	else
264*0de1020fSKevin Cheng 		*tdp_get_pte(vm, expected_fault_gpa) &= ~(PTE_PRESENT_MASK(&vm->stage2_mmu) |
265*0de1020fSKevin Cheng 							   PTE_READABLE_MASK(&vm->stage2_mmu) |
266*0de1020fSKevin Cheng 							   PTE_WRITABLE_MASK(&vm->stage2_mmu) |
267*0de1020fSKevin Cheng 							   PTE_EXECUTABLE_MASK(&vm->stage2_mmu));
268*0de1020fSKevin Cheng 
269*0de1020fSKevin Cheng 	sync_global_to_guest(vm, l2_entry);
270*0de1020fSKevin Cheng 	sync_global_to_guest(vm, l2_test_page);
271*0de1020fSKevin Cheng 	vcpu_args_set(vcpu, 3, nested_gva, expected_fault_gpa, (u64)type);
272*0de1020fSKevin Cheng 
273*0de1020fSKevin Cheng 	/*
274*0de1020fSKevin Cheng 	 * For the INS-based write test, KVM emulates the instruction and
275*0de1020fSKevin Cheng 	 * first reads from the I/O port, which exits to userspace.
276*0de1020fSKevin Cheng 	 * Re-enter the guest so emulation can proceed to the memory
277*0de1020fSKevin Cheng 	 * write, where the nested page fault is triggered.
278*0de1020fSKevin Cheng 	 */
279*0de1020fSKevin Cheng 	for (;;) {
280*0de1020fSKevin Cheng 		vcpu_run(vcpu);
281*0de1020fSKevin Cheng 
282*0de1020fSKevin Cheng 		if (vcpu->run->exit_reason == KVM_EXIT_IO &&
283*0de1020fSKevin Cheng 		    vcpu->run->io.port == TEST_IO_PORT &&
284*0de1020fSKevin Cheng 		    vcpu->run->io.direction == KVM_EXIT_IO_IN) {
285*0de1020fSKevin Cheng 			continue;
286*0de1020fSKevin Cheng 		}
287*0de1020fSKevin Cheng 		break;
288*0de1020fSKevin Cheng 	}
289*0de1020fSKevin Cheng 
290*0de1020fSKevin Cheng 	switch (get_ucall(vcpu, &uc)) {
291*0de1020fSKevin Cheng 	case UCALL_DONE:
292*0de1020fSKevin Cheng 		break;
293*0de1020fSKevin Cheng 	case UCALL_ABORT:
294*0de1020fSKevin Cheng 		REPORT_GUEST_ASSERT(uc);
295*0de1020fSKevin Cheng 	default:
296*0de1020fSKevin Cheng 		TEST_FAIL("Unexpected exit reason: %d", vcpu->run->exit_reason);
297*0de1020fSKevin Cheng 	}
298*0de1020fSKevin Cheng 
299*0de1020fSKevin Cheng 	kvm_vm_free(vm);
300*0de1020fSKevin Cheng }
301*0de1020fSKevin Cheng 
302*0de1020fSKevin Cheng int main(int argc, char *argv[])
303*0de1020fSKevin Cheng {
304*0de1020fSKevin Cheng 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || kvm_cpu_has(X86_FEATURE_SVM));
305*0de1020fSKevin Cheng 	TEST_REQUIRE(kvm_cpu_has_tdp());
306*0de1020fSKevin Cheng 
307*0de1020fSKevin Cheng 	run_test(TEST_FINAL_PAGE_UNMAPPED);
308*0de1020fSKevin Cheng 	run_test(TEST_PT_PAGE_UNMAPPED);
309*0de1020fSKevin Cheng 	run_test(TEST_FINAL_PAGE_WRITE_PROTECTED);
310*0de1020fSKevin Cheng 	run_test(TEST_PT_PAGE_WRITE_PROTECTED);
311*0de1020fSKevin Cheng 
312*0de1020fSKevin Cheng 	return 0;
313*0de1020fSKevin Cheng }
314