Reviewed-by: Ray Ni <ray...@intel.com>

Thanks,
Ray
> -----Original Message-----
> From: Liu, Zhiguang <zhiguang....@intel.com>
> Sent: Thursday, November 30, 2023 2:29 PM
> To: devel@edk2.groups.io
> Cc: Liu, Zhiguang <zhiguang....@intel.com>; Ni, Ray <ray...@intel.com>;
> Kumar, Rahul R <rahul.r.ku...@intel.com>; Gerd Hoffmann
> <kra...@redhat.com>; Laszlo Ersek <ler...@redhat.com>
> Subject: [PATCH v2 3/3] UefiCpuPkg/CpuMpPei: Use CpuPageTableLib to set
> memory attribute.
> 
> Currently, there are code to set memory attribute in CpuMpPei module.
> However, the code doesn't handle the case of 5 level paging.
> Use the CpuPageTableLib to set memory attribute for two purpose:
> 1. Add 5 level paging support
> 2. Clean up code
> 
> Cc: Ray Ni <ray...@intel.com>
> Cc: Rahul Kumar <rahul1.ku...@intel.com>
> Cc: Gerd Hoffmann <kra...@redhat.com>
> Cc: Laszlo Ersek <ler...@redhat.com>
> Signed-off-by: Zhiguang Liu <zhiguang....@intel.com>
> ---
>  UefiCpuPkg/CpuMpPei/CpuPaging.c | 317 +++++++-------------------------
>  1 file changed, 69 insertions(+), 248 deletions(-)
> 
> diff --git a/UefiCpuPkg/CpuMpPei/CpuPaging.c
> b/UefiCpuPkg/CpuMpPei/CpuPaging.c
> index b7ddb0005b..2dd7237141 100644
> --- a/UefiCpuPkg/CpuMpPei/CpuPaging.c
> +++ b/UefiCpuPkg/CpuMpPei/CpuPaging.c
> @@ -15,50 +15,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  #include <Guid/MigratedFvInfo.h>
> 
>  #include "CpuMpPei.h"
> -
> -#define IA32_PG_P   BIT0
> -#define IA32_PG_RW  BIT1
> -#define IA32_PG_U   BIT2
> -#define IA32_PG_A   BIT5
> -#define IA32_PG_D   BIT6
> -#define IA32_PG_PS  BIT7
> -#define IA32_PG_NX  BIT63
> -
> -#define PAGE_ATTRIBUTE_BITS  (IA32_PG_RW | IA32_PG_P)
> -#define PAGE_PROGATE_BITS    (IA32_PG_D | IA32_PG_A | IA32_PG_NX |
> IA32_PG_U | \
> -                               PAGE_ATTRIBUTE_BITS)
> -
> -#define PAGING_PAE_INDEX_MASK        0x1FF
> -#define PAGING_4K_ADDRESS_MASK_64    0x000FFFFFFFFFF000ull
> -#define PAGING_2M_ADDRESS_MASK_64    0x000FFFFFFFE00000ull
> -#define PAGING_1G_ADDRESS_MASK_64    0x000FFFFFC0000000ull
> -#define PAGING_512G_ADDRESS_MASK_64  0x000FFF8000000000ull
> -
> -typedef enum {
> -  PageNone = 0,
> -  PageMin  = 1,
> -  Page4K   = PageMin,
> -  Page2M   = 2,
> -  Page1G   = 3,
> -  Page512G = 4,
> -  PageMax  = Page512G
> -} PAGE_ATTRIBUTE;
> -
> -typedef struct {
> -  PAGE_ATTRIBUTE    Attribute;
> -  UINT64            Length;
> -  UINT64            AddressMask;
> -  UINTN             AddressBitOffset;
> -  UINTN             AddressBitLength;
> -} PAGE_ATTRIBUTE_TABLE;
> -
> -PAGE_ATTRIBUTE_TABLE  mPageAttributeTable[] = {
> -  { PageNone, 0,          0,                           0,  0 },
> -  { Page4K,   SIZE_4KB,   PAGING_4K_ADDRESS_MASK_64,   12, 9 },
> -  { Page2M,   SIZE_2MB,   PAGING_2M_ADDRESS_MASK_64,   21, 9 },
> -  { Page1G,   SIZE_1GB,   PAGING_1G_ADDRESS_MASK_64,   30, 9 },
> -  { Page512G, SIZE_512GB, PAGING_512G_ADDRESS_MASK_64, 39, 9 },
> -};
> +#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull
> 
>  EFI_PEI_NOTIFY_DESCRIPTOR  mPostMemNotifyList[] = {
>    {
> @@ -117,237 +74,101 @@ AllocatePageTableMemory (
>    return Address;
>  }
> 
> -/**
> -  Get the type of top level page table.
> -
> -  @retval Page512G  PML4 paging.
> -  @retval Page1G    PAE paging.
> -
> -**/
> -PAGE_ATTRIBUTE
> -GetPageTableTopLevelType (
> -  VOID
> -  )
> -{
> -  MSR_IA32_EFER_REGISTER  MsrEfer;
> -
> -  MsrEfer.Uint64 = AsmReadMsr64 (MSR_CORE_IA32_EFER);
> -
> -  return (MsrEfer.Bits.LMA == 1) ? Page512G : Page1G;
> -}
> -
> -/**
> -  Return page table entry matching the address.
> -
> -  @param[in]   Address          The address to be checked.
> -  @param[out]  PageAttributes   The page attribute of the page entry.
> -
> -  @return The page entry.
> -**/
> -VOID *
> -GetPageTableEntry (
> -  IN  PHYSICAL_ADDRESS  Address,
> -  OUT PAGE_ATTRIBUTE    *PageAttribute
> -  )
> -{
> -  INTN    Level;
> -  UINTN   Index;
> -  UINT64  *PageTable;
> -  UINT64  AddressEncMask;
> -
> -  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask);
> -  PageTable      = (UINT64 *)(UINTN)(AsmReadCr3 () &
> PAGING_4K_ADDRESS_MASK_64);
> -  for (Level = (INTN)GetPageTableTopLevelType (); Level > 0; --Level) {
> -    Index  = (UINTN)RShiftU64 (Address,
> mPageAttributeTable[Level].AddressBitOffset);
> -    Index &= PAGING_PAE_INDEX_MASK;
> -
> -    //
> -    // No mapping?
> -    //
> -    if (PageTable[Index] == 0) {
> -      *PageAttribute = PageNone;
> -      return NULL;
> -    }
> -
> -    //
> -    // Page memory?
> -    //
> -    if (((PageTable[Index] & IA32_PG_PS) != 0) || (Level == PageMin)) {
> -      *PageAttribute = (PAGE_ATTRIBUTE)Level;
> -      return &PageTable[Index];
> -    }
> -
> -    //
> -    // Page directory or table
> -    //
> -    PageTable = (UINT64 *)(UINTN)(PageTable[Index] &
> -                                  ~AddressEncMask &
> -                                  PAGING_4K_ADDRESS_MASK_64);
> -  }
> -
> -  *PageAttribute = PageNone;
> -  return NULL;
> -}
> -
> -/**
> -  This function splits one page entry to smaller page entries.
> -
> -  @param[in]  PageEntry        The page entry to be splitted.
> -  @param[in]  PageAttribute    The page attribute of the page entry.
> -  @param[in]  SplitAttribute   How to split the page entry.
> -  @param[in]  Recursively      Do the split recursively or not.
> -
> -  @retval RETURN_SUCCESS            The page entry is splitted.
> -  @retval RETURN_INVALID_PARAMETER  If target page attribute is invalid
> -  @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.
> -**/
> -RETURN_STATUS
> -SplitPage (
> -  IN  UINT64          *PageEntry,
> -  IN  PAGE_ATTRIBUTE  PageAttribute,
> -  IN  PAGE_ATTRIBUTE  SplitAttribute,
> -  IN  BOOLEAN         Recursively
> -  )
> -{
> -  UINT64          BaseAddress;
> -  UINT64          *NewPageEntry;
> -  UINTN           Index;
> -  UINT64          AddressEncMask;
> -  PAGE_ATTRIBUTE  SplitTo;
> -
> -  if ((SplitAttribute == PageNone) || (SplitAttribute >= PageAttribute)) {
> -    ASSERT (SplitAttribute != PageNone);
> -    ASSERT (SplitAttribute < PageAttribute);
> -    return RETURN_INVALID_PARAMETER;
> -  }
> -
> -  NewPageEntry = AllocatePageTableMemory (1);
> -  if (NewPageEntry == NULL) {
> -    ASSERT (NewPageEntry != NULL);
> -    return RETURN_OUT_OF_RESOURCES;
> -  }
> -
> -  //
> -  // One level down each step to achieve more compact page table.
> -  //
> -  SplitTo        = PageAttribute - 1;
> -  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
> -                   mPageAttributeTable[SplitTo].AddressMask;
> -  BaseAddress = *PageEntry &
> -                ~PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
> -                mPageAttributeTable[PageAttribute].AddressMask;
> -  for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {
> -    NewPageEntry[Index] = BaseAddress | AddressEncMask |
> -                          ((*PageEntry) & PAGE_PROGATE_BITS);
> -
> -    if (SplitTo != PageMin) {
> -      NewPageEntry[Index] |= IA32_PG_PS;
> -    }
> -
> -    if (Recursively && (SplitTo > SplitAttribute)) {
> -      SplitPage (&NewPageEntry[Index], SplitTo, SplitAttribute, Recursively);
> -    }
> -
> -    BaseAddress += mPageAttributeTable[SplitTo].Length;
> -  }
> -
> -  (*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask |
> PAGE_ATTRIBUTE_BITS;
> -
> -  return RETURN_SUCCESS;
> -}
> -
>  /**
>    This function modifies the page attributes for the memory region specified
> -  by BaseAddress and Length from their current attributes to the attributes
> -  specified by Attributes.
> +  by BaseAddress and Length to not present.
> 
>    Caller should make sure BaseAddress and Length is at page boundary.
> 
>    @param[in]   BaseAddress      Start address of a memory region.
>    @param[in]   Length           Size in bytes of the memory region.
> -  @param[in]   Attributes       Bit mask of attributes to modify.
> -
> -  @retval RETURN_SUCCESS            The attributes were modified for the
> memory
> -                                    region.
> -  @retval RETURN_INVALID_PARAMETER  Length is zero; or,
> -                                    Attributes specified an illegal 
> combination
> -                                    of attributes that cannot be set 
> together; or
> -                                    Addressis not 4KB aligned.
> +
> +  @retval RETURN_SUCCESS            The memory region is changed to not
> present.
>    @retval RETURN_OUT_OF_RESOURCES   There are not enough system
> resources to modify
>                                      the attributes.
>    @retval RETURN_UNSUPPORTED        Cannot modify the attributes of given
> memory.
> 
>  **/
>  RETURN_STATUS
> -EFIAPI
> -ConvertMemoryPageAttributes (
> +ConvertMemoryPageToNotPresent (
>    IN  PHYSICAL_ADDRESS  BaseAddress,
> -  IN  UINT64            Length,
> -  IN  UINT64            Attributes
> +  IN  UINT64            Length
>    )
>  {
> -  UINT64                *PageEntry;
> -  PAGE_ATTRIBUTE        PageAttribute;
> -  RETURN_STATUS         Status;
> -  EFI_PHYSICAL_ADDRESS  MaximumAddress;
> -
> -  if ((Length == 0) ||
> -      ((BaseAddress & (SIZE_4KB - 1)) != 0) ||
> -      ((Length & (SIZE_4KB - 1)) != 0))
> -  {
> -    ASSERT (Length > 0);
> -    ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
> -    ASSERT ((Length & (SIZE_4KB - 1)) == 0);
> -
> -    return RETURN_INVALID_PARAMETER;
> -  }
> -
> -  MaximumAddress = (EFI_PHYSICAL_ADDRESS)MAX_UINT32;
> -  if ((BaseAddress > MaximumAddress) ||
> -      (Length > MaximumAddress) ||
> -      (BaseAddress > MaximumAddress - (Length - 1)))
> -  {
> -    return RETURN_UNSUPPORTED;
> -  }
> -
> -  //
> -  // Below logic is to check 2M/4K page to make sure we do not waste
> memory.
> -  //
> -  while (Length != 0) {
> -    PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
> -    if (PageEntry == NULL) {
> -      return RETURN_UNSUPPORTED;
> -    }
> +  EFI_STATUS                  Status;
> +  UINTN                       PageTable;
> +  EFI_PHYSICAL_ADDRESS        Buffer;
> +  UINTN                       BufferSize;
> +  IA32_MAP_ATTRIBUTE          MapAttribute;
> +  IA32_MAP_ATTRIBUTE          MapMask;
> +  PAGING_MODE                 PagingMode;
> +  IA32_CR4                    Cr4;
> +  BOOLEAN                     Page5LevelSupport;
> +  UINT32                      RegEax;
> +  BOOLEAN                     Page1GSupport;
> +  CPUID_EXTENDED_CPU_SIG_EDX  RegEdx;
> +
> +  if (sizeof (UINTN) == sizeof (UINT64)) {
> +    //
> +    // Check Page5Level Support or not.
> +    //
> +    Cr4.UintN         = AsmReadCr4 ();
> +    Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
> 
> -    if (PageAttribute != Page4K) {
> -      Status = SplitPage (PageEntry, PageAttribute, Page4K, FALSE);
> -      if (RETURN_ERROR (Status)) {
> -        return Status;
> +    //
> +    // Check Page1G Support or not.
> +    //
> +    Page1GSupport = FALSE;
> +    AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
> +      AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL,
> &RegEdx.Uint32);
> +      if (RegEdx.Bits.Page1GB != 0) {
> +        Page1GSupport = TRUE;
>        }
> -
> -      //
> -      // Do it again until the page is 4K.
> -      //
> -      continue;
>      }
> 
>      //
> -    // Just take care of 'present' bit for Stack Guard.
> +    // Decide Paging Mode according Page5LevelSupport & Page1GSupport.
>      //
> -    if ((Attributes & IA32_PG_P) != 0) {
> -      *PageEntry |= (UINT64)IA32_PG_P;
> +    if (Page5LevelSupport) {
> +      PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level;
>      } else {
> -      *PageEntry &= ~((UINT64)IA32_PG_P);
> +      PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level;
>      }
> +  } else {
> +    PagingMode = PagingPae;
> +  }
> +
> +  MapAttribute.Uint64  = 0;
> +  MapMask.Uint64       = 0;
> +  MapMask.Bits.Present = 1;
> +  PageTable            = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
> +  BufferSize           = 0;
> 
> +  //
> +  // Get required buffer size for the pagetable that will be created.
> +  //
> +  Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize,
> BaseAddress, Length, &MapAttribute, &MapMask, NULL);
> +  if (Status == EFI_BUFFER_TOO_SMALL) {
>      //
> -    // Convert success, move to next
> +    // Allocate required Buffer.
>      //
> -    BaseAddress += SIZE_4KB;
> -    Length      -= SIZE_4KB;
> +    Status = PeiServicesAllocatePages (
> +               EfiBootServicesData,
> +               EFI_SIZE_TO_PAGES (BufferSize),
> +               &Buffer
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer,
> &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL);
>    }
> 
> -  return RETURN_SUCCESS;
> +  ASSERT_EFI_ERROR (Status);
> +  AsmWriteCr3 (PageTable);
> +  return Status;
>  }
> 
>  /**
> @@ -516,7 +337,7 @@ SetupStackGuardPage (
>      //
>      // Set Guard page at stack base address.
>      //
> -    ConvertMemoryPageAttributes (StackBase, EFI_PAGE_SIZE, 0);
> +    ConvertMemoryPageToNotPresent (StackBase, EFI_PAGE_SIZE);
>      DEBUG ((
>        DEBUG_INFO,
>        "Stack Guard set at %lx [cpu%lu]!\n",
> @@ -599,7 +420,7 @@ MemoryDiscoveredPpiNotifyCallback (
>      // Enable #PF exception, so if the code access SPI after disable NEM, it 
> will
> generate
>      // the exception to avoid potential vulnerability.
>      //
> -    ConvertMemoryPageAttributes (MigratedFvInfo->FvOrgBase,
> MigratedFvInfo->FvLength, 0);
> +    ConvertMemoryPageToNotPresent (MigratedFvInfo->FvOrgBase,
> MigratedFvInfo->FvLength);
> 
>      Hob.Raw = GET_NEXT_HOB (Hob);
>      Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);
> --
> 2.31.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111979): https://edk2.groups.io/g/devel/message/111979
Mute This Topic: https://groups.io/mt/102889280/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