From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) (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 9E1E782059 for ; Fri, 3 Feb 2017 00:51:22 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP; 03 Feb 2017 00:51:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,328,1477983600"; d="scan'208";a="39187389" Received: from fmsmsx104.amr.corp.intel.com ([10.18.124.202]) by orsmga002.jf.intel.com with ESMTP; 03 Feb 2017 00:51:21 -0800 Received: from fmsmsx152.amr.corp.intel.com (10.18.125.5) by fmsmsx104.amr.corp.intel.com (10.18.124.202) with Microsoft SMTP Server (TLS) id 14.3.248.2; Fri, 3 Feb 2017 00:51:21 -0800 Received: from shsmsx152.ccr.corp.intel.com (10.239.6.52) by FMSMSX152.amr.corp.intel.com (10.18.125.5) with Microsoft SMTP Server (TLS) id 14.3.248.2; Fri, 3 Feb 2017 00:51:20 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.88]) by SHSMSX152.ccr.corp.intel.com ([169.254.6.132]) with mapi id 14.03.0248.002; Fri, 3 Feb 2017 16:51:19 +0800 From: "Gao, Liming" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: "Kinney, Michael D" , "Fan, Jeff" Thread-Topic: [edk2] [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute setting. Thread-Index: AQHSd6/tlH3zAixTO0+1JRW1/OmpYqFXAtug Date: Fri, 3 Feb 2017 08:51:18 +0000 Message-ID: <4A89E2EF3DFEDB4C8BFDE51014F606A14D6D6446@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> In-Reply-To: <1485419955-26652-2-git-send-email-jiewen.yao@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: 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: Fri, 03 Feb 2017 08:51:22 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Jiewen: This patch adds PageTableLib implementation into CpuDxe driver. The purpo= se of this change is to update SetMemoryAttributes() API in CpuDxe driver. = If so, new function AssignMemoryPageAttributes() will be enough. Other SetM= emoryPageAttributes(),ClearMemoryPageAttributes() and GetMemoryPageAttribut= es() are not required. If they are useful, you can separate PageTableLib im= plementation from this patch.=20 Thanks Liming >-----Original Message----- >From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of >Jiewen Yao >Sent: Thursday, January 26, 2017 4:39 PM >To: edk2-devel@lists.01.org >Cc: Kinney, Michael D ; Fan, Jeff > >Subject: [edk2] [PATCH 1/3] UefiCpuPkg/CpuDxe: Add memory attribute >setting. > >Add memory attribute setting in CpuArch protocol. >Previous SetMemoryAttributes() API only supports cache attribute setting. > >This patch updated SetMemoryAttributes() API to support memory attribute >setting by updating CPU page table. > >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(-) > >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 @@ > > #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) > > // > // 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; > > // > // If this function is called because GCD SetMemorySpaceAttributes () i= s >called >@@ -384,69 +387,87 @@ CpuSetMemoryAttributes ( > return EFI_SUCCESS; > } > >- switch (Attributes) { >- case EFI_MEMORY_UC: >- CacheType =3D CacheUncacheable; >- break; > >- case EFI_MEMORY_WC: >- CacheType =3D CacheWriteCombining; >- break; >+ CacheAttributes =3D Attributes & CACHE_ATTRIBUTE_MASK; >+ MemoryAttributes =3D Attributes & MEMORY_ATTRIBUTE_MASK; > >- case EFI_MEMORY_WT: >- CacheType =3D CacheWriteThrough; >- break; >+ if (Attributes !=3D (CacheAttributes | MemoryAttributes)) { >+ return EFI_INVALID_PARAMETER; >+ } > >- case EFI_MEMORY_WP: >- CacheType =3D CacheWriteProtected; >- break; >+ if (CacheAttributes !=3D 0) { >+ if (!IsMtrrSupported ()) { >+ return EFI_UNSUPPORTED; >+ } > >- case EFI_MEMORY_WB: >- CacheType =3D CacheWriteBack; >- break; >+ switch (CacheAttributes) { >+ case EFI_MEMORY_UC: >+ CacheType =3D CacheUncacheable; >+ break; > >- 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; > >- default: >- return EFI_INVALID_PARAMETER; >- } >- // >- // call MTRR libary function >- // >- Status =3D MtrrSetMemoryAttribute ( >- BaseAddress, >- Length, >- CacheType >- ); >+ case EFI_MEMORY_WT: >+ CacheType =3D CacheWriteThrough; >+ break; > >- 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, // TimeoutInMicrosecson= d >- &MtrrSettings, // ProcedureArgument >- NULL // FailedCpuList >- ); >- ASSERT (MpStatus =3D=3D EFI_SUCCESS || MpStatus =3D=3D EFI_NOT_STAR= TED); >+ 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, // TimeoutInMicrose= csond >+ &MtrrSettings, // ProcedureArgumen= t >+ 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); > } > > /** >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 > > [Packages] >@@ -52,6 +52,8 @@ > CpuGdt.h > CpuMp.c > CpuMp.h >+ PageTableLib.h >+ PageTableLibX86Pae.c > > [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 B= SD >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_SUP >PORT BIT2 >+#define >PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE >BIT30 >+#define >PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATE >D 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 specifi= ed by >BaseAddress and >+ Length from their current attributes to the attributes specified by Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @param PagingContext The paging context. NULL means get page table >from current CPU context. >+ @param BaseAddress The physical address that is the start addres= s 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 mem= ory >region. >+ @param AllocatePagesFunc If page split is needed, this function is use= d 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @param PagingContext The paging context. NULL means get page table >from current CPU context. >+ @param BaseAddress The physical address that is the start addres= s 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 mem= ory >region. >+ @param AllocatePagesFunc If page split is needed, this function is use= d 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 specifie= d by >BaseAddress and >+ Length from their current attributes to the attributes specified by Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @param PagingContext The paging context. NULL means get page table >from current CPU context. >+ @param BaseAddress The physical address that is the start addres= s 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 mem= ory >region. >+ @param AllocatePagesFunc If page split is needed, this function is use= d 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 specifie= d 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 addres= s of a >memory region. >+ @param Attributes The bit mask of attributes of the memory regi= on. >+ @param PageSize The size of the pages which contains the >BaseAddress. >+ >+ @retval RETURN_SUCCESS The Attributes and PageSize is returne= d. >+ @retval RETURN_INVALID_PARAMETER Both Attributes and PageSize are >zero. >+ @retval RETURN_NOT_FOUND The processor does not setup paging fo= r >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 B= SD >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_ACTIVATE >D; >+ } >+ } >+ } >+ if ((RegEdx & BIT26) !=3D 0) { >+ PagingContext->ContextData.Ia32.Attributes |=3D >PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUP >PORT; >+ } >+ } >+} >+ >+/** >+ 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 t= he >memory region. >+ @param[in] PageAction The page action. >+ @param[out] IsModified TRUE means page table modified. FALSE mean= s >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_ACTIVATE >D) !=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 is= 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 + ((*PageE= ntry) >& 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->4K >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 specif= ied >by BaseAddress and >+ Length from their current attributes to the attributes specified by Att= ributes. >+ >+ 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 ad= dress >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 is= used >to allocate more pages. >+ NULL mean page split is unsupported. >+ @param[out] IsSplitted TRUE means page table splitted. FALSE mea= ns >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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 memor= y. >+ // >+ 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 specifi= ed by >BaseAddress and >+ Length from their current attributes to the attributes specified by Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @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 ad= dress >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 the= memory >region. >+ @param[in] AllocatePagesFunc If page split is needed, this function is= 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @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 ad= dress >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 the= memory >region. >+ @param[in] AllocatePagesFunc If page split is needed, this function is= 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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, >&IsModified); >+ 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 specifie= d by >BaseAddress and >+ Length from their current attributes to the attributes specified by Att= ributes. >+ >+ Caller should make sure BaseAddress and Length is at page boundary. >+ >+ Caller need guarentee the TPL <=3D TPL_NOTIFY, if there is split page r= equest. >+ >+ @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 ad= dress >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 the= memory >region. >+ @param[in] AllocatePagesFunc If page split is needed, this function is= 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 modif= ied. >+ @retval RETURN_INVALID_PARAMETER Length is zero. >+ Attributes specified an illegal combin= ation 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 BaseAddres= s and Length. >+ The bit mask of attributes is not supp= ort for the memory >resource >+ range specified by BaseAddress and Len= gth. >+**/ >+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 specifie= d 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 ad= dress >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 returne= d. >+ @retval RETURN_INVALID_PARAMETER Both Attributes and PageSize are >zero. >+ @retval RETURN_NOT_FOUND The processor does not setup paging fo= r >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 > >_______________________________________________ >edk2-devel mailing list >edk2-devel@lists.01.org >https://lists.01.org/mailman/listinfo/edk2-devel