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 <kraxel@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Message-Id: <20240222105407.75735-4-kraxel@redhat.com>
Cc: Michael Roth <michael.roth@amd.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Oliver Steffen <osteffen@redhat.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
[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"]
This commit is contained in:
Gerd Hoffmann 2024-02-22 11:54:07 +01:00 committed by mergify[bot]
parent 13fbc16556
commit adebfe121c

View File

@ -631,6 +631,7 @@ PlatformAddressWidthFromCpuid (
UINT32 RegEax, RegEbx, RegEcx, RegEdx, Max; UINT32 RegEax, RegEbx, RegEcx, RegEdx, Max;
UINT8 PhysBits; UINT8 PhysBits;
CHAR8 Signature[13]; CHAR8 Signature[13];
IA32_CR4 Cr4;
BOOLEAN Valid = FALSE; BOOLEAN Valid = FALSE;
BOOLEAN Page1GSupport = FALSE; BOOLEAN Page1GSupport = FALSE;
@ -670,31 +671,55 @@ PlatformAddressWidthFromCpuid (
} }
} }
Cr4.UintN = AsmReadCr4 ();
DEBUG (( DEBUG ((
DEBUG_INFO, 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__, __func__,
Signature, Signature,
PhysBits, PhysBits,
QemuQuirk ? "On" : "Off", QemuQuirk ? "On" : "Off",
Cr4.Bits.LA57 ? "On" : "Off",
Valid ? "Yes" : "No" Valid ? "Yes" : "No"
)); ));
if (Valid) { if (Valid) {
/*
* 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) { if (PhysBits > 46) {
/* /*
* Avoid 5-level paging altogether for now, which limits * Some older linux kernels apparently have problems handling
* PhysBits to 48. Also avoid using address bit 48, due to sign * phys-bits > 46 correctly, so use that instead of 47 as
* extension we can't identity-map these addresses (and lots of * limit.
* 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__)); DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 46 (4-level paging)\n", __func__));
PhysBits = 46; PhysBits = 46;
} }
}
if (!Page1GSupport && (PhysBits > 40)) { if (!Page1GSupport && (PhysBits > 40)) {
DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 40 (no 1G pages available)\n", __func__)); DEBUG ((DEBUG_INFO, "%a: limit PhysBits to 40 (no 1G pages available)\n", __func__));