Skip to content

Commit c8cc43c

Browse files
committed
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: ef4c9f4 ("KVM: selftests: Fix 32-bit truncation of vm_get_max_gfn()") Cc: [email protected] Cc: David Matlack <[email protected]> Reported-by: Maxim Levitsky <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Message-Id: <[email protected]> Reviewed-by: Sean Christopherson <[email protected]> Tested-by: Sean Christopherson <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 3244867 commit c8cc43c

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

tools/testing/selftests/kvm/include/kvm_util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ enum vm_guest_mode {
7171

7272
#endif
7373

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+
7483
#define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
7584
#define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE)
7685

tools/testing/selftests/kvm/lib/kvm_util.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm)
302302
(1ULL << (vm->va_bits - 1)) >> vm->page_shift);
303303

304304
/* Limit physical addresses to PA-bits. */
305-
vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
305+
vm->max_gfn = vm_compute_max_gfn(vm);
306306

307307
/* Allocate and setup memory for guest. */
308308
vm->vpages_mapped = sparsebit_alloc();

tools/testing/selftests/kvm/lib/x86_64/processor.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,3 +1431,71 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpui
14311431

14321432
return cpuid;
14331433
}
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+
}

0 commit comments

Comments
 (0)