summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2024-02-22 11:54:07 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-02-29 09:56:38 +0000
commitadebfe121ca02a3a9c610389929d5e158334a4ea (patch)
tree705520fa05dbf2db21e6b093d63decc00f19ad3d
parent13fbc16556d05a70d1bbef2e673f1b16b22dd6c6 (diff)
downloadedk2-adebfe121ca02a3a9c610389929d5e158334a4ea.tar.gz
edk2-adebfe121ca02a3a9c610389929d5e158334a4ea.tar.bz2
edk2-adebfe121ca02a3a9c610389929d5e158334a4ea.zip
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"]
-rw-r--r--OvmfPkg/Library/PlatformInitLib/MemDetect.c63
1 files 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)) {