1 #include "svm.h" 2 #include "vm.h" 3 #include "alloc_page.h" 4 #include "vmalloc.h" 5 6 static void *scratch_page; 7 8 static void null_test(struct svm_test *test) 9 { 10 } 11 12 static void npt_np_prepare(struct svm_test *test) 13 { 14 u64 *pte; 15 16 scratch_page = alloc_page(); 17 pte = npt_get_pte((u64) scratch_page); 18 19 *pte &= ~1ULL; 20 } 21 22 static void npt_np_test(struct svm_test *test) 23 { 24 (void)*(volatile u64 *)scratch_page; 25 } 26 27 static bool npt_np_check(struct svm_test *test) 28 { 29 u64 *pte = npt_get_pte((u64) scratch_page); 30 31 *pte |= 1ULL; 32 33 return (vmcb->control.exit_code == SVM_EXIT_NPF) 34 && (vmcb->control.exit_info_1 == 0x100000004ULL); 35 } 36 37 static void npt_nx_prepare(struct svm_test *test) 38 { 39 u64 *pte; 40 41 test->scratch = rdmsr(MSR_EFER); 42 wrmsr(MSR_EFER, test->scratch | EFER_NX); 43 44 /* Clear the guest's EFER.NX, it should not affect NPT behavior. */ 45 vmcb->save.efer &= ~EFER_NX; 46 47 pte = npt_get_pte((u64) null_test); 48 49 *pte |= PT64_NX_MASK; 50 } 51 52 static bool npt_nx_check(struct svm_test *test) 53 { 54 u64 *pte = npt_get_pte((u64) null_test); 55 56 wrmsr(MSR_EFER, test->scratch); 57 58 *pte &= ~PT64_NX_MASK; 59 60 return (vmcb->control.exit_code == SVM_EXIT_NPF) 61 && (vmcb->control.exit_info_1 == 0x100000015ULL); 62 } 63 64 static void npt_us_prepare(struct svm_test *test) 65 { 66 u64 *pte; 67 68 scratch_page = alloc_page(); 69 pte = npt_get_pte((u64) scratch_page); 70 71 *pte &= ~(1ULL << 2); 72 } 73 74 static void npt_us_test(struct svm_test *test) 75 { 76 (void)*(volatile u64 *)scratch_page; 77 } 78 79 static bool npt_us_check(struct svm_test *test) 80 { 81 u64 *pte = npt_get_pte((u64) scratch_page); 82 83 *pte |= (1ULL << 2); 84 85 return (vmcb->control.exit_code == SVM_EXIT_NPF) 86 && (vmcb->control.exit_info_1 == 0x100000005ULL); 87 } 88 89 static void npt_rw_prepare(struct svm_test *test) 90 { 91 92 u64 *pte; 93 94 pte = npt_get_pte(0x80000); 95 96 *pte &= ~(1ULL << 1); 97 } 98 99 static void npt_rw_test(struct svm_test *test) 100 { 101 u64 *data = (void *)(0x80000); 102 103 *data = 0; 104 } 105 106 static bool npt_rw_check(struct svm_test *test) 107 { 108 u64 *pte = npt_get_pte(0x80000); 109 110 *pte |= (1ULL << 1); 111 112 return (vmcb->control.exit_code == SVM_EXIT_NPF) 113 && (vmcb->control.exit_info_1 == 0x100000007ULL); 114 } 115 116 static void npt_rw_pfwalk_prepare(struct svm_test *test) 117 { 118 119 u64 *pte; 120 121 pte = npt_get_pte(read_cr3()); 122 123 *pte &= ~(1ULL << 1); 124 } 125 126 static bool npt_rw_pfwalk_check(struct svm_test *test) 127 { 128 u64 *pte = npt_get_pte(read_cr3()); 129 130 *pte |= (1ULL << 1); 131 132 return (vmcb->control.exit_code == SVM_EXIT_NPF) 133 && (vmcb->control.exit_info_1 == 0x200000007ULL) 134 && (vmcb->control.exit_info_2 == read_cr3()); 135 } 136 137 static void npt_l1mmio_prepare(struct svm_test *test) 138 { 139 } 140 141 u32 nested_apic_version1; 142 u32 nested_apic_version2; 143 144 static void npt_l1mmio_test(struct svm_test *test) 145 { 146 volatile u32 *data = (volatile void *)(0xfee00030UL); 147 148 nested_apic_version1 = *data; 149 nested_apic_version2 = *data; 150 } 151 152 static bool npt_l1mmio_check(struct svm_test *test) 153 { 154 volatile u32 *data = (volatile void *)(0xfee00030); 155 u32 lvr = *data; 156 157 return nested_apic_version1 == lvr && nested_apic_version2 == lvr; 158 } 159 160 static void npt_rw_l1mmio_prepare(struct svm_test *test) 161 { 162 163 u64 *pte; 164 165 pte = npt_get_pte(0xfee00080); 166 167 *pte &= ~(1ULL << 1); 168 } 169 170 static void npt_rw_l1mmio_test(struct svm_test *test) 171 { 172 volatile u32 *data = (volatile void *)(0xfee00080); 173 174 *data = *data; 175 } 176 177 static bool npt_rw_l1mmio_check(struct svm_test *test) 178 { 179 u64 *pte = npt_get_pte(0xfee00080); 180 181 *pte |= (1ULL << 1); 182 183 return (vmcb->control.exit_code == SVM_EXIT_NPF) 184 && (vmcb->control.exit_info_1 == 0x100000007ULL); 185 } 186 187 static void basic_guest_main(struct svm_test *test) 188 { 189 } 190 191 static void __svm_npt_rsvd_bits_test(u64 * pxe, u64 rsvd_bits, u64 efer, 192 ulong cr4, u64 guest_efer, ulong guest_cr4) 193 { 194 u64 pxe_orig = *pxe; 195 int exit_reason; 196 u64 pfec; 197 198 wrmsr(MSR_EFER, efer); 199 write_cr4(cr4); 200 201 vmcb->save.efer = guest_efer; 202 vmcb->save.cr4 = guest_cr4; 203 204 *pxe |= rsvd_bits; 205 206 exit_reason = svm_vmrun(); 207 208 report(exit_reason == SVM_EXIT_NPF, 209 "Wanted #NPF on rsvd bits = 0x%lx, got exit = 0x%x", rsvd_bits, 210 exit_reason); 211 212 if (pxe == npt_get_pdpe((u64) basic_guest_main) || pxe == npt_get_pml4e()) { 213 /* 214 * The guest's page tables will blow up on a bad PDPE/PML4E, 215 * before starting the final walk of the guest page. 216 */ 217 pfec = 0x20000000full; 218 } else { 219 /* RSVD #NPF on final walk of guest page. */ 220 pfec = 0x10000000dULL; 221 222 /* PFEC.FETCH=1 if NX=1 *or* SMEP=1. */ 223 if ((cr4 & X86_CR4_SMEP) || (efer & EFER_NX)) 224 pfec |= 0x10; 225 226 } 227 228 report(vmcb->control.exit_info_1 == pfec, 229 "Wanted PFEC = 0x%lx, got PFEC = %lx, PxE = 0x%lx. " 230 "host.NX = %u, host.SMEP = %u, guest.NX = %u, guest.SMEP = %u", 231 pfec, vmcb->control.exit_info_1, *pxe, 232 !!(efer & EFER_NX), !!(cr4 & X86_CR4_SMEP), 233 !!(guest_efer & EFER_NX), !!(guest_cr4 & X86_CR4_SMEP)); 234 235 *pxe = pxe_orig; 236 } 237 238 static void _svm_npt_rsvd_bits_test(u64 * pxe, u64 pxe_rsvd_bits, u64 efer, 239 ulong cr4, u64 guest_efer, ulong guest_cr4) 240 { 241 u64 rsvd_bits; 242 int i; 243 244 /* 245 * RDTSC or RDRAND can sometimes fail to generate a valid reserved bits 246 */ 247 if (!pxe_rsvd_bits) { 248 report_skip 249 ("svm_npt_rsvd_bits_test: Reserved bits are not valid"); 250 return; 251 } 252 253 /* 254 * Test all combinations of guest/host EFER.NX and CR4.SMEP. If host 255 * EFER.NX=0, use NX as the reserved bit, otherwise use the passed in 256 * @pxe_rsvd_bits. 257 */ 258 for (i = 0; i < 16; i++) { 259 if (i & 1) { 260 rsvd_bits = pxe_rsvd_bits; 261 efer |= EFER_NX; 262 } else { 263 rsvd_bits = PT64_NX_MASK; 264 efer &= ~EFER_NX; 265 } 266 if (i & 2) 267 cr4 |= X86_CR4_SMEP; 268 else 269 cr4 &= ~X86_CR4_SMEP; 270 if (i & 4) 271 guest_efer |= EFER_NX; 272 else 273 guest_efer &= ~EFER_NX; 274 if (i & 8) 275 guest_cr4 |= X86_CR4_SMEP; 276 else 277 guest_cr4 &= ~X86_CR4_SMEP; 278 279 __svm_npt_rsvd_bits_test(pxe, rsvd_bits, efer, cr4, 280 guest_efer, guest_cr4); 281 } 282 } 283 284 static u64 get_random_bits(u64 hi, u64 low) 285 { 286 unsigned retry = 5; 287 u64 rsvd_bits = 0; 288 289 if (this_cpu_has(X86_FEATURE_RDRAND)) { 290 do { 291 rsvd_bits = (rdrand() << low) & GENMASK_ULL(hi, low); 292 retry--; 293 } while (!rsvd_bits && retry); 294 } 295 296 if (!rsvd_bits) { 297 retry = 5; 298 do { 299 rsvd_bits = (rdtsc() << low) & GENMASK_ULL(hi, low); 300 retry--; 301 } while (!rsvd_bits && retry); 302 } 303 304 return rsvd_bits; 305 } 306 307 static void svm_npt_rsvd_bits_test(void) 308 { 309 u64 saved_efer, host_efer, sg_efer, guest_efer; 310 ulong saved_cr4, host_cr4, sg_cr4, guest_cr4; 311 312 if (!npt_supported()) { 313 report_skip("NPT not supported"); 314 return; 315 } 316 317 saved_efer = host_efer = rdmsr(MSR_EFER); 318 saved_cr4 = host_cr4 = read_cr4(); 319 sg_efer = guest_efer = vmcb->save.efer; 320 sg_cr4 = guest_cr4 = vmcb->save.cr4; 321 322 test_set_guest(basic_guest_main); 323 324 /* 325 * 4k PTEs don't have reserved bits if MAXPHYADDR >= 52, just skip the 326 * sub-test. The NX test is still valid, but the extra bit of coverage 327 * isn't worth the extra complexity. 328 */ 329 if (cpuid_maxphyaddr() >= 52) 330 goto skip_pte_test; 331 332 _svm_npt_rsvd_bits_test(npt_get_pte((u64) basic_guest_main), 333 get_random_bits(51, cpuid_maxphyaddr()), 334 host_efer, host_cr4, guest_efer, guest_cr4); 335 336 skip_pte_test: 337 _svm_npt_rsvd_bits_test(npt_get_pde((u64) basic_guest_main), 338 get_random_bits(20, 13) | PT_PAGE_SIZE_MASK, 339 host_efer, host_cr4, guest_efer, guest_cr4); 340 341 _svm_npt_rsvd_bits_test(npt_get_pdpe((u64) basic_guest_main), 342 PT_PAGE_SIZE_MASK | 343 (this_cpu_has(X86_FEATURE_GBPAGES) ? 344 get_random_bits(29, 13) : 0), host_efer, 345 host_cr4, guest_efer, guest_cr4); 346 347 _svm_npt_rsvd_bits_test(npt_get_pml4e(), BIT_ULL(8), 348 host_efer, host_cr4, guest_efer, guest_cr4); 349 350 wrmsr(MSR_EFER, saved_efer); 351 write_cr4(saved_cr4); 352 vmcb->save.efer = sg_efer; 353 vmcb->save.cr4 = sg_cr4; 354 } 355 356 #define NPT_V1_TEST(name, prepare, guest_code, check) \ 357 { #name, npt_supported, prepare, default_prepare_gif_clear, guest_code, \ 358 default_finished, check } 359 360 #define NPT_V2_TEST(name) { #name, .v2 = name } 361 362 static struct svm_test npt_tests[] = { 363 NPT_V1_TEST(npt_nx, npt_nx_prepare, null_test, npt_nx_check), 364 NPT_V1_TEST(npt_np, npt_np_prepare, npt_np_test, npt_np_check), 365 NPT_V1_TEST(npt_us, npt_us_prepare, npt_us_test, npt_us_check), 366 NPT_V1_TEST(npt_rw, npt_rw_prepare, npt_rw_test, npt_rw_check), 367 NPT_V1_TEST(npt_rw_pfwalk, npt_rw_pfwalk_prepare, null_test, npt_rw_pfwalk_check), 368 NPT_V1_TEST(npt_l1mmio, npt_l1mmio_prepare, npt_l1mmio_test, npt_l1mmio_check), 369 NPT_V1_TEST(npt_rw_l1mmio, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test, npt_rw_l1mmio_check), 370 NPT_V2_TEST(svm_npt_rsvd_bits_test), 371 { NULL, NULL, NULL, NULL, NULL, NULL, NULL } 372 }; 373 374 int main(int ac, char **av) 375 { 376 pteval_t opt_mask = 0; 377 378 __setup_vm(&opt_mask); 379 return run_svm_tests(ac, av, npt_tests); 380 } 381