From: "Ni, Ray" <ray.ni@intel.com>
To: "Liu, Zhiguang" <zhiguang.liu@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Kumar, Rahul R" <rahul.r.kumar@intel.com>,
Gerd Hoffmann <kraxel@redhat.com>,
Laszlo Ersek <lersek@redhat.com>
Subject: Re: [edk2-devel] [PATCH v2 3/3] UefiCpuPkg/CpuMpPei: Use CpuPageTableLib to set memory attribute.
Date: Fri, 1 Dec 2023 08:42:28 +0000 [thread overview]
Message-ID: <MN6PR11MB8244AF6B7F049E34572CF8C88C81A@MN6PR11MB8244.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20231130062909.2003-3-zhiguang.liu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Thanks,
Ray
> -----Original Message-----
> From: Liu, Zhiguang <zhiguang.liu@intel.com>
> Sent: Thursday, November 30, 2023 2:29 PM
> To: devel@edk2.groups.io
> Cc: Liu, Zhiguang <zhiguang.liu@intel.com>; Ni, Ray <ray.ni@intel.com>;
> Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann
> <kraxel@redhat.com>; Laszlo Ersek <lersek@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.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Zhiguang Liu <zhiguang.liu@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/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
next prev parent reply other threads:[~2023-12-01 8:42 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-30 6:29 [edk2-devel] [PATCH v2 1/3] UefiCpuPkg/CpuPageTableLib: Init local variable before using it Zhiguang Liu
2023-11-30 6:29 ` [edk2-devel] [PATCH v2 2/3] UefiCpuPkg/CpuPageTableLib/TestCase: Refine test case for PAE paging Zhiguang Liu
2023-12-01 8:41 ` Ni, Ray
2023-11-30 6:29 ` [edk2-devel] [PATCH v2 3/3] UefiCpuPkg/CpuMpPei: Use CpuPageTableLib to set memory attribute Zhiguang Liu
2023-12-01 8:42 ` Ni, Ray [this message]
2023-12-12 0:35 ` Laszlo Ersek
2023-12-01 8:40 ` [edk2-devel] [PATCH v2 1/3] UefiCpuPkg/CpuPageTableLib: Init local variable before using it Ni, Ray
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=MN6PR11MB8244AF6B7F049E34572CF8C88C81A@MN6PR11MB8244.namprd11.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox