From 49b7faba1d6e29bd6238d6b85de22b2c3fca4d12 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Mar 2024 08:43:58 +0100 Subject: OvmfPkg/ResetVector: add 5-level paging support Add macros to check for 5-level paging and gigabyte page support. Enable 5-level paging for the non-confidential-computing case. Signed-off-by: Gerd Hoffmann Message-Id: <20240301074402.98625-7-kraxel@redhat.com> Reviewed-by: Laszlo Ersek Cc: Jiewen Yao Cc: Oliver Steffen Cc: Michael Roth Cc: Erdem Aktas Cc: Min Xu Cc: Ard Biesheuvel Cc: Tom Lendacky [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/ResetVector/Ia32/PageTables64.asm | 100 ++++++++++++++++++++++++++++++ OvmfPkg/ResetVector/ResetVector.inf | 1 + OvmfPkg/ResetVector/ResetVector.nasmb | 1 + 3 files changed, 102 insertions(+) diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm index 84a7b4efc0..2d7fd523e4 100644 --- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm +++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm @@ -101,6 +101,97 @@ BITS 32 loop .pageTableEntriesLoop4Level %endmacro +; +; Check whenever 5-level paging can be used +; +; Argument: jump label for 4-level paging +; +%macro Check5LevelPaging 1 + ; check for cpuid leaf 0x07 + mov eax, 0x00 + cpuid + cmp eax, 0x07 + jb %1 + + ; check for la57 (aka 5-level paging) + mov eax, 0x07 + mov ecx, 0x00 + cpuid + bt ecx, 16 + jnc %1 + + ; check for cpuid leaf 0x80000001 + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000001 + jb %1 + + ; check for 1g pages + mov eax, 0x80000001 + cpuid + bt edx, 26 + jnc %1 +%endmacro + +; +; Create page tables for 5-level paging with gigabyte pages +; +; Argument: upper 32 bits of the page table entries +; +; We have 6 pages available for the early page tables, +; we use four of them: +; PT_ADDR(0) - level 5 directory +; PT_ADDR(0x1000) - level 4 directory +; PT_ADDR(0x2000) - level 2 directory (0 -> 1GB) +; PT_ADDR(0x3000) - level 3 directory +; +; The level 2 directory for the first gigabyte has the same +; physical address in both 4-level and 5-level paging mode, +; SevClearPageEncMaskForGhcbPage depends on this. +; +; The 1 GB -> 4 GB range is mapped using 1G pages in the +; level 3 directory. +; +%macro CreatePageTables5Level 1 + ; level 5 + mov dword[PT_ADDR (0)], PT_ADDR (0x1000) + PAGE_PDE_DIRECTORY_ATTR + mov dword[PT_ADDR (4)], %1 + + ; level 4 + mov dword[PT_ADDR (0x1000)], PT_ADDR (0x3000) + PAGE_PDE_DIRECTORY_ATTR + mov dword[PT_ADDR (0x1004)], %1 + + ; level 3 (1x -> level 2, 3x 1GB) + mov dword[PT_ADDR (0x3000)], PT_ADDR (0x2000) + PAGE_PDE_DIRECTORY_ATTR + mov dword[PT_ADDR (0x3004)], %1 + mov dword[PT_ADDR (0x3008)], (1 << 30) + PAGE_PDE_LARGEPAGE_ATTR + mov dword[PT_ADDR (0x300c)], %1 + mov dword[PT_ADDR (0x3010)], (2 << 30) + PAGE_PDE_LARGEPAGE_ATTR + mov dword[PT_ADDR (0x3014)], %1 + mov dword[PT_ADDR (0x3018)], (3 << 30) + PAGE_PDE_LARGEPAGE_ATTR + mov dword[PT_ADDR (0x301c)], %1 + + ; + ; level 2 (512 * 2MB entries => 1GB) + ; + mov ecx, 0x200 +.pageTableEntriesLoop5Level: + mov eax, ecx + dec eax + shl eax, 21 + add eax, PAGE_PDE_LARGEPAGE_ATTR + mov dword[ecx * 8 + PT_ADDR (0x2000 - 8)], eax + mov dword[(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], %1 + loop .pageTableEntriesLoop5Level +%endmacro + +%macro Enable5LevelPaging 0 + ; set la57 bit in cr4 + mov eax, cr4 + bts eax, 12 + mov cr4, eax +%endmacro + ; ; Modified: EAX, EBX, ECX, EDX ; @@ -125,6 +216,13 @@ SetCr3ForPageTables64: ; normal (non-CoCo) workflow ; ClearOvmfPageTables +%if PG_5_LEVEL + Check5LevelPaging Paging4Level + CreatePageTables5Level 0 + Enable5LevelPaging + jmp SetCr3 +Paging4Level: +%endif CreatePageTables4Level 0 jmp SetCr3 @@ -152,6 +250,8 @@ TdxBspInit: jmp SetCr3 SetCr3: + ; + ; common workflow ; ; Set CR3 now that the paging structures are available ; diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf index a4154ca90c..65f71b05a0 100644 --- a/OvmfPkg/ResetVector/ResetVector.inf +++ b/OvmfPkg/ResetVector/ResetVector.inf @@ -64,3 +64,4 @@ gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableSize gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize + gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb index 366a70fb99..2bd80149e5 100644 --- a/OvmfPkg/ResetVector/ResetVector.nasmb +++ b/OvmfPkg/ResetVector/ResetVector.nasmb @@ -53,6 +53,7 @@ %define WORK_AREA_GUEST_TYPE (FixedPcdGet32 (PcdOvmfWorkAreaBase)) %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset)) +%define PG_5_LEVEL (FixedPcdGetBool (PcdUse5LevelPageTable)) %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)) %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase)) -- cgit v1.2.3