From adebfe121ca02a3a9c610389929d5e158334a4ea Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 22 Feb 2024 11:54:07 +0100 Subject: OvmfPkg/PlatformInitLib: add 5-level paging support Adjust physical address space logic for la57 mode (5-level paging). With a larger logical address space we can identity-map a larger physical address space. Signed-off-by: Gerd Hoffmann Reviewed-by: Laszlo Ersek Acked-by: Ard Biesheuvel Message-Id: <20240222105407.75735-4-kraxel@redhat.com> Cc: Michael Roth Cc: Jiewen Yao Cc: Liming Gao Cc: Laszlo Ersek Cc: Tom Lendacky Cc: Paolo Bonzini Cc: Ard Biesheuvel Cc: Gerd Hoffmann Cc: Min Xu Cc: Erdem Aktas Cc: Oliver Steffen Cc: Ard Biesheuvel [lersek@redhat.com: turn the "Cc:" message headers from Gerd's on-list posting into "Cc:" tags in the commit message, in order to pacify "PatchCheck.py"] --- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 63 ++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c index f042517bb6..7b6e5102ad 100644 --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c @@ -628,11 +628,12 @@ PlatformAddressWidthFromCpuid ( IN BOOLEAN QemuQuirk ) { - UINT32 RegEax, RegEbx, RegEcx, RegEdx, Max; - UINT8 PhysBits; - CHAR8 Signature[13]; - BOOLEAN Valid = FALSE; - BOOLEAN Page1GSupport = FALSE; + UINT32 RegEax, RegEbx, RegEcx, RegEdx, Max; + UINT8 PhysBits; + CHAR8 Signature[13]; + IA32_CR4 Cr4; + BOOLEAN Valid = FALSE; + BOOLEAN Page1GSupport = FALSE; ZeroMem (Signature, sizeof (Signature)); @@ -670,30 +671,54 @@ PlatformAddressWidthFromCpuid ( } } + Cr4.UintN = AsmReadCr4 (); + DEBUG (( DEBUG_INFO, - "%a: Signature: '%a', PhysBits: %d, QemuQuirk: %a, Valid: %a\n", + "%a: Signature: '%a', PhysBits: %d, QemuQuirk: %a, la57: %a, Valid: %a\n", __func__, Signature, PhysBits, QemuQuirk ? "On" : "Off", + Cr4.Bits.LA57 ? "On" : "Off", Valid ? "Yes" : "No" )); if (Valid) { - if (PhysBits > 46) { - /* - * Avoid 5-level paging altogether for now, which limits - * PhysBits to 48. Also avoid using address bit 48, due to sign - * extension we can't identity-map these addresses (and lots of - * places in edk2 assume we have everything identity-mapped). - * So the actual limit is 47. - * - * Also some older linux kernels apparently have problems handling - * phys-bits > 46 correctly, so use that as limit. - */ - DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 46 (avoid 5-level paging)\n", __func__)); - PhysBits = 46; + /* + * Due to the sign extension we can use only the lower half of the + * virtual address space to identity-map physical address space, + * which gives us a 47 bit wide address space with 4 paging levels + * and a 56 bit wide address space with 5 paging levels. + */ + if (Cr4.Bits.LA57) { + if (PhysBits > 48) { + /* + * Some Intel CPUs support 5-level paging, have more than 48 + * phys-bits but support only 4-level EPT, which effectively + * limits guest phys-bits to 48. + * + * AMD Processors have a different but somewhat related + * problem: They can handle guest phys-bits larger than 48 + * only in case the host runs in 5-level paging mode. + * + * Until we have some way to communicate that kind of + * limitations from hypervisor to guest, limit phys-bits + * to 48 unconditionally. + */ + DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 48 (5-level paging)\n", __func__)); + PhysBits = 48; + } + } else { + if (PhysBits > 46) { + /* + * Some older linux kernels apparently have problems handling + * phys-bits > 46 correctly, so use that instead of 47 as + * limit. + */ + DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 46 (4-level paging)\n", __func__)); + PhysBits = 46; + } } if (!Page1GSupport && (PhysBits > 40)) { -- cgit v1.2.3