From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B9A298203C for ; Sun, 5 Feb 2017 21:26:32 -0800 (PST) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP; 05 Feb 2017 21:26:32 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,340,1477983600"; d="scan'208";a="221727454" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by fmsmga004.fm.intel.com with ESMTP; 05 Feb 2017 21:26:32 -0800 Received: from fmsmsx152.amr.corp.intel.com (10.18.125.5) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.248.2; Sun, 5 Feb 2017 21:26:31 -0800 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by FMSMSX152.amr.corp.intel.com (10.18.125.5) with Microsoft SMTP Server (TLS) id 14.3.248.2; Sun, 5 Feb 2017 21:26:31 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.88]) by SHSMSX103.ccr.corp.intel.com ([10.239.4.69]) with mapi id 14.03.0248.002; Mon, 6 Feb 2017 13:26:29 +0800 From: "Fan, Jeff" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: "Kinney, Michael D" Thread-Topic: [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. Thread-Index: AQHSd6/j/6Foat7yGk+wjE8Y65esT6FbXXnQ//+HqoCAAJ3LsA== Date: Mon, 6 Feb 2017 05:26:28 +0000 Message-ID: <542CF652F8836A4AB8DBFAAD40ED192A4C52BF57@shsmsx102.ccr.corp.intel.com> References: <1485419955-26652-1-git-send-email-jiewen.yao@intel.com> <1485419955-26652-2-git-send-email-jiewen.yao@intel.com> <542CF652F8836A4AB8DBFAAD40ED192A4C52BE02@shsmsx102.ccr.corp.intel.com> <74D8A39837DF1E4DA445A8C0B3885C503A8E958F@shsmsx102.ccr.corp.intel.com> In-Reply-To: <74D8A39837DF1E4DA445A8C0B3885C503A8E958F@shsmsx102.ccr.corp.intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiMjY0NjA4ZjctOTI2NC00NmYxLTgzYWEtZjE5YTRjMGExNTRiIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6IkJiWFBsTjQyb1wvbUR2ajdMWFJYdFJaN3ZXbm9abmxrSnB2YVRRRmN3NG1RPSJ9 x-ctpclassification: CTP_IC x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 06 Feb 2017 05:26:32 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable How about to use CpuPageTable.h and CpuPageTable.c? -----Original Message----- From: Yao, Jiewen=20 Sent: Monday, February 06, 2017 11:59 AM To: Fan, Jeff; edk2-devel@lists.01.org Cc: Kinney, Michael D Subject: RE: [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. Thanks for the suggestion. Comments below: > -----Original Message----- > From: Fan, Jeff > Sent: Sunday, February 5, 2017 7:27 PM > To: Yao, Jiewen ; edk2-devel@lists.01.org > Cc: Kinney, Michael D > Subject: RE: [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. >=20 > Jiewen, >=20 > 1. If SyncMemoryPageAttributesAp() is only to invoke SyncCpuFlushTlb(), y= ou > could simply remove the SyncCpuFlushTlb parameter and use VOID for > SyncMemoryPageAttributesAp(). > + SyncMemoryPageAttributesAp (SyncCpuFlushTlb); [Jiewen] No. We also have SyncMemoryPageAttributesAp (SyncCpuEnableWritePro= tection); > 2. Copyright date should be updated to 2017. [Jiewen] Good catch. > 3. How about to change the name of PageTableLib.h to another one? It may > confuse me this is library class or internal header file only. [Jiewen] Agree. How about we just use PageTable.h and PageTable.c? > Thanks! > Jeff >=20 > -----Original Message----- > From: Yao, Jiewen > Sent: Thursday, January 26, 2017 4:39 PM > To: edk2-devel@lists.01.org > Cc: Fan, Jeff; Kinney, Michael D > Subject: [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. >=20 > Add memory attribute setting in CpuArch protocol. > Previous SetMemoryAttributes() API only supports cache attribute setting. >=20 > This patch updated SetMemoryAttributes() API to support memory attribute > setting by updating CPU page table. >=20 > Cc: Jeff Fan > Cc: Michael Kinney > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Jiewen Yao > --- > UefiCpuPkg/CpuDxe/CpuDxe.c | 137 +-- > UefiCpuPkg/CpuDxe/CpuDxe.inf | 4 +- > UefiCpuPkg/CpuDxe/PageTableLib.h | 204 ++++ > UefiCpuPkg/CpuDxe/PageTableLibX86Pae.c | 997 ++++++++++++++++++++ > 4 files changed, 1283 insertions(+), 59 deletions(-) >=20 > diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c > index f6d0a67..4a1d27e 100644 > --- a/UefiCpuPkg/CpuDxe/CpuDxe.c > +++ b/UefiCpuPkg/CpuDxe/CpuDxe.c > @@ -14,6 +14,10 @@ >=20 > #include "CpuDxe.h" > #include "CpuMp.h" > +#include "PageTableLib.h" > + > +#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | > EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | > EFI_MEMORY_WP) > +#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | > EFI_MEMORY_RO) >=20 > // > // Global Variables > @@ -368,10 +372,9 @@ CpuSetMemoryAttributes ( > EFI_STATUS MpStatus; > EFI_MP_SERVICES_PROTOCOL *MpService; > MTRR_SETTINGS MtrrSettings; > - > - if (!IsMtrrSupported ()) { > - return EFI_UNSUPPORTED; > - } > + UINT64 CacheAttributes; > + UINT64 MemoryAttributes; > + MTRR_MEMORY_CACHE_TYPE CurrentCacheType; >=20 > // > // If this function is called because GCD SetMemorySpaceAttributes () = is called > @@ -384,69 +387,87 @@ CpuSetMemoryAttributes ( > return EFI_SUCCESS; > } >=20 > - switch (Attributes) { > - case EFI_MEMORY_UC: > - CacheType =3D CacheUncacheable; > - break; >=20 > - case EFI_MEMORY_WC: > - CacheType =3D CacheWriteCombining; > - break; > + CacheAttributes =3D Attributes & CACHE_ATTRIBUTE_MASK; > + MemoryAttributes =3D Attributes & MEMORY_ATTRIBUTE_MASK; >=20 > - case EFI_MEMORY_WT: > - CacheType =3D CacheWriteThrough; > - break; > + if (Attributes !=3D (CacheAttributes | MemoryAttributes)) { > + return EFI_INVALID_PARAMETER; > + } >=20 > - case EFI_MEMORY_WP: > - CacheType =3D CacheWriteProtected; > - break; > + if (CacheAttributes !=3D 0) { > + if (!IsMtrrSupported ()) { > + return EFI_UNSUPPORTED; > + } >=20 > - case EFI_MEMORY_WB: > - CacheType =3D CacheWriteBack; > - break; > + switch (CacheAttributes) { > + case EFI_MEMORY_UC: > + CacheType =3D CacheUncacheable; > + break; >=20 > - case EFI_MEMORY_UCE: > - case EFI_MEMORY_RP: > - case EFI_MEMORY_XP: > - case EFI_MEMORY_RUNTIME: > - return EFI_UNSUPPORTED; > + case EFI_MEMORY_WC: > + CacheType =3D CacheWriteCombining; > + break; >=20 > - default: > - return EFI_INVALID_PARAMETER; > - } > - // > - // call MTRR libary function > - // > - Status =3D MtrrSetMemoryAttribute ( > - BaseAddress, > - Length, > - CacheType > - ); > + case EFI_MEMORY_WT: > + CacheType =3D CacheWriteThrough; > + break; >=20 > - if (!RETURN_ERROR (Status)) { > - MpStatus =3D gBS->LocateProtocol ( > - &gEfiMpServiceProtocolGuid, > - NULL, > - (VOID **)&MpService > - ); > - // > - // Synchronize the update with all APs > - // > - if (!EFI_ERROR (MpStatus)) { > - MtrrGetAllMtrrs (&MtrrSettings); > - MpStatus =3D MpService->StartupAllAPs ( > - MpService, // This > - SetMtrrsFromBuffer, // Procedure > - FALSE, // SingleThread > - NULL, // WaitEvent > - 0, // > TimeoutInMicrosecsond > - &MtrrSettings, // ProcedureArgument > - NULL // FailedCpuList > - ); > - ASSERT (MpStatus =3D=3D EFI_SUCCESS || MpStatus =3D=3D EFI_NOT_STA= RTED); > + case EFI_MEMORY_WP: > + CacheType =3D CacheWriteProtected; > + break; > + > + case EFI_MEMORY_WB: > + CacheType =3D CacheWriteBack; > + break; > + > + default: > + return EFI_INVALID_PARAMETER; > + } > + CurrentCacheType =3D MtrrGetMemoryAttribute(BaseAddress); > + if (CurrentCacheType !=3D CacheType) { > + // > + // call MTRR libary function > + // > + Status =3D MtrrSetMemoryAttribute ( > + BaseAddress, > + Length, > + CacheType > + ); > + > + if (!RETURN_ERROR (Status)) { > + MpStatus =3D gBS->LocateProtocol ( > + &gEfiMpServiceProtocolGuid, > + NULL, > + (VOID **)&MpService > + ); > + // > + // Synchronize the update with all APs > + // > + if (!EFI_ERROR (MpStatus)) { > + MtrrGetAllMtrrs (&MtrrSettings); > + MpStatus =3D MpService->StartupAllAPs ( > + MpService, // This > + SetMtrrsFromBuffer, // Procedure > + FALSE, // SingleThread > + NULL, // WaitEvent > + 0, // > TimeoutInMicrosecsond > + &MtrrSettings, // > ProcedureArgument > + NULL // FailedCpuList > + ); > + ASSERT (MpStatus =3D=3D EFI_SUCCESS || MpStatus =3D=3D > EFI_NOT_STARTED); > + } > + } > + if (EFI_ERROR(Status)) { > + return Status; > + } > } > } > - return (EFI_STATUS) Status; > + > + // > + // Set memory attribute by page table > + // > + return AssignMemoryPageAttributes (NULL, BaseAddress, Length, > MemoryAttributes, AllocatePages); > } >=20 > /** > diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf > index bf389bb..47fd57e 100644 > --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf > +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf > @@ -19,7 +19,7 @@ > FILE_GUID =3D > 1A1E4886-9517-440e-9FDE-3BE44CEE2136 > MODULE_TYPE =3D DXE_DRIVER > VERSION_STRING =3D 1.0 > - > + ENTRY_POINT =3D InitializePageTableLib > ENTRY_POINT =3D InitializeCpu >=20 > [Packages] > @@ -52,6 +52,8 @@ > CpuGdt.h > CpuMp.c > CpuMp.h > + PageTableLib.h > + PageTableLibX86Pae.c >=20 > [Sources.IA32] > Ia32/CpuAsm.asm > diff --git a/UefiCpuPkg/CpuDxe/PageTableLib.h > b/UefiCpuPkg/CpuDxe/PageTableLib.h > new file mode 100644 > index 0000000..66450e4 > --- /dev/null > +++ b/UefiCpuPkg/CpuDxe/PageTableLib.h > @@ -0,0 +1,204 @@ > +/** @file > + Page table management header file. > + > + Copyright (c) 2016, Intel Corporation. All rights reserved.
> + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD > License > + which accompanies this distribution. The full text of the license may= be > found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > OR IMPLIED. > + > +**/ > + > +#ifndef _PAGE_TABLE_LIB_H_ > +#define _PAGE_TABLE_LIB_H_ > + > +#include > + > +#define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE > BIT0 > +#define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE > BIT1 > +#define > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUPPO > RT BIT2 > +#define > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE > BIT30 > +#define > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED > BIT31 > +// Other bits are reserved for future use > +typedef struct { > + UINT32 PageTableBase; > + UINT32 Reserved; > + UINT32 Attributes; > +} PAGE_TABLE_LIB_PAGING_CONTEXT_IA32; > + > +typedef struct { > + UINT64 PageTableBase; > + UINT32 Attributes; > +} PAGE_TABLE_LIB_PAGING_CONTEXT_X64; > + > +typedef union { > + PAGE_TABLE_LIB_PAGING_CONTEXT_IA32 Ia32; > + PAGE_TABLE_LIB_PAGING_CONTEXT_X64 X64; > +} PAGE_TABLE_LIB_PAGING_CONTEXT_DATA; > + > +typedef struct { > + // > + // PE32+ Machine type for EFI images > + // > + // #define IMAGE_FILE_MACHINE_I386 0x014c > + // #define IMAGE_FILE_MACHINE_X64 0x8664 > + // > + UINT16 MachineType; > + PAGE_TABLE_LIB_PAGING_CONTEXT_DATA ContextData; > +} PAGE_TABLE_LIB_PAGING_CONTEXT; > + > +/** > + Allocates one or more 4KB pages for page table. > + > + @param Pages The number of 4 KB pages to allocate. > + > + @return A pointer to the allocated buffer or NULL if allocation fails. > + > +**/ > +typedef > +VOID * > +(EFIAPI *PAGE_TABLE_LIB_ALLOCATE_PAGES) ( > + IN UINTN Pages > + ); > + > +/** > + This function assigns the page attributes for the memory region specif= ied by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param PagingContext The paging context. NULL means get page > table from current CPU context. > + @param BaseAddress The physical address that is the start addre= ss > of a memory region. > + @param Length The size in bytes of the memory region. > + @param Attributes The bit mask of attributes to set for the > memory region. > + @param AllocatePagesFunc If page split is needed, this function is us= ed to > allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +AssignMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ); > + > +/** > + This function sets the page attributes for the memory region specified= by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param PagingContext The paging context. NULL means get page > table from current CPU context. > + @param BaseAddress The physical address that is the start addre= ss > of a memory region. > + @param Length The size in bytes of the memory region. > + @param Attributes The bit mask of attributes to set for the > memory region. > + @param AllocatePagesFunc If page split is needed, this function is us= ed to > allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were set for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +SetMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ); > + > +/** > + This function clears the page attributes for the memory region specifi= ed by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param PagingContext The paging context. NULL means get page > table from current CPU context. > + @param BaseAddress The physical address that is the start addre= ss > of a memory region. > + @param Length The size in bytes of the memory region. > + @param Attributes The bit mask of attributes to set for the > memory region. > + @param AllocatePagesFunc If page split is needed, this function is us= ed to > allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +ClearMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ); > + > +/** > + This function return the page attributes for the memory region specifi= ed by > BaseAddress. > + > + Caller should make sure BaseAddress is at page boundary. > + > + @param PagingContext The paging context. NULL means get page > table from current CPU context. > + @param BaseAddress The physical address that is the start addre= ss > of a memory region. > + @param Attributes The bit mask of attributes of the memory > region. > + @param PageSize The size of the pages which contains the > BaseAddress. > + > + @retval RETURN_SUCCESS The Attributes and PageSize is > returned. > + @retval RETURN_INVALID_PARAMETER Both Attributes and PageSize are > zero. > + @retval RETURN_NOT_FOUND The processor does not setup > paging for BaseAddress. > +**/ > +RETURN_STATUS > +EFIAPI > +GetMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + OUT UINT64 *Attributes, > + OUT UINT64 *PageSize > + ); > + > +#endif > diff --git a/UefiCpuPkg/CpuDxe/PageTableLibX86Pae.c > b/UefiCpuPkg/CpuDxe/PageTableLibX86Pae.c > new file mode 100644 > index 0000000..0d6c6a6 > --- /dev/null > +++ b/UefiCpuPkg/CpuDxe/PageTableLibX86Pae.c > @@ -0,0 +1,997 @@ > +/** @file > + Page table management support. > + > + Copyright (c) 2016, Intel Corporation. All rights reserved.
> + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD > License > + which accompanies this distribution. The full text of the license may= be > found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > OR IMPLIED. > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "PageTableLib.h" > + > +/// > +/// Page Table Entry > +/// > +#define IA32_PG_P BIT0 > +#define IA32_PG_RW BIT1 > +#define IA32_PG_U BIT2 > +#define IA32_PG_WT BIT3 > +#define IA32_PG_CD BIT4 > +#define IA32_PG_A BIT5 > +#define IA32_PG_D BIT6 > +#define IA32_PG_PS BIT7 > +#define IA32_PG_PAT_2M BIT12 > +#define IA32_PG_PAT_4K IA32_PG_PS > +#define IA32_PG_PMNT BIT62 > +#define IA32_PG_NX BIT63 > + > +#define PAGE_ATTRIBUTE_BITS (IA32_PG_D | IA32_PG_A | > IA32_PG_U | IA32_PG_RW | IA32_PG_P) > +// > +// Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE > +// X64 PAE PDPTE does not have such restriction > +// > +#define IA32_PAE_PDPTE_ATTRIBUTE_BITS (IA32_PG_P) > + > +#define PAGE_PROGATE_BITS (IA32_PG_NX | > PAGE_ATTRIBUTE_BITS) > + > +#define PAGING_4K_MASK 0xFFF > +#define PAGING_2M_MASK 0x1FFFFF > +#define PAGING_1G_MASK 0x3FFFFFFF > + > +#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 > + > +typedef enum { > + PageNone, > + Page4K, > + Page2M, > + Page1G, > +} PAGE_ATTRIBUTE; > + > +typedef struct { > + PAGE_ATTRIBUTE Attribute; > + UINT64 Length; > + UINT64 AddressMask; > +} PAGE_ATTRIBUTE_TABLE; > + > +typedef enum { > + PageActionAssign, > + PageActionSet, > + PageActionClear, > +} PAGE_ACTION; > + > +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] =3D { > + {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64}, > + {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64}, > + {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64}, > +}; > + > +/** > + Enable write protection function for AP. > + > + @param[in,out] Buffer The pointer to private data buffer. > +**/ > +VOID > +EFIAPI > +SyncCpuEnableWriteProtection ( > + IN OUT VOID *Buffer > + ) > +{ > + AsmWriteCr0 (AsmReadCr0 () | BIT16); > +} > + > +/** > + CpuFlushTlb function for AP. > + > + @param[in,out] Buffer The pointer to private data buffer. > +**/ > +VOID > +EFIAPI > +SyncCpuFlushTlb ( > + IN OUT VOID *Buffer > + ) > +{ > + CpuFlushTlb(); > +} > + > +/** > + Sync memory page attributes for AP. > + > + @param[in] Procedure A pointer to the function to be run on > enabled APs of > + the system. > +**/ > +VOID > +SyncMemoryPageAttributesAp ( > + IN EFI_AP_PROCEDURE Procedure > + ) > +{ > + EFI_STATUS Status; > + EFI_MP_SERVICES_PROTOCOL *MpService; > + > + Status =3D gBS->LocateProtocol ( > + &gEfiMpServiceProtocolGuid, > + NULL, > + (VOID **)&MpService > + ); > + // > + // Synchronize the update with all APs > + // > + if (!EFI_ERROR (Status)) { > + Status =3D MpService->StartupAllAPs ( > + MpService, // This > + Procedure, // Procedure > + FALSE, // SingleThread > + NULL, // WaitEvent > + 0, // TimeoutInMicrosecsond > + NULL, // ProcedureArgument > + NULL // FailedCpuList > + ); > + ASSERT (Status =3D=3D EFI_SUCCESS || Status =3D=3D EFI_NOT_STARTED); > + } > +} > + > +/** > + Return current paging context. > + > + @param[in,out] PagingContext The paging context. > +**/ > +VOID > +GetCurrentPagingContext ( > + IN OUT PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext > + ) > +{ > + UINT32 RegEax; > + UINT32 RegEdx; > + > + ZeroMem(PagingContext, sizeof(*PagingContext)); > + if (sizeof(UINTN) =3D=3D sizeof(UINT64)) { > + PagingContext->MachineType =3D IMAGE_FILE_MACHINE_X64; > + } else { > + PagingContext->MachineType =3D IMAGE_FILE_MACHINE_I386; > + } > + if ((AsmReadCr0 () & BIT31) !=3D 0) { > + PagingContext->ContextData.X64.PageTableBase =3D (AsmReadCr3 () & > PAGING_4K_ADDRESS_MASK_64); > + if ((AsmReadCr0 () & BIT16) =3D=3D 0) { > + AsmWriteCr0 (AsmReadCr0 () | BIT16); > + SyncMemoryPageAttributesAp (SyncCpuEnableWriteProtection); > + } > + } else { > + PagingContext->ContextData.X64.PageTableBase =3D 0; > + } > + > + if ((AsmReadCr4 () & BIT4) !=3D 0) { > + PagingContext->ContextData.Ia32.Attributes |=3D > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE; > + } > + if ((AsmReadCr4 () & BIT5) !=3D 0) { > + PagingContext->ContextData.Ia32.Attributes |=3D > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE; > + } > + if ((AsmReadCr0 () & BIT16) !=3D 0) { > + PagingContext->ContextData.Ia32.Attributes |=3D > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE; > + } > + > + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); > + if (RegEax > 0x80000000) { > + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); > + if ((RegEdx & BIT20) !=3D 0) { > + // XD supported > + if ((AsmReadMsr64 (0x000001A0) & BIT34) =3D=3D 0) { > + // XD enabled > + if ((AsmReadMsr64 (0xC0000080) & BIT11) !=3D 0) { > + // XD activated > + PagingContext->ContextData.Ia32.Attributes |=3D > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED; > + } > + } > + } > + if ((RegEdx & BIT26) !=3D 0) { > + PagingContext->ContextData.Ia32.Attributes |=3D > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUPPO > RT; > + } > + } > +} > + > +/** > + Return length according to page attributes. > + > + @param[in] PageAttributes The page attribute of the page entry. > + > + @return The length of page entry. > +**/ > +UINTN > +PageAttributeToLength ( > + IN PAGE_ATTRIBUTE PageAttribute > + ) > +{ > + UINTN Index; > + for (Index =3D 0; Index < > sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) { > + if (PageAttribute =3D=3D mPageAttributeTable[Index].Attribute) { > + return (UINTN)mPageAttributeTable[Index].Length; > + } > + } > + return 0; > +} > + > +/** > + Return address mask according to page attributes. > + > + @param[in] PageAttributes The page attribute of the page entry. > + > + @return The address mask of page entry. > +**/ > +UINTN > +PageAttributeToMask ( > + IN PAGE_ATTRIBUTE PageAttribute > + ) > +{ > + UINTN Index; > + for (Index =3D 0; Index < > sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) { > + if (PageAttribute =3D=3D mPageAttributeTable[Index].Attribute) { > + return (UINTN)mPageAttributeTable[Index].AddressMask; > + } > + } > + return 0; > +} > + > +/** > + Return page table entry to match the address. > + > + @param[in] PagingContext The paging context. > + @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 PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext, > + IN PHYSICAL_ADDRESS Address, > + OUT PAGE_ATTRIBUTE *PageAttribute > + ) > +{ > + UINTN Index1; > + UINTN Index2; > + UINTN Index3; > + UINTN Index4; > + UINT64 *L1PageTable; > + UINT64 *L2PageTable; > + UINT64 *L3PageTable; > + UINT64 *L4PageTable; > + > + ASSERT (PagingContext !=3D NULL); > + > + Index4 =3D ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK; > + Index3 =3D ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK; > + Index2 =3D ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK; > + Index1 =3D ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK; > + > + if (PagingContext->MachineType =3D=3D IMAGE_FILE_MACHINE_X64) { > + L4PageTable =3D (UINT64 > *)(UINTN)PagingContext->ContextData.X64.PageTableBase; > + if (L4PageTable[Index4] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + > + L3PageTable =3D (UINT64 *)(UINTN)(L4PageTable[Index4] & > PAGING_4K_ADDRESS_MASK_64); > + } else { > + ASSERT((PagingContext->ContextData.Ia32.Attributes & > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) !=3D 0); > + L3PageTable =3D (UINT64 > *)(UINTN)PagingContext->ContextData.Ia32.PageTableBase; > + } > + if (L3PageTable[Index3] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + if ((L3PageTable[Index3] & IA32_PG_PS) !=3D 0) { > + // 1G > + *PageAttribute =3D Page1G; > + return &L3PageTable[Index3]; > + } > + > + L2PageTable =3D (UINT64 *)(UINTN)(L3PageTable[Index3] & > PAGING_4K_ADDRESS_MASK_64); > + if (L2PageTable[Index2] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + if ((L2PageTable[Index2] & IA32_PG_PS) !=3D 0) { > + // 2M > + *PageAttribute =3D Page2M; > + return &L2PageTable[Index2]; > + } > + > + // 4k > + L1PageTable =3D (UINT64 *)(UINTN)(L2PageTable[Index2] & > PAGING_4K_ADDRESS_MASK_64); > + if ((L1PageTable[Index1] =3D=3D 0) && (Address !=3D 0)) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + *PageAttribute =3D Page4K; > + return &L1PageTable[Index1]; > +} > + > +/** > + Return memory attributes of page entry. > + > + @param[in] PageEntry The page entry. > + > + @return Memory attributes of page entry. > +**/ > +UINT64 > +GetAttributesFromPageEntry ( > + IN UINT64 *PageEntry > + ) > +{ > + UINT64 Attributes; > + Attributes =3D 0; > + if ((*PageEntry & IA32_PG_P) =3D=3D 0) { > + Attributes |=3D EFI_MEMORY_RP; > + } > + if ((*PageEntry & IA32_PG_RW) =3D=3D 0) { > + Attributes |=3D EFI_MEMORY_RO; > + } > + if ((*PageEntry & IA32_PG_NX) !=3D 0) { > + Attributes |=3D EFI_MEMORY_XP; > + } > + return Attributes; > +} > + > +/** > + Modify memory attributes of page entry. > + > + @param[in] PagingContext The paging context. > + @param[in] PageEntry The page entry. > + @param[in] Attributes The bit mask of attributes to modify for = the > memory region. > + @param[in] PageAction The page action. > + @param[out] IsModified TRUE means page table modified. FALSE > means page table not modified. > +**/ > +VOID > +ConvertPageEntryAttribute ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext, > + IN UINT64 *PageEntry, > + IN UINT64 Attributes, > + IN PAGE_ACTION PageAction, > + OUT BOOLEAN *IsModified > + ) > +{ > + UINT64 CurrentPageEntry; > + UINT64 NewPageEntry; > + > + CurrentPageEntry =3D *PageEntry; > + NewPageEntry =3D CurrentPageEntry; > + if ((Attributes & EFI_MEMORY_RP) !=3D 0) { > + switch (PageAction) { > + case PageActionAssign: > + case PageActionSet: > + NewPageEntry &=3D ~(UINT64)IA32_PG_P; > + break; > + case PageActionClear: > + NewPageEntry |=3D IA32_PG_P; > + break; > + } > + } else { > + switch (PageAction) { > + case PageActionAssign: > + NewPageEntry |=3D IA32_PG_P; > + break; > + case PageActionSet: > + case PageActionClear: > + break; > + } > + } > + if ((Attributes & EFI_MEMORY_RO) !=3D 0) { > + switch (PageAction) { > + case PageActionAssign: > + case PageActionSet: > + NewPageEntry &=3D ~(UINT64)IA32_PG_RW; > + break; > + case PageActionClear: > + NewPageEntry |=3D IA32_PG_RW; > + break; > + } > + } else { > + switch (PageAction) { > + case PageActionAssign: > + NewPageEntry |=3D IA32_PG_RW; > + break; > + case PageActionSet: > + case PageActionClear: > + break; > + } > + } > + if ((PagingContext->ContextData.Ia32.Attributes & > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED) !=3D > 0) { > + if ((Attributes & EFI_MEMORY_XP) !=3D 0) { > + switch (PageAction) { > + case PageActionAssign: > + case PageActionSet: > + NewPageEntry |=3D IA32_PG_NX; > + break; > + case PageActionClear: > + NewPageEntry &=3D ~IA32_PG_NX; > + break; > + } > + } else { > + switch (PageAction) { > + case PageActionAssign: > + NewPageEntry &=3D ~IA32_PG_NX; > + break; > + case PageActionSet: > + case PageActionClear: > + break; > + } > + } > + } > + *PageEntry =3D NewPageEntry; > + if (CurrentPageEntry !=3D NewPageEntry) { > + *IsModified =3D TRUE; > + DEBUG ((DEBUG_INFO, "ConvertPageEntryAttribute 0x%lx", > CurrentPageEntry)); > + DEBUG ((DEBUG_INFO, "->0x%lx\n", NewPageEntry)); > + } else { > + *IsModified =3D FALSE; > + } > +} > + > +/** > + This function returns if there is need to split page entry. > + > + @param[in] BaseAddress The base address to be checked. > + @param[in] Length The length to be checked. > + @param[in] PageEntry The page entry to be checked. > + @param[in] PageAttribute The page attribute of the page entry. > + > + @retval SplitAttributes on if there is need to split page entry. > +**/ > +PAGE_ATTRIBUTE > +NeedSplitPage ( > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 *PageEntry, > + IN PAGE_ATTRIBUTE PageAttribute > + ) > +{ > + UINT64 PageEntryLength; > + > + PageEntryLength =3D PageAttributeToLength (PageAttribute); > + > + if (((BaseAddress & (PageEntryLength - 1)) =3D=3D 0) && (Length >=3D > PageEntryLength)) { > + return PageNone; > + } > + > + if (((BaseAddress & PAGING_2M_MASK) !=3D 0) || (Length < SIZE_2MB)) { > + return Page4K; > + } > + > + return Page2M; > +} > + > +/** > + This function splits one page entry to small 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] AllocatePagesFunc If page split is needed, this function i= s used > to allocate more pages. > + > + @retval RETURN_SUCCESS The page entry is splitted. > + @retval RETURN_UNSUPPORTED The page entry does not support > to be splitted. > + @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 PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc > + ) > +{ > + UINT64 BaseAddress; > + UINT64 *NewPageEntry; > + UINTN Index; > + > + ASSERT (PageAttribute =3D=3D Page2M || PageAttribute =3D=3D Page1G); > + > + ASSERT (AllocatePagesFunc !=3D NULL); > + > + if (PageAttribute =3D=3D Page2M) { > + // > + // Split 2M to 4K > + // > + ASSERT (SplitAttribute =3D=3D Page4K); > + if (SplitAttribute =3D=3D Page4K) { > + NewPageEntry =3D AllocatePagesFunc (1); > + DEBUG ((DEBUG_INFO, "Split - 0x%x\n", NewPageEntry)); > + if (NewPageEntry =3D=3D NULL) { > + return RETURN_OUT_OF_RESOURCES; > + } > + BaseAddress =3D *PageEntry & PAGING_2M_ADDRESS_MASK_64; > + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) { > + NewPageEntry[Index] =3D BaseAddress + SIZE_4KB * Index + > ((*PageEntry) & PAGE_PROGATE_BITS); > + } > + (*PageEntry) =3D (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & > PAGE_PROGATE_BITS); > + return RETURN_SUCCESS; > + } else { > + return RETURN_UNSUPPORTED; > + } > + } else if (PageAttribute =3D=3D Page1G) { > + // > + // Split 1G to 2M > + // No need support 1G->4K directly, we should use 1G->2M, then 2M->4= K > to get more compact page table. > + // > + ASSERT (SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K= ); > + if ((SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K)) = { > + NewPageEntry =3D AllocatePagesFunc (1); > + DEBUG ((DEBUG_INFO, "Split - 0x%x\n", NewPageEntry)); > + if (NewPageEntry =3D=3D NULL) { > + return RETURN_OUT_OF_RESOURCES; > + } > + BaseAddress =3D *PageEntry & PAGING_1G_ADDRESS_MASK_64; > + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) { > + NewPageEntry[Index] =3D BaseAddress + SIZE_2MB * Index + > IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS); > + } > + (*PageEntry) =3D (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & > PAGE_PROGATE_BITS); > + return RETURN_SUCCESS; > + } else { > + return RETURN_UNSUPPORTED; > + } > + } else { > + return RETURN_UNSUPPORTED; > + } > +} > + > +/** > + This function modifies the page attributes for the memory region speci= fied by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + @param[in] PagingContext The paging context. NULL means get page > table from current CPU context. > + @param[in] BaseAddress The physical address that is the start > address of a memory region. > + @param[in] Length The size in bytes of the memory region. > + @param[in] Attributes The bit mask of attributes to modify for= the > memory region. > + @param[in] PageAction The page action. > + @param[in] AllocatePagesFunc If page split is needed, this function i= s used > to allocate more pages. > + NULL mean page split is unsupported. > + @param[out] IsSplitted TRUE means page table splitted. FALSE > means page table not splitted. > + @param[out] IsModified TRUE means page table modified. FALSE > means page table not modified. > + > + @retval RETURN_SUCCESS The attributes were modified for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +ConvertMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_ACTION PageAction, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL, > + OUT BOOLEAN *IsSplitted, OPTIONAL > + OUT BOOLEAN *IsModified OPTIONAL > + ) > +{ > + PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext; > + UINT64 *PageEntry; > + PAGE_ATTRIBUTE PageAttribute; > + UINTN PageEntryLength; > + PAGE_ATTRIBUTE SplitAttribute; > + RETURN_STATUS Status; > + BOOLEAN IsEntryModified; > + > + if ((BaseAddress & (SIZE_4KB - 1)) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "BaseAddress(0x%lx) is not aligned!\n", > BaseAddress)); > + return EFI_UNSUPPORTED; > + } > + if ((Length & (SIZE_4KB - 1)) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "Length(0x%lx) is not aligned!\n", Length)); > + return EFI_UNSUPPORTED; > + } > + if (Length =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "Length is 0!\n")); > + return RETURN_INVALID_PARAMETER; > + } > + > + if ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | > EFI_MEMORY_XP)) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "Attributes(0x%lx) has unsupported bit\n", > Attributes)); > + return EFI_UNSUPPORTED; > + } > + > + if (PagingContext =3D=3D NULL) { > + GetCurrentPagingContext (&CurrentPagingContext); > + } else { > + CopyMem (&CurrentPagingContext, PagingContext, > sizeof(CurrentPagingContext)); > + } > + switch(CurrentPagingContext.MachineType) { > + case IMAGE_FILE_MACHINE_I386: > + if (CurrentPagingContext.ContextData.Ia32.PageTableBase =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "PageTable is 0!\n")); > + if (Attributes =3D=3D 0) { > + return EFI_SUCCESS; > + } else { > + return EFI_UNSUPPORTED; > + } > + } > + if ((CurrentPagingContext.ContextData.Ia32.Attributes & > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "Non-PAE Paging!\n")); > + return EFI_UNSUPPORTED; > + } > + break; > + case IMAGE_FILE_MACHINE_X64: > + ASSERT (CurrentPagingContext.ContextData.X64.PageTableBase !=3D 0); > + break; > + default: > + ASSERT(FALSE); > + return EFI_UNSUPPORTED; > + break; > + } > + > +// DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) > - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes)); > + > + if (IsSplitted !=3D NULL) { > + *IsSplitted =3D FALSE; > + } > + if (IsModified !=3D NULL) { > + *IsModified =3D FALSE; > + } > + > + // > + // Below logic is to check 2M/4K page to make sure we donot waist memo= ry. > + // > + while (Length !=3D 0) { > + PageEntry =3D GetPageTableEntry (&CurrentPagingContext, BaseAddress, > &PageAttribute); > + if (PageEntry =3D=3D NULL) { > + return RETURN_UNSUPPORTED; > + } > + PageEntryLength =3D PageAttributeToLength (PageAttribute); > + SplitAttribute =3D NeedSplitPage (BaseAddress, Length, PageEntry, > PageAttribute); > + if (SplitAttribute =3D=3D PageNone) { > + ConvertPageEntryAttribute (&CurrentPagingContext, PageEntry, > Attributes, PageAction, &IsEntryModified); > + if (IsEntryModified) { > + if (IsModified !=3D NULL) { > + *IsModified =3D TRUE; > + } > + } > + // > + // Convert success, move to next > + // > + BaseAddress +=3D PageEntryLength; > + Length -=3D PageEntryLength; > + } else { > + if (AllocatePagesFunc =3D=3D NULL) { > + return RETURN_UNSUPPORTED; > + } > + Status =3D SplitPage (PageEntry, PageAttribute, SplitAttribute, > AllocatePagesFunc); > + if (RETURN_ERROR (Status)) { > + return RETURN_UNSUPPORTED; > + } > + if (IsSplitted !=3D NULL) { > + *IsSplitted =3D TRUE; > + } > + if (IsModified !=3D NULL) { > + *IsModified =3D TRUE; > + } > + // > + // Just split current page > + // Convert success in next around > + // > + } > + } > + > + return RETURN_SUCCESS; > +} > + > +/** > + This function assigns the page attributes for the memory region specif= ied by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param[in] PagingContext The paging context. NULL means get page > table from current CPU context. > + @param[in] BaseAddress The physical address that is the start > address of a memory region. > + @param[in] Length The size in bytes of the memory region. > + @param[in] Attributes The bit mask of attributes to set for th= e > memory region. > + @param[in] AllocatePagesFunc If page split is needed, this function i= s used > to allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +AssignMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ) > +{ > + RETURN_STATUS Status; > + BOOLEAN IsModified; > + BOOLEAN IsSplitted; > + > +// DEBUG((DEBUG_INFO, "AssignMemoryPageAttributes: 0x%lx - 0x%lx > (0x%lx)\n", BaseAddress, Length, Attributes)); > + Status =3D ConvertMemoryPageAttributes (PagingContext, BaseAddress, > Length, Attributes, PageActionAssign, AllocatePagesFunc, &IsSplitted, > &IsModified); > + if (!EFI_ERROR(Status)) { > + if ((PagingContext =3D=3D NULL) && IsModified) { > + // > + // Flush TLB as last step > + // > + CpuFlushTlb(); > + SyncMemoryPageAttributesAp (SyncCpuFlushTlb); > + } > + } > + > + return Status; > +} > + > +/** > + This function sets the page attributes for the memory region specified= by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param[in] PagingContext The paging context. NULL means get page > table from current CPU context. > + @param[in] BaseAddress The physical address that is the start > address of a memory region. > + @param[in] Length The size in bytes of the memory region. > + @param[in] Attributes The bit mask of attributes to set for th= e > memory region. > + @param[in] AllocatePagesFunc If page split is needed, this function i= s used > to allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were set for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +SetMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ) > +{ > + RETURN_STATUS Status; > + BOOLEAN IsModified; > + BOOLEAN IsSplitted; > + > +// DEBUG((DEBUG_INFO, "SetMemoryPageAttributes: 0x%lx - 0x%lx > (0x%lx)\n", BaseAddress, Length, Attributes)); > + Status =3D ConvertMemoryPageAttributes (PagingContext, BaseAddress, > Length, Attributes, PageActionSet, AllocatePagesFunc, &IsSplitted, &IsMod= ified); > + if (!EFI_ERROR(Status)) { > + if ((PagingContext =3D=3D NULL) && IsModified) { > + // > + // Flush TLB as last step > + // > + CpuFlushTlb(); > + SyncMemoryPageAttributesAp (SyncCpuFlushTlb); > + } > + } > + > + return Status; > +} > + > +/** > + This function clears the page attributes for the memory region specifi= ed by > BaseAddress and > + Length from their current attributes to the attributes specified by At= tributes. > + > + Caller should make sure BaseAddress and Length is at page boundary. > + > + Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page = request. > + > + @param[in] PagingContext The paging context. NULL means get page > table from current CPU context. > + @param[in] BaseAddress The physical address that is the start > address of a memory region. > + @param[in] Length The size in bytes of the memory region. > + @param[in] Attributes The bit mask of attributes to set for th= e > memory region. > + @param[in] AllocatePagesFunc If page split is needed, this function i= s used > to allocate more pages. > + NULL mean page split is unsupported. > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_ACCESS_DENIED The attributes for the memory > resource range specified by > + BaseAddress and Length cannot be > modified. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal > combination of attributes that > + cannot be set together. > + @retval RETURN_OUT_OF_RESOURCES There are not enough system > resources to modify the attributes of > + the memory resource range. > + @retval RETURN_UNSUPPORTED The processor does not support one > or more bytes of the memory > + resource range specified by > BaseAddress and Length. > + The bit mask of attributes is not > support for the memory resource > + range specified by BaseAddress and > Length. > +**/ > +RETURN_STATUS > +EFIAPI > +ClearMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINT64 Length, > + IN UINT64 Attributes, > + IN PAGE_TABLE_LIB_ALLOCATE_PAGES AllocatePagesFunc OPTIONAL > + ) > +{ > + RETURN_STATUS Status; > + BOOLEAN IsModified; > + BOOLEAN IsSplitted; > + > +// DEBUG((DEBUG_INFO, "ClearMemoryPageAttributes: 0x%lx - 0x%lx > (0x%lx)\n", BaseAddress, Length, Attributes)); > + Status =3D ConvertMemoryPageAttributes (PagingContext, BaseAddress, > Length, Attributes, PageActionClear, AllocatePagesFunc, &IsSplitted, > &IsModified); > + if (!EFI_ERROR(Status)) { > + if ((PagingContext =3D=3D NULL) && IsModified) { > + // > + // Flush TLB as last step > + // > + CpuFlushTlb(); > + SyncMemoryPageAttributesAp (SyncCpuFlushTlb); > + } > + } > + > + return Status; > +} > + > +/** > + This function return the page attributes for the memory region specifi= ed by > BaseAddress. > + > + Caller should make sure BaseAddress is at page boundary. > + > + @param[in] PagingContext The paging context. NULL means get page > table from current CPU context. > + @param[in] BaseAddress The physical address that is the start > address of a memory region. > + @param[out] Attributes The bit mask of attributes of the memory > region. > + @param[out] PageSize The size of the pages which contains the > BaseAddress. > + > + @retval RETURN_SUCCESS The Attributes and PageSize is > returned. > + @retval RETURN_INVALID_PARAMETER Both Attributes and PageSize are > zero. > + @retval RETURN_NOT_FOUND The processor does not setup > paging for BaseAddress. > +**/ > +RETURN_STATUS > +EFIAPI > +GetMemoryPageAttributes ( > + IN PAGE_TABLE_LIB_PAGING_CONTEXT *PagingContext OPTIONAL, > + IN PHYSICAL_ADDRESS BaseAddress, > + OUT UINT64 *Attributes, > + OUT UINT64 *PageSize > + ) > +{ > + PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext; > + PAGE_ATTRIBUTE PageAttribute; > + UINT64 *PageEntry; > + > + if (Attributes =3D=3D NULL && PageSize =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "Attributes and PageSize are NULL!\n")); > + return RETURN_INVALID_PARAMETER; > + } > + > + if ((BaseAddress & (SIZE_4KB - 1)) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "BaseAddress(0x%lx) is not aligned!\n", > BaseAddress)); > + return EFI_UNSUPPORTED; > + } > + > +// DEBUG((DEBUG_INFO, "GetMemoryPageAttributes: 0x%lx\n", > BaseAddress)); > + if (PagingContext =3D=3D NULL) { > + GetCurrentPagingContext (&CurrentPagingContext); > + } else { > + CopyMem (&CurrentPagingContext, PagingContext, > sizeof(CurrentPagingContext)); > + } > + switch(CurrentPagingContext.MachineType) { > + case IMAGE_FILE_MACHINE_I386: > + if (CurrentPagingContext.ContextData.Ia32.PageTableBase =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "PageTable is 0!\n")); > + if (Attributes !=3D NULL) { > + *Attributes =3D 0; > + } > + if (PageSize !=3D NULL) { > + *PageSize =3D 0; > + } > + return EFI_SUCCESS; > + } > + if ((CurrentPagingContext.ContextData.Ia32.Attributes & > PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE) =3D=3D 0) { > + DEBUG ((DEBUG_ERROR, "Non-PAE Paging!\n")); > + return EFI_UNSUPPORTED; > + } > + break; > + case IMAGE_FILE_MACHINE_X64: > + ASSERT (CurrentPagingContext.ContextData.X64.PageTableBase !=3D 0); > + break; > + default: > + ASSERT(FALSE); > + return EFI_UNSUPPORTED; > + break; > + } > + > + PageEntry =3D GetPageTableEntry(&CurrentPagingContext, BaseAddress, > &PageAttribute); > + if (PageEntry =3D=3D NULL) { > + return RETURN_NOT_FOUND; > + } > + > + if (Attributes !=3D NULL) { > + *Attributes =3D 0; > + if ((*PageEntry & IA32_PG_NX) !=3D 0) { > + *Attributes |=3D EFI_MEMORY_XP; > + } > + if ((*PageEntry & IA32_PG_RW) =3D=3D 0) { > + *Attributes |=3D EFI_MEMORY_RO; > + } > + if ((*PageEntry & IA32_PG_P) =3D=3D 0) { > + *Attributes |=3D EFI_MEMORY_RP; > + } > + } > + > + if (PageSize !=3D NULL) { > + *PageSize =3D PageAttributeToLength(PageAttribute); > + } > + > + return RETURN_SUCCESS; > +} > + > +/** > + Initialize the Page Table lib. > + > + @param ImageHandle Image handle this driver. > + @param SystemTable Pointer to the System Table. > + > + @retval EFI_SUCCESS Thread can be successfully created > + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure > + @retval EFI_DEVICE_ERROR Cannot create the thread > + > +**/ > +EFI_STATUS > +EFIAPI > +InitializePageTableLib ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + PAGE_TABLE_LIB_PAGING_CONTEXT CurrentPagingContext; > + > + GetCurrentPagingContext (&CurrentPagingContext); > + DEBUG ((DEBUG_INFO, "CurrentPagingContext:\n", > CurrentPagingContext.MachineType)); > + DEBUG ((DEBUG_INFO, " MachineType - 0x%x\n", > CurrentPagingContext.MachineType)); > + DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", > CurrentPagingContext.ContextData.X64.PageTableBase)); > + DEBUG ((DEBUG_INFO, " Attributes - 0x%x\n", > CurrentPagingContext.ContextData.X64.Attributes)); > + > + return EFI_SUCCESS; > +} > + > -- > 2.7.4.windows.1