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]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to