selftests: KVM: avoid failures due to reserved HyperTransport region

AMD proceessors define an address range that is reserved by HyperTransport
and causes a failure if used for guest physical addresses. Avoid
selftests failures by reserving those guest physical addresses; the
rules are:

- On parts with <40 bits, its fully hidden from software.

- Before Fam17h, it was always 12G just below 1T, even if there was more
RAM above this location. In this case we just not use any RAM above 1T.

- On Fam17h and later, it is variable based on SME, and is either just
below 2^48 (no encryption) or 2^43 (encryption).

Fixes: ef4c9f4f6546 ("KVM: selftests: Fix 32-bit truncation of vm_get_max_gfn()")
Cc: stable@vger.kernel.org
Cc: David Matlack <dmatlack@google.com>
Reported-by: Maxim Levitsky <mlevitsk@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210805105423.412878-1-pbonzini@redhat.com>
Reviewed-by: Sean Christopherson <seanjc@google.com>
Tested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

+78 -1
+9
tools/testing/selftests/kvm/include/kvm_util.h
··· 71 72 #endif 73 74 #define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT) 75 #define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE) 76
··· 71 72 #endif 73 74 + #if defined(__x86_64__) 75 + unsigned long vm_compute_max_gfn(struct kvm_vm *vm); 76 + #else 77 + static inline unsigned long vm_compute_max_gfn(struct kvm_vm *vm) 78 + { 79 + return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; 80 + } 81 + #endif 82 + 83 #define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT) 84 #define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE) 85
+1 -1
tools/testing/selftests/kvm/lib/kvm_util.c
··· 302 (1ULL << (vm->va_bits - 1)) >> vm->page_shift); 303 304 /* Limit physical addresses to PA-bits. */ 305 - vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; 306 307 /* Allocate and setup memory for guest. */ 308 vm->vpages_mapped = sparsebit_alloc();
··· 302 (1ULL << (vm->va_bits - 1)) >> vm->page_shift); 303 304 /* Limit physical addresses to PA-bits. */ 305 + vm->max_gfn = vm_compute_max_gfn(vm); 306 307 /* Allocate and setup memory for guest. */ 308 vm->vpages_mapped = sparsebit_alloc();
+68
tools/testing/selftests/kvm/lib/x86_64/processor.c
··· 1431 1432 return cpuid; 1433 }
··· 1431 1432 return cpuid; 1433 } 1434 + 1435 + #define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 1436 + #define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 1437 + #define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65 1438 + 1439 + static inline unsigned x86_family(unsigned int eax) 1440 + { 1441 + unsigned int x86; 1442 + 1443 + x86 = (eax >> 8) & 0xf; 1444 + 1445 + if (x86 == 0xf) 1446 + x86 += (eax >> 20) & 0xff; 1447 + 1448 + return x86; 1449 + } 1450 + 1451 + unsigned long vm_compute_max_gfn(struct kvm_vm *vm) 1452 + { 1453 + const unsigned long num_ht_pages = 12 << (30 - vm->page_shift); /* 12 GiB */ 1454 + unsigned long ht_gfn, max_gfn, max_pfn; 1455 + uint32_t eax, ebx, ecx, edx, max_ext_leaf; 1456 + 1457 + max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1; 1458 + 1459 + /* Avoid reserved HyperTransport region on AMD processors. */ 1460 + eax = ecx = 0; 1461 + cpuid(&eax, &ebx, &ecx, &edx); 1462 + if (ebx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx || 1463 + ecx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx || 1464 + edx != X86EMUL_CPUID_VENDOR_AuthenticAMD_edx) 1465 + return max_gfn; 1466 + 1467 + /* On parts with <40 physical address bits, the area is fully hidden */ 1468 + if (vm->pa_bits < 40) 1469 + return max_gfn; 1470 + 1471 + /* Before family 17h, the HyperTransport area is just below 1T. */ 1472 + ht_gfn = (1 << 28) - num_ht_pages; 1473 + eax = 1; 1474 + cpuid(&eax, &ebx, &ecx, &edx); 1475 + if (x86_family(eax) < 0x17) 1476 + goto done; 1477 + 1478 + /* 1479 + * Otherwise it's at the top of the physical address space, possibly 1480 + * reduced due to SME by bits 11:6 of CPUID[0x8000001f].EBX. Use 1481 + * the old conservative value if MAXPHYADDR is not enumerated. 1482 + */ 1483 + eax = 0x80000000; 1484 + cpuid(&eax, &ebx, &ecx, &edx); 1485 + max_ext_leaf = eax; 1486 + if (max_ext_leaf < 0x80000008) 1487 + goto done; 1488 + 1489 + eax = 0x80000008; 1490 + cpuid(&eax, &ebx, &ecx, &edx); 1491 + max_pfn = (1ULL << ((eax & 0xff) - vm->page_shift)) - 1; 1492 + if (max_ext_leaf >= 0x8000001f) { 1493 + eax = 0x8000001f; 1494 + cpuid(&eax, &ebx, &ecx, &edx); 1495 + max_pfn >>= (ebx >> 6) & 0x3f; 1496 + } 1497 + 1498 + ht_gfn = max_pfn - num_ht_pages; 1499 + done: 1500 + return min(max_gfn, ht_gfn - 1); 1501 + }