Reviewed-by: Ray Ni <ray...@intel.com> > -----Original Message----- > From: Tan, Dun <dun....@intel.com> > Sent: Friday, March 24, 2023 2:00 PM > To: devel@edk2.groups.io > Cc: Dong, Eric <eric.d...@intel.com>; Ni, Ray <ray...@intel.com>; Kumar, > Rahul R <rahul.r.ku...@intel.com>; Gerd Hoffmann <kra...@redhat.com> > Subject: [Patch V5 20/22] UefiCpuPkg/CpuPageTableLib: Enable PAE paging > > Modify CpuPageTableLib code to enable PAE paging. > In PageTableMap() API: > When creating new PAE page table, after creating page table, > set all MustBeZero fields of 4 PDPTE to 0. The MustBeZero > fields are treated as RW and other attributes by the common > map logic. So they might be set to 1. > When updating exsiting PAE page table, the special steps are: > 1.Prepare 4K-aligned 32bytes memory in stack for 4 temp PDPTE. > 2.Copy original 4 PDPTE to the 4 temp PDPTE and set the RW, > UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. > 4.After updating the page table, set the MustBeZero fields of > 4 temp PDPTE to 0. > 5.Copy the temp PDPTE to original PDPTE. > > In PageTableParse() API, also create 4 temp PDPTE in stack. > Copy original 4 PDPTE to the 4 temp PDPTE. Then set the RW, > UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. Finally > use the address of temp PDPTE as the page table address. > > Signed-off-by: Dun Tan <dun....@intel.com> > Cc: Eric Dong <eric.d...@intel.com> > Cc: Ray Ni <ray...@intel.com> > Cc: Rahul Kumar <rahul1.ku...@intel.com> > Tested-by: Gerd Hoffmann <kra...@redhat.com> > Acked-by: Gerd Hoffmann <kra...@redhat.com> > --- > UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h | 2 ++ > UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c | 53 > ++++++++++++++++++++++++++++++++++++++++++++++++----- > UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c | 25 > +++++++++++++++++++++---- > 3 files changed, 71 insertions(+), 9 deletions(-) > > diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h > b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h > index 2c67ecb469..8c4d43be89 100644 > --- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h > +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h > @@ -20,6 +20,8 @@ > > #define REGION_LENGTH(l) LShiftU64 (1, (l) * 9 + 3) > > +#define MAX_PAE_PDPTE_NUM 4 > + > typedef enum { > Pte = 1, > Pde = 2, > diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c > b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c > index 2430f1b37c..7cdba0d77f 100644 > --- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c > +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c > @@ -671,15 +671,17 @@ PageTableMap ( > IA32_PAGE_LEVEL MaxLeafLevel; > IA32_MAP_ATTRIBUTE ParentAttribute; > BOOLEAN LocalIsModified; > + UINTN Index; > + IA32_PAGING_ENTRY *PagingEntry; > + UINT8 BufferInStack[SIZE_4KB - 1 + MAX_PAE_PDPTE_NUM * > sizeof (IA32_PAGING_ENTRY)]; > > if (Length == 0) { > return RETURN_SUCCESS; > } > > - if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || > (PagingMode >= PagingModeMax)) { > + if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) { > // > // 32bit paging is never supported. > - // PAE paging will be supported later. > // > return RETURN_UNSUPPORTED; > } > @@ -716,17 +718,32 @@ PageTableMap ( > > MaxLeafLevel = (IA32_PAGE_LEVEL)(UINT8)PagingMode; > MaxLevel = (IA32_PAGE_LEVEL)(UINT8)(PagingMode >> 8); > - MaxLinearAddress = LShiftU64 (1, 12 + MaxLevel * 9); > + MaxLinearAddress = (PagingMode == PagingPae) ? LShiftU64 (1, 32) : > LShiftU64 (1, 12 + MaxLevel * 9); > > if ((LinearAddress > MaxLinearAddress) || (Length > MaxLinearAddress - > LinearAddress)) { > // > - // Maximum linear address is (1 << 48) or (1 << 57) > + // Maximum linear address is (1 << 32), (1 << 48) or (1 << 57) > // > return RETURN_INVALID_PARAMETER; > } > > TopPagingEntry.Uintn = *PageTable; > if (TopPagingEntry.Uintn != 0) { > + if (PagingMode == PagingPae) { > + // > + // Create 4 temporary PDPTE at a 4k-aligned address. > + // Copy the original PDPTE content and set ReadWrite, UserSupervisor to > 1, set Nx to 0. > + // > + TopPagingEntry.Uintn = ALIGN_VALUE ((UINTN)BufferInStack, > BASE_4KB); > + PagingEntry = (IA32_PAGING_ENTRY *)(TopPagingEntry.Uintn); > + CopyMem (PagingEntry, (VOID *)(*PageTable), MAX_PAE_PDPTE_NUM > * sizeof (IA32_PAGING_ENTRY)); > + for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) { > + PagingEntry[Index].Pnle.Bits.ReadWrite = 1; > + PagingEntry[Index].Pnle.Bits.UserSupervisor = 1; > + PagingEntry[Index].Pnle.Bits.Nx = 0; > + } > + } > + > TopPagingEntry.Pce.Present = 1; > TopPagingEntry.Pce.ReadWrite = 1; > TopPagingEntry.Pce.UserSupervisor = 1; > @@ -801,7 +818,33 @@ PageTableMap ( > ); > > if (!RETURN_ERROR (Status)) { > - *PageTable = (UINTN)(TopPagingEntry.Uintn & > IA32_PE_BASE_ADDRESS_MASK_40); > + PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)(TopPagingEntry.Uintn & > IA32_PE_BASE_ADDRESS_MASK_40); > + > + if (PagingMode == PagingPae) { > + // > + // These MustBeZero fields are treated as RW and other attributes by > the common map logic. So they might be set to 1. > + // > + for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) { > + PagingEntry[Index].PdptePae.Bits.MustBeZero = 0; > + PagingEntry[Index].PdptePae.Bits.MustBeZero2 = 0; > + PagingEntry[Index].PdptePae.Bits.MustBeZero3 = 0; > + } > + > + if (*PageTable != 0) { > + // > + // Copy temp PDPTE to original PDPTE. > + // > + CopyMem ((VOID *)(*PageTable), PagingEntry, > MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY)); > + } > + } > + > + if (*PageTable == 0) { > + // > + // Do not assign the *PageTable when it's an existing page table. > + // If it's an existing PAE page table, PagingEntry is the temp buffer > in > stack. > + // > + *PageTable = (UINTN)PagingEntry; > + } > } > > return Status; > diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c > b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c > index 65490751ab..f6d7b9bb4c 100644 > --- a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c > +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c > @@ -158,6 +158,7 @@ VOID > PageTableLibParsePnle ( > IN UINT64 PageTableBaseAddress, > IN UINTN Level, > + IN UINTN MaxLevel, > IN UINT64 RegionStart, > IN IA32_MAP_ATTRIBUTE *ParentMapAttribute, > IN OUT IA32_MAP_ENTRY *Map, > @@ -171,13 +172,15 @@ PageTableLibParsePnle ( > UINTN Index; > IA32_MAP_ATTRIBUTE MapAttribute; > UINT64 RegionLength; > + UINTN PagingEntryNumber; > > ASSERT (OneEntry != NULL); > > - PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress; > - RegionLength = REGION_LENGTH (Level); > + PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress; > + RegionLength = REGION_LENGTH (Level); > + PagingEntryNumber = ((MaxLevel == 3) && (Level == 3)) ? > MAX_PAE_PDPTE_NUM : 512; > > - for (Index = 0; Index < 512; Index++, RegionStart += RegionLength) { > + for (Index = 0; Index < PagingEntryNumber; Index++, RegionStart += > RegionLength) { > if (PagingEntry[Index].Pce.Present == 0) { > continue; > } > @@ -228,6 +231,7 @@ PageTableLibParsePnle ( > PageTableLibParsePnle ( > IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle), > Level - 1, > + MaxLevel, > RegionStart, > &MapAttribute, > Map, > @@ -269,6 +273,8 @@ PageTableParse ( > IA32_MAP_ENTRY *LastEntry; > IA32_MAP_ENTRY OneEntry; > UINTN MaxLevel; > + UINTN Index; > + IA32_PAGING_ENTRY BufferInStack[MAX_PAE_PDPTE_NUM]; > > if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) { > // > @@ -290,6 +296,17 @@ PageTableParse ( > return RETURN_SUCCESS; > } > > + if (PagingMode == PagingPae) { > + CopyMem (BufferInStack, (VOID *)PageTable, sizeof (BufferInStack)); > + for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) { > + BufferInStack[Index].Pnle.Bits.ReadWrite = 1; > + BufferInStack[Index].Pnle.Bits.UserSupervisor = 1; > + BufferInStack[Index].Pnle.Bits.Nx = 0; > + } > + > + PageTable = (UINTN)BufferInStack; > + } > + > // > // Page table layout is as below: > // > @@ -319,7 +336,7 @@ PageTableParse ( > MapCapacity = *MapCount; > *MapCount = 0; > LastEntry = NULL; > - PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, 0, &NopAttribute, > Map, MapCount, MapCapacity, &LastEntry, &OneEntry); > + PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, MaxLevel, 0, > &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry); > > if (*MapCount > MapCapacity) { > return RETURN_BUFFER_TOO_SMALL; > -- > 2.31.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#101756): https://edk2.groups.io/g/devel/message/101756 Mute This Topic: https://groups.io/mt/97818243/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/9847357/21656/1706620634/xyzzy [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-