xref: /kvm-unit-tests/x86/svm_npt.c (revision f3f338619e4938c2509f5c691adc1f331b07c203)
1*63a180cbSSean Christopherson #include "apic.h"
262f5db4bSSean Christopherson #include "svm.h"
362f5db4bSSean Christopherson #include "vm.h"
462f5db4bSSean Christopherson #include "alloc_page.h"
562f5db4bSSean Christopherson #include "vmalloc.h"
662f5db4bSSean Christopherson 
762f5db4bSSean Christopherson static void *scratch_page;
862f5db4bSSean Christopherson 
null_test(struct svm_test * test)962f5db4bSSean Christopherson static void null_test(struct svm_test *test)
1062f5db4bSSean Christopherson {
1162f5db4bSSean Christopherson }
1262f5db4bSSean Christopherson 
npt_np_prepare(struct svm_test * test)1362f5db4bSSean Christopherson static void npt_np_prepare(struct svm_test *test)
1462f5db4bSSean Christopherson {
1562f5db4bSSean Christopherson 	u64 *pte;
1662f5db4bSSean Christopherson 
1762f5db4bSSean Christopherson 	scratch_page = alloc_page();
1862f5db4bSSean Christopherson 	pte = npt_get_pte((u64) scratch_page);
1962f5db4bSSean Christopherson 
2062f5db4bSSean Christopherson 	*pte &= ~1ULL;
2162f5db4bSSean Christopherson }
2262f5db4bSSean Christopherson 
npt_np_test(struct svm_test * test)2362f5db4bSSean Christopherson static void npt_np_test(struct svm_test *test)
2462f5db4bSSean Christopherson {
2562f5db4bSSean Christopherson 	(void)*(volatile u64 *)scratch_page;
2662f5db4bSSean Christopherson }
2762f5db4bSSean Christopherson 
npt_np_check(struct svm_test * test)2862f5db4bSSean Christopherson static bool npt_np_check(struct svm_test *test)
2962f5db4bSSean Christopherson {
3062f5db4bSSean Christopherson 	u64 *pte = npt_get_pte((u64) scratch_page);
3162f5db4bSSean Christopherson 
3262f5db4bSSean Christopherson 	*pte |= 1ULL;
3362f5db4bSSean Christopherson 
3462f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
3562f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x100000004ULL);
3662f5db4bSSean Christopherson }
3762f5db4bSSean Christopherson 
npt_nx_prepare(struct svm_test * test)3862f5db4bSSean Christopherson static void npt_nx_prepare(struct svm_test *test)
3962f5db4bSSean Christopherson {
4062f5db4bSSean Christopherson 	u64 *pte;
4162f5db4bSSean Christopherson 
4262f5db4bSSean Christopherson 	test->scratch = rdmsr(MSR_EFER);
4362f5db4bSSean Christopherson 	wrmsr(MSR_EFER, test->scratch | EFER_NX);
4462f5db4bSSean Christopherson 
4562f5db4bSSean Christopherson 	/* Clear the guest's EFER.NX, it should not affect NPT behavior. */
4662f5db4bSSean Christopherson 	vmcb->save.efer &= ~EFER_NX;
4762f5db4bSSean Christopherson 
4862f5db4bSSean Christopherson 	pte = npt_get_pte((u64) null_test);
4962f5db4bSSean Christopherson 
5062f5db4bSSean Christopherson 	*pte |= PT64_NX_MASK;
5162f5db4bSSean Christopherson }
5262f5db4bSSean Christopherson 
npt_nx_check(struct svm_test * test)5362f5db4bSSean Christopherson static bool npt_nx_check(struct svm_test *test)
5462f5db4bSSean Christopherson {
5562f5db4bSSean Christopherson 	u64 *pte = npt_get_pte((u64) null_test);
5662f5db4bSSean Christopherson 
5762f5db4bSSean Christopherson 	wrmsr(MSR_EFER, test->scratch);
5862f5db4bSSean Christopherson 
5962f5db4bSSean Christopherson 	*pte &= ~PT64_NX_MASK;
6062f5db4bSSean Christopherson 
6162f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
6262f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x100000015ULL);
6362f5db4bSSean Christopherson }
6462f5db4bSSean Christopherson 
npt_us_prepare(struct svm_test * test)6562f5db4bSSean Christopherson static void npt_us_prepare(struct svm_test *test)
6662f5db4bSSean Christopherson {
6762f5db4bSSean Christopherson 	u64 *pte;
6862f5db4bSSean Christopherson 
6962f5db4bSSean Christopherson 	scratch_page = alloc_page();
7062f5db4bSSean Christopherson 	pte = npt_get_pte((u64) scratch_page);
7162f5db4bSSean Christopherson 
7262f5db4bSSean Christopherson 	*pte &= ~(1ULL << 2);
7362f5db4bSSean Christopherson }
7462f5db4bSSean Christopherson 
npt_us_test(struct svm_test * test)7562f5db4bSSean Christopherson static void npt_us_test(struct svm_test *test)
7662f5db4bSSean Christopherson {
7762f5db4bSSean Christopherson 	(void)*(volatile u64 *)scratch_page;
7862f5db4bSSean Christopherson }
7962f5db4bSSean Christopherson 
npt_us_check(struct svm_test * test)8062f5db4bSSean Christopherson static bool npt_us_check(struct svm_test *test)
8162f5db4bSSean Christopherson {
8262f5db4bSSean Christopherson 	u64 *pte = npt_get_pte((u64) scratch_page);
8362f5db4bSSean Christopherson 
8462f5db4bSSean Christopherson 	*pte |= (1ULL << 2);
8562f5db4bSSean Christopherson 
8662f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
8762f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x100000005ULL);
8862f5db4bSSean Christopherson }
8962f5db4bSSean Christopherson 
npt_rw_prepare(struct svm_test * test)9062f5db4bSSean Christopherson static void npt_rw_prepare(struct svm_test *test)
9162f5db4bSSean Christopherson {
9262f5db4bSSean Christopherson 
9362f5db4bSSean Christopherson 	u64 *pte;
9462f5db4bSSean Christopherson 
9562f5db4bSSean Christopherson 	pte = npt_get_pte(0x80000);
9662f5db4bSSean Christopherson 
9762f5db4bSSean Christopherson 	*pte &= ~(1ULL << 1);
9862f5db4bSSean Christopherson }
9962f5db4bSSean Christopherson 
npt_rw_test(struct svm_test * test)10062f5db4bSSean Christopherson static void npt_rw_test(struct svm_test *test)
10162f5db4bSSean Christopherson {
10262f5db4bSSean Christopherson 	u64 *data = (void *)(0x80000);
10362f5db4bSSean Christopherson 
10462f5db4bSSean Christopherson 	*data = 0;
10562f5db4bSSean Christopherson }
10662f5db4bSSean Christopherson 
npt_rw_check(struct svm_test * test)10762f5db4bSSean Christopherson static bool npt_rw_check(struct svm_test *test)
10862f5db4bSSean Christopherson {
10962f5db4bSSean Christopherson 	u64 *pte = npt_get_pte(0x80000);
11062f5db4bSSean Christopherson 
11162f5db4bSSean Christopherson 	*pte |= (1ULL << 1);
11262f5db4bSSean Christopherson 
11362f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
11462f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x100000007ULL);
11562f5db4bSSean Christopherson }
11662f5db4bSSean Christopherson 
npt_rw_pfwalk_prepare(struct svm_test * test)11762f5db4bSSean Christopherson static void npt_rw_pfwalk_prepare(struct svm_test *test)
11862f5db4bSSean Christopherson {
11962f5db4bSSean Christopherson 
12062f5db4bSSean Christopherson 	u64 *pte;
12162f5db4bSSean Christopherson 
12262f5db4bSSean Christopherson 	pte = npt_get_pte(read_cr3());
12362f5db4bSSean Christopherson 
12462f5db4bSSean Christopherson 	*pte &= ~(1ULL << 1);
12562f5db4bSSean Christopherson }
12662f5db4bSSean Christopherson 
npt_rw_pfwalk_check(struct svm_test * test)12762f5db4bSSean Christopherson static bool npt_rw_pfwalk_check(struct svm_test *test)
12862f5db4bSSean Christopherson {
12962f5db4bSSean Christopherson 	u64 *pte = npt_get_pte(read_cr3());
13062f5db4bSSean Christopherson 
13162f5db4bSSean Christopherson 	*pte |= (1ULL << 1);
13262f5db4bSSean Christopherson 
13362f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
13462f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x200000007ULL)
13562f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_2 == read_cr3());
13662f5db4bSSean Christopherson }
13762f5db4bSSean Christopherson 
138*63a180cbSSean Christopherson static bool was_x2apic;
139*63a180cbSSean Christopherson 
npt_apic_prepare(void)140*63a180cbSSean Christopherson static void npt_apic_prepare(void)
141*63a180cbSSean Christopherson {
142*63a180cbSSean Christopherson 	was_x2apic = is_x2apic_enabled();
143*63a180cbSSean Christopherson 
144*63a180cbSSean Christopherson 	if (was_x2apic)
145*63a180cbSSean Christopherson 		reset_apic();
146*63a180cbSSean Christopherson }
147*63a180cbSSean Christopherson 
npt_apic_restore(void)148*63a180cbSSean Christopherson static void npt_apic_restore(void)
149*63a180cbSSean Christopherson {
150*63a180cbSSean Christopherson 	if (was_x2apic)
151*63a180cbSSean Christopherson 		enable_x2apic();
152*63a180cbSSean Christopherson 
153*63a180cbSSean Christopherson 	was_x2apic = false;
154*63a180cbSSean Christopherson }
155*63a180cbSSean Christopherson 
npt_l1mmio_prepare(struct svm_test * test)15662f5db4bSSean Christopherson static void npt_l1mmio_prepare(struct svm_test *test)
15762f5db4bSSean Christopherson {
158*63a180cbSSean Christopherson 	npt_apic_prepare();
15962f5db4bSSean Christopherson }
16062f5db4bSSean Christopherson 
16162f5db4bSSean Christopherson u32 nested_apic_version1;
16262f5db4bSSean Christopherson u32 nested_apic_version2;
16362f5db4bSSean Christopherson 
npt_l1mmio_test(struct svm_test * test)16462f5db4bSSean Christopherson static void npt_l1mmio_test(struct svm_test *test)
16562f5db4bSSean Christopherson {
16662f5db4bSSean Christopherson 	volatile u32 *data = (volatile void *)(0xfee00030UL);
16762f5db4bSSean Christopherson 
16862f5db4bSSean Christopherson 	nested_apic_version1 = *data;
16962f5db4bSSean Christopherson 	nested_apic_version2 = *data;
17062f5db4bSSean Christopherson }
17162f5db4bSSean Christopherson 
npt_l1mmio_check(struct svm_test * test)17262f5db4bSSean Christopherson static bool npt_l1mmio_check(struct svm_test *test)
17362f5db4bSSean Christopherson {
17462f5db4bSSean Christopherson 	volatile u32 *data = (volatile void *)(0xfee00030);
17562f5db4bSSean Christopherson 	u32 lvr = *data;
17662f5db4bSSean Christopherson 
177*63a180cbSSean Christopherson 	/* Restore APIC state *after* reading LVR. */
178*63a180cbSSean Christopherson 	npt_apic_restore();
179*63a180cbSSean Christopherson 
18062f5db4bSSean Christopherson 	return nested_apic_version1 == lvr && nested_apic_version2 == lvr;
18162f5db4bSSean Christopherson }
18262f5db4bSSean Christopherson 
npt_rw_l1mmio_prepare(struct svm_test * test)18362f5db4bSSean Christopherson static void npt_rw_l1mmio_prepare(struct svm_test *test)
18462f5db4bSSean Christopherson {
18562f5db4bSSean Christopherson 
18662f5db4bSSean Christopherson 	u64 *pte;
18762f5db4bSSean Christopherson 
188*63a180cbSSean Christopherson 	npt_apic_prepare();
189*63a180cbSSean Christopherson 
19062f5db4bSSean Christopherson 	pte = npt_get_pte(0xfee00080);
19162f5db4bSSean Christopherson 
19262f5db4bSSean Christopherson 	*pte &= ~(1ULL << 1);
19362f5db4bSSean Christopherson }
19462f5db4bSSean Christopherson 
npt_rw_l1mmio_test(struct svm_test * test)19562f5db4bSSean Christopherson static void npt_rw_l1mmio_test(struct svm_test *test)
19662f5db4bSSean Christopherson {
19762f5db4bSSean Christopherson 	volatile u32 *data = (volatile void *)(0xfee00080);
19862f5db4bSSean Christopherson 
19962f5db4bSSean Christopherson 	*data = *data;
20062f5db4bSSean Christopherson }
20162f5db4bSSean Christopherson 
npt_rw_l1mmio_check(struct svm_test * test)20262f5db4bSSean Christopherson static bool npt_rw_l1mmio_check(struct svm_test *test)
20362f5db4bSSean Christopherson {
20462f5db4bSSean Christopherson 	u64 *pte = npt_get_pte(0xfee00080);
20562f5db4bSSean Christopherson 
20662f5db4bSSean Christopherson 	*pte |= (1ULL << 1);
20762f5db4bSSean Christopherson 
208*63a180cbSSean Christopherson 	npt_apic_restore();
209*63a180cbSSean Christopherson 
21062f5db4bSSean Christopherson 	return (vmcb->control.exit_code == SVM_EXIT_NPF)
21162f5db4bSSean Christopherson 	    && (vmcb->control.exit_info_1 == 0x100000007ULL);
21262f5db4bSSean Christopherson }
21362f5db4bSSean Christopherson 
basic_guest_main(struct svm_test * test)21462f5db4bSSean Christopherson static void basic_guest_main(struct svm_test *test)
21562f5db4bSSean Christopherson {
21662f5db4bSSean Christopherson }
21762f5db4bSSean Christopherson 
__svm_npt_rsvd_bits_test(u64 * pxe,u64 rsvd_bits,u64 efer,ulong cr4,u64 guest_efer,ulong guest_cr4)21862f5db4bSSean Christopherson static void __svm_npt_rsvd_bits_test(u64 * pxe, u64 rsvd_bits, u64 efer,
21962f5db4bSSean Christopherson 				     ulong cr4, u64 guest_efer, ulong guest_cr4)
22062f5db4bSSean Christopherson {
22162f5db4bSSean Christopherson 	u64 pxe_orig = *pxe;
22262f5db4bSSean Christopherson 	int exit_reason;
22362f5db4bSSean Christopherson 	u64 pfec;
22462f5db4bSSean Christopherson 
22562f5db4bSSean Christopherson 	wrmsr(MSR_EFER, efer);
22662f5db4bSSean Christopherson 	write_cr4(cr4);
22762f5db4bSSean Christopherson 
22862f5db4bSSean Christopherson 	vmcb->save.efer = guest_efer;
22962f5db4bSSean Christopherson 	vmcb->save.cr4 = guest_cr4;
23062f5db4bSSean Christopherson 
23162f5db4bSSean Christopherson 	*pxe |= rsvd_bits;
23262f5db4bSSean Christopherson 
23362f5db4bSSean Christopherson 	exit_reason = svm_vmrun();
23462f5db4bSSean Christopherson 
23562f5db4bSSean Christopherson 	report(exit_reason == SVM_EXIT_NPF,
23662f5db4bSSean Christopherson 	       "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%x", rsvd_bits,
23762f5db4bSSean Christopherson 	       exit_reason);
23862f5db4bSSean Christopherson 
2396f5ce7c1SManali Shukla 	if (pxe == npt_get_pdpe((u64) basic_guest_main) || pxe == npt_get_pml4e()) {
24062f5db4bSSean Christopherson 		/*
24162f5db4bSSean Christopherson 		 * The guest's page tables will blow up on a bad PDPE/PML4E,
24262f5db4bSSean Christopherson 		 * before starting the final walk of the guest page.
24362f5db4bSSean Christopherson 		 */
24462f5db4bSSean Christopherson 		pfec = 0x20000000full;
24562f5db4bSSean Christopherson 	} else {
24662f5db4bSSean Christopherson 		/* RSVD #NPF on final walk of guest page. */
24762f5db4bSSean Christopherson 		pfec = 0x10000000dULL;
24862f5db4bSSean Christopherson 
24962f5db4bSSean Christopherson 		/* PFEC.FETCH=1 if NX=1 *or* SMEP=1. */
25062f5db4bSSean Christopherson 		if ((cr4 & X86_CR4_SMEP) || (efer & EFER_NX))
25162f5db4bSSean Christopherson 			pfec |= 0x10;
25262f5db4bSSean Christopherson 
25362f5db4bSSean Christopherson 	}
25462f5db4bSSean Christopherson 
25562f5db4bSSean Christopherson 	report(vmcb->control.exit_info_1 == pfec,
25662f5db4bSSean Christopherson 	       "Wanted PFEC = 0x%lx, got PFEC = %lx, PxE = 0x%lx.  "
25762f5db4bSSean Christopherson 	       "host.NX = %u, host.SMEP = %u, guest.NX = %u, guest.SMEP = %u",
25862f5db4bSSean Christopherson 	       pfec, vmcb->control.exit_info_1, *pxe,
25962f5db4bSSean Christopherson 	       !!(efer & EFER_NX), !!(cr4 & X86_CR4_SMEP),
26062f5db4bSSean Christopherson 	       !!(guest_efer & EFER_NX), !!(guest_cr4 & X86_CR4_SMEP));
26162f5db4bSSean Christopherson 
26262f5db4bSSean Christopherson 	*pxe = pxe_orig;
26362f5db4bSSean Christopherson }
26462f5db4bSSean Christopherson 
_svm_npt_rsvd_bits_test(u64 * pxe,u64 pxe_rsvd_bits,u64 efer,ulong cr4,u64 guest_efer,ulong guest_cr4)26562f5db4bSSean Christopherson static void _svm_npt_rsvd_bits_test(u64 * pxe, u64 pxe_rsvd_bits, u64 efer,
26662f5db4bSSean Christopherson 				    ulong cr4, u64 guest_efer, ulong guest_cr4)
26762f5db4bSSean Christopherson {
26862f5db4bSSean Christopherson 	u64 rsvd_bits;
26962f5db4bSSean Christopherson 	int i;
27062f5db4bSSean Christopherson 
27162f5db4bSSean Christopherson 	/*
27262f5db4bSSean Christopherson 	 * RDTSC or RDRAND can sometimes fail to generate a valid reserved bits
27362f5db4bSSean Christopherson 	 */
27462f5db4bSSean Christopherson 	if (!pxe_rsvd_bits) {
27562f5db4bSSean Christopherson 		report_skip
27662f5db4bSSean Christopherson 		    ("svm_npt_rsvd_bits_test: Reserved bits are not valid");
27762f5db4bSSean Christopherson 		return;
27862f5db4bSSean Christopherson 	}
27962f5db4bSSean Christopherson 
28062f5db4bSSean Christopherson 	/*
28162f5db4bSSean Christopherson 	 * Test all combinations of guest/host EFER.NX and CR4.SMEP.  If host
28262f5db4bSSean Christopherson 	 * EFER.NX=0, use NX as the reserved bit, otherwise use the passed in
28362f5db4bSSean Christopherson 	 * @pxe_rsvd_bits.
28462f5db4bSSean Christopherson 	 */
28562f5db4bSSean Christopherson 	for (i = 0; i < 16; i++) {
28662f5db4bSSean Christopherson 		if (i & 1) {
28762f5db4bSSean Christopherson 			rsvd_bits = pxe_rsvd_bits;
28862f5db4bSSean Christopherson 			efer |= EFER_NX;
28962f5db4bSSean Christopherson 		} else {
29062f5db4bSSean Christopherson 			rsvd_bits = PT64_NX_MASK;
29162f5db4bSSean Christopherson 			efer &= ~EFER_NX;
29262f5db4bSSean Christopherson 		}
29362f5db4bSSean Christopherson 		if (i & 2)
29462f5db4bSSean Christopherson 			cr4 |= X86_CR4_SMEP;
29562f5db4bSSean Christopherson 		else
29662f5db4bSSean Christopherson 			cr4 &= ~X86_CR4_SMEP;
29762f5db4bSSean Christopherson 		if (i & 4)
29862f5db4bSSean Christopherson 			guest_efer |= EFER_NX;
29962f5db4bSSean Christopherson 		else
30062f5db4bSSean Christopherson 			guest_efer &= ~EFER_NX;
30162f5db4bSSean Christopherson 		if (i & 8)
30262f5db4bSSean Christopherson 			guest_cr4 |= X86_CR4_SMEP;
30362f5db4bSSean Christopherson 		else
30462f5db4bSSean Christopherson 			guest_cr4 &= ~X86_CR4_SMEP;
30562f5db4bSSean Christopherson 
30662f5db4bSSean Christopherson 		__svm_npt_rsvd_bits_test(pxe, rsvd_bits, efer, cr4,
30762f5db4bSSean Christopherson 					 guest_efer, guest_cr4);
30862f5db4bSSean Christopherson 	}
30962f5db4bSSean Christopherson }
31062f5db4bSSean Christopherson 
get_random_bits(u64 hi,u64 low)31162f5db4bSSean Christopherson static u64 get_random_bits(u64 hi, u64 low)
31262f5db4bSSean Christopherson {
31362f5db4bSSean Christopherson 	unsigned retry = 5;
31462f5db4bSSean Christopherson 	u64 rsvd_bits = 0;
31562f5db4bSSean Christopherson 
31662f5db4bSSean Christopherson 	if (this_cpu_has(X86_FEATURE_RDRAND)) {
31762f5db4bSSean Christopherson 		do {
31862f5db4bSSean Christopherson 			rsvd_bits = (rdrand() << low) & GENMASK_ULL(hi, low);
31962f5db4bSSean Christopherson 			retry--;
32062f5db4bSSean Christopherson 		} while (!rsvd_bits && retry);
32162f5db4bSSean Christopherson 	}
32262f5db4bSSean Christopherson 
32362f5db4bSSean Christopherson 	if (!rsvd_bits) {
32462f5db4bSSean Christopherson 		retry = 5;
32562f5db4bSSean Christopherson 		do {
32662f5db4bSSean Christopherson 			rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low);
32762f5db4bSSean Christopherson 			retry--;
32862f5db4bSSean Christopherson 		} while (!rsvd_bits && retry);
32962f5db4bSSean Christopherson 	}
33062f5db4bSSean Christopherson 
33162f5db4bSSean Christopherson 	return rsvd_bits;
33262f5db4bSSean Christopherson }
33362f5db4bSSean Christopherson 
svm_npt_rsvd_bits_test(void)33462f5db4bSSean Christopherson static void svm_npt_rsvd_bits_test(void)
33562f5db4bSSean Christopherson {
33662f5db4bSSean Christopherson 	u64 saved_efer, host_efer, sg_efer, guest_efer;
33762f5db4bSSean Christopherson 	ulong saved_cr4, host_cr4, sg_cr4, guest_cr4;
33862f5db4bSSean Christopherson 
33962f5db4bSSean Christopherson 	if (!npt_supported()) {
34062f5db4bSSean Christopherson 		report_skip("NPT not supported");
34162f5db4bSSean Christopherson 		return;
34262f5db4bSSean Christopherson 	}
34362f5db4bSSean Christopherson 
34462f5db4bSSean Christopherson 	saved_efer = host_efer = rdmsr(MSR_EFER);
34562f5db4bSSean Christopherson 	saved_cr4 = host_cr4 = read_cr4();
34662f5db4bSSean Christopherson 	sg_efer = guest_efer = vmcb->save.efer;
34762f5db4bSSean Christopherson 	sg_cr4 = guest_cr4 = vmcb->save.cr4;
34862f5db4bSSean Christopherson 
34962f5db4bSSean Christopherson 	test_set_guest(basic_guest_main);
35062f5db4bSSean Christopherson 
35162f5db4bSSean Christopherson 	/*
35262f5db4bSSean Christopherson 	 * 4k PTEs don't have reserved bits if MAXPHYADDR >= 52, just skip the
35362f5db4bSSean Christopherson 	 * sub-test.  The NX test is still valid, but the extra bit of coverage
35462f5db4bSSean Christopherson 	 * isn't worth the extra complexity.
35562f5db4bSSean Christopherson 	 */
35662f5db4bSSean Christopherson 	if (cpuid_maxphyaddr() >= 52)
35762f5db4bSSean Christopherson 		goto skip_pte_test;
35862f5db4bSSean Christopherson 
35962f5db4bSSean Christopherson 	_svm_npt_rsvd_bits_test(npt_get_pte((u64) basic_guest_main),
36062f5db4bSSean Christopherson 				get_random_bits(51, cpuid_maxphyaddr()),
36162f5db4bSSean Christopherson 				host_efer, host_cr4, guest_efer, guest_cr4);
36262f5db4bSSean Christopherson 
36362f5db4bSSean Christopherson skip_pte_test:
36462f5db4bSSean Christopherson 	_svm_npt_rsvd_bits_test(npt_get_pde((u64) basic_guest_main),
36562f5db4bSSean Christopherson 				get_random_bits(20, 13) | PT_PAGE_SIZE_MASK,
36662f5db4bSSean Christopherson 				host_efer, host_cr4, guest_efer, guest_cr4);
36762f5db4bSSean Christopherson 
3686f5ce7c1SManali Shukla 	_svm_npt_rsvd_bits_test(npt_get_pdpe((u64) basic_guest_main),
36962f5db4bSSean Christopherson 				PT_PAGE_SIZE_MASK |
37062f5db4bSSean Christopherson 				(this_cpu_has(X86_FEATURE_GBPAGES) ?
37162f5db4bSSean Christopherson 				 get_random_bits(29, 13) : 0), host_efer,
37262f5db4bSSean Christopherson 				host_cr4, guest_efer, guest_cr4);
37362f5db4bSSean Christopherson 
37462f5db4bSSean Christopherson 	_svm_npt_rsvd_bits_test(npt_get_pml4e(), BIT_ULL(8),
37562f5db4bSSean Christopherson 				host_efer, host_cr4, guest_efer, guest_cr4);
37662f5db4bSSean Christopherson 
37762f5db4bSSean Christopherson 	wrmsr(MSR_EFER, saved_efer);
37862f5db4bSSean Christopherson 	write_cr4(saved_cr4);
37962f5db4bSSean Christopherson 	vmcb->save.efer = sg_efer;
38062f5db4bSSean Christopherson 	vmcb->save.cr4 = sg_cr4;
38162f5db4bSSean Christopherson }
38262f5db4bSSean Christopherson 
383cf75a19cSSean Christopherson #define NPT_V1_TEST(name, prepare, guest_code, check)				\
384cf75a19cSSean Christopherson 	{ #name, npt_supported, prepare, default_prepare_gif_clear, guest_code,	\
385cf75a19cSSean Christopherson 	  default_finished, check }
386cf75a19cSSean Christopherson 
387cf75a19cSSean Christopherson #define NPT_V2_TEST(name) { #name, .v2 = name }
38862f5db4bSSean Christopherson 
38962f5db4bSSean Christopherson static struct svm_test npt_tests[] = {
390cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_nx, npt_nx_prepare, null_test, npt_nx_check),
391cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_np, npt_np_prepare, npt_np_test, npt_np_check),
392cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_us, npt_us_prepare, npt_us_test, npt_us_check),
393cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_rw, npt_rw_prepare, npt_rw_test, npt_rw_check),
394cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_rw_pfwalk, npt_rw_pfwalk_prepare, null_test, npt_rw_pfwalk_check),
395cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_l1mmio, npt_l1mmio_prepare, npt_l1mmio_test, npt_l1mmio_check),
396cf75a19cSSean Christopherson 	NPT_V1_TEST(npt_rw_l1mmio, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test, npt_rw_l1mmio_check),
397cf75a19cSSean Christopherson 	NPT_V2_TEST(svm_npt_rsvd_bits_test),
39862f5db4bSSean Christopherson 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
39962f5db4bSSean Christopherson };
40062f5db4bSSean Christopherson 
main(int ac,char ** av)40162f5db4bSSean Christopherson int main(int ac, char **av)
40262f5db4bSSean Christopherson {
40362f5db4bSSean Christopherson 	pteval_t opt_mask = 0;
40462f5db4bSSean Christopherson 
40562f5db4bSSean Christopherson 	__setup_vm(&opt_mask);
40662f5db4bSSean Christopherson 	return run_svm_tests(ac, av, npt_tests);
40762f5db4bSSean Christopherson }
408