From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mx.groups.io with SMTP id smtpd.web12.27079.1658150325580236005 for ; Mon, 18 Jul 2022 06:18:45 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=ji3MXHYg; spf=pass (domain: intel.com, ip: 134.134.136.65, mailfrom: ray.ni@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1658150325; x=1689686325; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/zMQiByYUL4688eSxKn79TK7Jwj3D+qJZMm4xaUc1SA=; b=ji3MXHYgRgIxwvfTGYK8hZmiCqAsVcMqiz/MCMiSpBQzVGNFqly+hIaa qW5DvwGbLEegEIQL4/PGuAL6PXQpnZIAlHsjluytlwtU6OP9jgx9mdusm SW63au2+QXMYYbkYT4aOpOpGO3R1RhFd33K7muUHeuqTWSndd6Xd1O8fX 9XZyz0HeT/zh++YkfmL8drteVJa72K7azRl54kkTOzRFfzjsmwuqL4udp TY8o9e3xRJrbWrke8ndgCguhBHEK8BGqHTQMhZJTeS1bK5RCeZAynWPEI wIUJC+tLhFsqTuCM0RYXNEe37ZFigDfSmNJ5J8YPjWiUMQOstyn2a+PTN Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10411"; a="287363886" X-IronPort-AV: E=Sophos;i="5.92,281,1650956400"; d="scan'208";a="287363886" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Jul 2022 06:18:40 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.92,281,1650956400"; d="scan'208";a="624724945" Received: from shwdeopenlab706.ccr.corp.intel.com ([10.239.183.102]) by orsmga008.jf.intel.com with ESMTP; 18 Jul 2022 06:18:39 -0700 From: "Ni, Ray" To: devel@edk2.groups.io Cc: Eric Dong Subject: [PATCH 01/10] UefiCpuPkg: Create CpuPageTableLib for manipulating X86 paging structs Date: Mon, 18 Jul 2022 21:18:22 +0800 Message-Id: <20220718131831.660-2-ray.ni@intel.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20220718131831.660-1-ray.ni@intel.com> References: <20220718131831.660-1-ray.ni@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable The lib includes two APIs: * PageTableMap It creates/updates mapping from LA to PA. The implementation only supports paging structures used in 64bit mode now. PAE paging structure support will be added in future. * PageTableParse It parses the page table and returns the mapping relations in an array of IA32_MAP_ENTRY. It passed some stress tests. These test code will be upstreamed in other patches following edk2 Unit Test framework. Signed-off-by: Ray Ni Cc: Eric Dong --- UefiCpuPkg/Include/Library/CpuPageTableLib.h | 129 +++++ .../Library/CpuPageTableLib/CpuPageTable.h | 204 +++++++ .../CpuPageTableLib/CpuPageTableLib.inf | 35 ++ .../Library/CpuPageTableLib/CpuPageTableMap.c | 543 ++++++++++++++++++ .../CpuPageTableLib/CpuPageTableParse.c | 330 +++++++++++ UefiCpuPkg/UefiCpuPkg.dec | 3 + UefiCpuPkg/UefiCpuPkg.dsc | 4 +- 7 files changed, 1247 insertions(+), 1 deletion(-) create mode 100644 UefiCpuPkg/Include/Library/CpuPageTableLib.h create mode 100644 UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h create mode 100644 UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf create mode 100644 UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c create mode 100644 UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c diff --git a/UefiCpuPkg/Include/Library/CpuPageTableLib.h b/UefiCpuPkg/Incl= ude/Library/CpuPageTableLib.h new file mode 100644 index 0000000000..2dc9b7d18e --- /dev/null +++ b/UefiCpuPkg/Include/Library/CpuPageTableLib.h @@ -0,0 +1,129 @@ +/** @file=0D + Public include file for PageTableLib library.=0D +=0D + Copyright (c) 2022, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef PAGE_TABLE_LIB_H_=0D +#define PAGE_TABLE_LIB_H_=0D +=0D +typedef union {=0D + struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D + UINT64 ReadWrite : 1; // 0 =3D Read-Only, 1=3D Read/Writ= e=0D + UINT64 UserSupervisor : 1; // 0 =3D Supervisor, 1=3DUser=0D + UINT64 WriteThrough : 1; // 0 =3D Write-Back caching, 1=3DW= rite-Through caching=0D + UINT64 CacheDisabled : 1; // 0 =3D Cached, 1=3DNon-Cached=0D + UINT64 Accessed : 1; // 0 =3D Not accessed, 1 =3D Acces= sed (set by CPU)=0D + UINT64 Dirty : 1; // 0 =3D Not dirty, 1 =3D Dirty (s= et by CPU)=0D + UINT64 Pat : 1; // PAT=0D +=0D + UINT64 Global : 1; // 0 =3D Not global, 1 =3D Global = (if CR4.PGE =3D 1)=0D + UINT64 Reserved1 : 3; // Ignored=0D +=0D + UINT64 PageTableBaseAddress : 40; // Page Table Base Address=0D + UINT64 Reserved2 : 7; // Ignored=0D + UINT64 ProtectionKey : 4; // Protection key=0D + UINT64 Nx : 1; // No Execute bit=0D + } Bits;=0D + UINT64 Uint64;=0D +} IA32_MAP_ATTRIBUTE;=0D +=0D +#define IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK 0xFFFFFFFFFF000ul= l=0D +#define IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS(pa) ((pa)->Uint64 & IA= 32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK)=0D +#define IA32_MAP_ATTRIBUTE_ATTRIBUTES(pa) ((pa)->Uint64 & ~I= A32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK)=0D +=0D +//=0D +// Below enum follows "4.1.1 Four Paging Modes" in Chapter 4 Paging of SDM= Volume 3.=0D +// Page1GB is only supported in 4-level and 5-level.=0D +//=0D +typedef enum {=0D + Paging32bit,=0D +=0D + //=0D + // High byte in paging mode indicates the max levels of the page table.= =0D + // Low byte in paging mode indicates the max level that can be a leaf en= try.=0D + //=0D + PagingPae =3D 0x0302,=0D +=0D + Paging4Level =3D 0x0402,=0D + Paging4Level1GB =3D 0x0403,=0D +=0D + Paging5Level =3D 0x0502,=0D + Paging5Level1GB =3D 0x0503,=0D +=0D + PagingModeMax=0D +} PAGING_MODE;=0D +=0D +/**=0D + Create or update page table to map [LinearAddress, LinearAddress + Lengt= h) with specified attribute.=0D +=0D + @param[in, out] PageTable The pointer to the page table to update, = or pointer to NULL if a new page table is to be created.=0D + @param[in] PagingMode The paging mode.=0D + @param[in] Buffer The free buffer to be used for page table= creation/updating.=0D + @param[in, out] BufferSize The buffer size.=0D + On return, the remaining buffer size.=0D + The free buffer is used from the end so c= aller can supply the same Buffer pointer with an updated=0D + BufferSize in the second call to this API= .=0D + @param[in] LinearAddress The start of the linear address range.=0D + @param[in] Length The length of the linear address range.=0D + @param[in] Attribute The attribute of the linear address range= .=0D + All non-reserved fields in IA32_MAP_ATTRI= BUTE are supported to set in the page table.=0D + Page table entries that map the linear ad= dress range are reset to 0 before set to the new attribute=0D + when a new physical base address is set.= =0D + @param[in] Mask The mask used for attribute. The correspo= nding field in Attribute is ignored if that in Mask is 0.=0D +=0D + @retval RETURN_UNSUPPORTED PagingMode is not supported.=0D + @retval RETURN_INVALID_PARAMETER PageTable, BufferSize, Attribute or Ma= sk is NULL.=0D + @retval RETURN_INVALID_PARAMETER *BufferSize is not multiple of 4KB.=0D + @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for page table= creation/updating.=0D + BufferSize is updated to indicate the = expected buffer size.=0D + Caller may still get RETURN_BUFFER_TOO= _SMALL with the new BufferSize.=0D + @retval RETURN_SUCCESS PageTable is created/updated successfu= lly.=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +PageTableMap (=0D + IN OUT UINTN *PageTable OPTIONAL,=0D + IN PAGING_MODE PagingMode,=0D + IN VOID *Buffer,=0D + IN OUT UINTN *BufferSize,=0D + IN UINT64 LinearAddress,=0D + IN UINT64 Length,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + );=0D +=0D +typedef struct {=0D + UINT64 LinearAddress;=0D + UINT64 Length;=0D + IA32_MAP_ATTRIBUTE Attribute;=0D +} IA32_MAP_ENTRY;=0D +=0D +/**=0D + Parse page table.=0D +=0D + @param[in] PageTable Pointer to the page table.=0D + @param[in] PagingMode The paging mode.=0D + @param[out] Map Return an array that describes multiple linea= r address ranges.=0D + @param[in, out] MapCount On input, the maximum number of entries that = Map can hold.=0D + On output, the number of entries in Map.=0D +=0D + @retval RETURN_UNSUPPORTED PageLevel is not 5 or 4.=0D + @retval RETURN_INVALID_PARAMETER MapCount is NULL.=0D + @retval RETURN_INVALID_PARAMETER *MapCount is not 0 but Map is NULL.=0D + @retval RETURN_BUFFER_TOO_SMALL *MapCount is too small.=0D + @retval RETURN_SUCCESS Page table is parsed successfully.=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +PageTableParse (=0D + IN UINTN PageTable,=0D + IN PAGING_MODE PagingMode,=0D + IN IA32_MAP_ENTRY *Map,=0D + IN OUT UINTN *MapCount=0D + );=0D +=0D +#endif=0D diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h b/UefiCpuPkg= /Library/CpuPageTableLib/CpuPageTable.h new file mode 100644 index 0000000000..c041ea3f56 --- /dev/null +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h @@ -0,0 +1,204 @@ +/** @file=0D + Internal header for CpuPageTableLib.=0D +=0D + Copyright (c) 2022, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef CPU_PAGE_TABLE_H_=0D +#define CPU_PAGE_TABLE_H_=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define IA32_PE_BASE_ADDRESS_MASK_40 0xFFFFFFFFFF000ull=0D +#define IA32_PE_BASE_ADDRESS_MASK_39 0xFFFFFFFFFE000ull=0D +=0D +#define REGION_LENGTH(l) LShiftU64 (1, (l) * 9 + 3)=0D +=0D +typedef struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D +} IA32_PAGE_COMMON_ENTRY;=0D +=0D +///=0D +/// Format of a non-leaf entry that references a page table entry=0D +///=0D +typedef union {=0D + struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D + UINT64 ReadWrite : 1; // 0 =3D Read-Only, 1=3D Read/Writ= e=0D + UINT64 UserSupervisor : 1; // 0 =3D Supervisor, 1=3DUser=0D + UINT64 WriteThrough : 1; // 0 =3D Write-Back caching, 1=3DW= rite-Through caching=0D + UINT64 CacheDisabled : 1; // 0 =3D Cached, 1=3DNon-Cached=0D + UINT64 Accessed : 1; // 0 =3D Not accessed, 1 =3D Acces= sed (set by CPU)=0D + UINT64 Available0 : 1; // Ignored=0D + UINT64 MustBeZero : 1; // Must Be Zero=0D +=0D + UINT64 Available2 : 4; // Ignored=0D +=0D + UINT64 PageTableBaseAddress : 40; // Page Table Base Address=0D + UINT64 Available3 : 11; // Ignored=0D + UINT64 Nx : 1; // No Execute bit=0D + } Bits;=0D + UINT64 Uint64;=0D +} IA32_PAGE_NON_LEAF_ENTRY;=0D +=0D +#define IA32_PNLE_PAGE_TABLE_BASE_ADDRESS(pa) ((pa)->Uint64 & IA32_PE_BAS= E_ADDRESS_MASK_40)=0D +=0D +///=0D +/// Format of a PML5 Entry (PML5E) that References a PML4 Table=0D +///=0D +typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PML5E;=0D +=0D +///=0D +/// Format of a PML4 Entry (PML4E) that References a Page-Directory-Pointe= r Table=0D +///=0D +typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PML4E;=0D +=0D +///=0D +/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that References= a Page Directory=0D +///=0D +typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PDPTE;=0D +=0D +///=0D +/// Format of a Page-Directory Entry that References a Page Table=0D +///=0D +typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PDE;=0D +=0D +///=0D +/// Format of a leaf entry that Maps a 1-Gbyte or 2-MByte Page=0D +///=0D +typedef union {=0D + struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D + UINT64 ReadWrite : 1; // 0 =3D Read-Only, 1=3D Read/Writ= e=0D + UINT64 UserSupervisor : 1; // 0 =3D Supervisor, 1=3DUser=0D + UINT64 WriteThrough : 1; // 0 =3D Write-Back caching, 1=3DW= rite-Through caching=0D + UINT64 CacheDisabled : 1; // 0 =3D Cached, 1=3DNon-Cached=0D + UINT64 Accessed : 1; // 0 =3D Not accessed, 1 =3D Acces= sed (set by CPU)=0D + UINT64 Dirty : 1; // 0 =3D Not dirty, 1 =3D Dirty (s= et by CPU)=0D + UINT64 MustBeOne : 1; // Page Size. Must Be One=0D +=0D + UINT64 Global : 1; // 0 =3D Not global, 1 =3D Global = (if CR4.PGE =3D 1)=0D + UINT64 Available1 : 3; // Ignored=0D + UINT64 Pat : 1; // PAT=0D +=0D + UINT64 PageTableBaseAddress : 39; // Page Table Base Address=0D + UINT64 Available3 : 7; // Ignored=0D + UINT64 ProtectionKey : 4; // Protection key=0D + UINT64 Nx : 1; // No Execute bit=0D + } Bits;=0D + UINT64 Uint64;=0D +} IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE;=0D +#define IA32_PLEB_PAGE_TABLE_BASE_ADDRESS(pa) ((pa)->Uint64 & IA32_PE_BAS= E_ADDRESS_MASK_39)=0D +=0D +///=0D +/// Format of a Page-Directory Entry that Maps a 2-MByte Page=0D +///=0D +typedef IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE IA32_PDE_2M;=0D +=0D +///=0D +/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that Maps a 1-G= Byte Page=0D +///=0D +typedef IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE IA32_PDPTE_1G;=0D +=0D +///=0D +/// Format of a Page-Table Entry that Maps a 4-KByte Page=0D +///=0D +typedef union {=0D + struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D + UINT64 ReadWrite : 1; // 0 =3D Read-Only, 1=3D Read/Writ= e=0D + UINT64 UserSupervisor : 1; // 0 =3D Supervisor, 1=3DUser=0D + UINT64 WriteThrough : 1; // 0 =3D Write-Back caching, 1=3DW= rite-Through caching=0D + UINT64 CacheDisabled : 1; // 0 =3D Cached, 1=3DNon-Cached=0D + UINT64 Accessed : 1; // 0 =3D Not accessed, 1 =3D Acces= sed (set by CPU)=0D + UINT64 Dirty : 1; // 0 =3D Not dirty, 1 =3D Dirty (s= et by CPU)=0D + UINT64 Pat : 1; // PAT=0D +=0D + UINT64 Global : 1; // 0 =3D Not global, 1 =3D Global = (if CR4.PGE =3D 1)=0D + UINT64 Available1 : 3; // Ignored=0D +=0D + UINT64 PageTableBaseAddress : 40; // Page Table Base Address=0D + UINT64 Available3 : 7; // Ignored=0D + UINT64 ProtectionKey : 4; // Protection key=0D + UINT64 Nx : 1; // No Execute bit=0D + } Bits;=0D + UINT64 Uint64;=0D +} IA32_PTE_4K;=0D +#define IA32_PTE4K_PAGE_TABLE_BASE_ADDRESS(pa) ((pa)->Uint64 & IA32_PE_BA= SE_ADDRESS_MASK_40)=0D +=0D +///=0D +/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that References= a Page Directory (32bit PAE specific)=0D +///=0D +typedef union {=0D + struct {=0D + UINT64 Present : 1; // 0 =3D Not present in memory, 1 = =3D Present in memory=0D + UINT64 MustBeZero : 2; // Must Be Zero=0D + UINT64 WriteThrough : 1; // 0 =3D Write-Back caching, 1=3DW= rite-Through caching=0D + UINT64 CacheDisabled : 1; // 0 =3D Cached, 1=3DNon-Cached=0D + UINT64 MustBeZero2 : 4; // Must Be Zero=0D +=0D + UINT64 Available : 3; // Ignored=0D +=0D + UINT64 PageTableBaseAddress : 40; // Page Table Base Address=0D + UINT64 MustBeZero3 : 12; // Must Be Zero=0D + } Bits;=0D + UINT64 Uint64;=0D +} IA32_PDPTE_PAE;=0D +=0D +typedef union {=0D + IA32_PAGE_NON_LEAF_ENTRY Pnle; // To access Pml5, Pml4, Pdpt= e and Pde.=0D + IA32_PML5E Pml5;=0D + IA32_PML4E Pml4;=0D + IA32_PDPTE Pdpte;=0D + IA32_PDE Pde;=0D +=0D + IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE PleB; // to access Pdpte1G and Pde2= M.=0D + IA32_PDPTE_1G Pdpte1G;=0D + IA32_PDE_2M Pde2M;=0D +=0D + IA32_PTE_4K Pte4K;=0D +=0D + IA32_PDPTE_PAE PdptePae;=0D + IA32_PAGE_COMMON_ENTRY Pce; // To access all common bits i= n above entries.=0D +=0D + UINT64 Uint64;=0D + UINTN Uintn;=0D +} IA32_PAGING_ENTRY;=0D +=0D +/**=0D + Return TRUE when the page table entry is a leaf entry that points to the= physical address memory.=0D + Return FALSE when the page table entry is a non-leaf entry that points t= o the page table entries.=0D +=0D + @param[in] PagingEntry Pointer to the page table entry.=0D + @param[in] Level Page level where the page table entry resides in.= =0D +=0D + @retval TRUE It's a leaf entry.=0D + @retval FALSE It's a non-leaf entry.=0D +**/=0D +BOOLEAN=0D +IsPle (=0D + IN IA32_PAGING_ENTRY *PagingEntry,=0D + IN UINTN Level=0D + );=0D +=0D +/**=0D + Return the attribute of a 2M/1G page table entry.=0D +=0D + @param[in] PleB Pointer to a 2M/1G page table entry.=0D + @param[in] ParentMapAttribute Pointer to the parent attribute.=0D +=0D + @return Attribute of the 2M/1G page table entry.=0D +**/=0D +UINT64=0D +PageTableLibGetPleBMapAttribute (=0D + IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE *PleB,=0D + IN IA32_MAP_ATTRIBUTE *ParentMapAttribute=0D + );=0D +=0D +#endif=0D diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf b/UefiC= puPkg/Library/CpuPageTableLib/CpuPageTableLib.inf new file mode 100644 index 0000000000..e4ead7441c --- /dev/null +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf @@ -0,0 +1,35 @@ +## @file=0D +# This library implements CpuPageTableLib that are generic for IA32 famil= y CPU.=0D +#=0D +# Copyright (c) 2022, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D CpuPageTableLib=0D + FILE_GUID =3D 524ed6a1-f661-451b-929b-b54d755c914a= =0D + MODULE_TYPE =3D BASE=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D CpuPageTableLib=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +[Sources]=0D + CpuPageTableMap.c=0D + CpuPageTableParse.c=0D + CpuPageTable.h=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + UefiCpuPkg/UefiCpuPkg.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + BaseMemoryLib=0D + DebugLib=0D diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c b/UefiCpu= Pkg/Library/CpuPageTableLib/CpuPageTableMap.c new file mode 100644 index 0000000000..25e13a6f6f --- /dev/null +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c @@ -0,0 +1,543 @@ +/** @file=0D + This library implements CpuPageTableLib that are generic for IA32 family= CPU.=0D +=0D + Copyright (c) 2022, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "CpuPageTable.h"=0D +=0D +/**=0D + Set the IA32_PTE_4K.=0D +=0D + @param[in] Pte4K Pointer to IA32_PTE_4K.=0D + @param[in] Offset The offset within the linear address range.=0D + @param[in] Attribute The attribute of the linear address range.=0D + All non-reserved fields in IA32_MAP_ATTRIBUTE are s= upported to set in the page table.=0D + Page table entry is reset to 0 before set to the ne= w attribute when a new physical base address is set.=0D + @param[in] Mask The mask used for attribute. The corresponding fiel= d in Attribute is ignored if that in Mask is 0.=0D +**/=0D +VOID=0D +PageTableLibSetPte4K (=0D + IN IA32_PTE_4K *Pte4K,=0D + IN UINT64 Offset,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + )=0D +{=0D + if (Mask->Bits.PageTableBaseAddress) {=0D + //=0D + // Reset all attributes when the physical address is changed.=0D + //=0D + Pte4K->Uint64 =3D IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribut= e) + Offset;=0D + }=0D +=0D + if (Mask->Bits.Present) {=0D + Pte4K->Bits.Present =3D Attribute->Bits.Present;=0D + }=0D +=0D + if (Mask->Bits.ReadWrite) {=0D + Pte4K->Bits.ReadWrite =3D Attribute->Bits.ReadWrite;=0D + }=0D +=0D + if (Mask->Bits.UserSupervisor) {=0D + Pte4K->Bits.UserSupervisor =3D Attribute->Bits.UserSupervisor;=0D + }=0D +=0D + if (Mask->Bits.WriteThrough) {=0D + Pte4K->Bits.WriteThrough =3D Attribute->Bits.WriteThrough;=0D + }=0D +=0D + if (Mask->Bits.CacheDisabled) {=0D + Pte4K->Bits.CacheDisabled =3D Attribute->Bits.CacheDisabled;=0D + }=0D +=0D + if (Mask->Bits.Accessed) {=0D + Pte4K->Bits.Accessed =3D Attribute->Bits.Accessed;=0D + }=0D +=0D + if (Mask->Bits.Dirty) {=0D + Pte4K->Bits.Dirty =3D Attribute->Bits.Dirty;=0D + }=0D +=0D + if (Mask->Bits.Pat) {=0D + Pte4K->Bits.Pat =3D Attribute->Bits.Pat;=0D + }=0D +=0D + if (Mask->Bits.Global) {=0D + Pte4K->Bits.Global =3D Attribute->Bits.Global;=0D + }=0D +=0D + if (Mask->Bits.ProtectionKey) {=0D + Pte4K->Bits.ProtectionKey =3D Attribute->Bits.ProtectionKey;=0D + }=0D +=0D + if (Mask->Bits.Nx) {=0D + Pte4K->Bits.Nx =3D Attribute->Bits.Nx;=0D + }=0D +}=0D +=0D +/**=0D + Set the IA32_PDPTE_1G or IA32_PDE_2M.=0D +=0D + @param[in] PleB Pointer to PDPTE_1G or PDE_2M. Both share the same = structure definition.=0D + @param[in] Offset The offset within the linear address range.=0D + @param[in] Attribute The attribute of the linear address range.=0D + All non-reserved fields in IA32_MAP_ATTRIBUTE are s= upported to set in the page table.=0D + Page table entry is reset to 0 before set to the ne= w attribute when a new physical base address is set.=0D + @param[in] Mask The mask used for attribute. The corresponding fiel= d in Attribute is ignored if that in Mask is 0.=0D +**/=0D +VOID=0D +PageTableLibSetPleB (=0D + IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE *PleB,=0D + IN UINT64 Offset,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + )=0D +{=0D + if (Mask->Bits.PageTableBaseAddress) {=0D + //=0D + // Reset all attributes when the physical address is changed.=0D + //=0D + PleB->Uint64 =3D IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute= ) + Offset;=0D + }=0D +=0D + PleB->Bits.MustBeOne =3D 1;=0D +=0D + if (Mask->Bits.Present) {=0D + PleB->Bits.Present =3D Attribute->Bits.Present;=0D + }=0D +=0D + if (Mask->Bits.ReadWrite) {=0D + PleB->Bits.ReadWrite =3D Attribute->Bits.ReadWrite;=0D + }=0D +=0D + if (Mask->Bits.UserSupervisor) {=0D + PleB->Bits.UserSupervisor =3D Attribute->Bits.UserSupervisor;=0D + }=0D +=0D + if (Mask->Bits.WriteThrough) {=0D + PleB->Bits.WriteThrough =3D Attribute->Bits.WriteThrough;=0D + }=0D +=0D + if (Mask->Bits.CacheDisabled) {=0D + PleB->Bits.CacheDisabled =3D Attribute->Bits.CacheDisabled;=0D + }=0D +=0D + if (Mask->Bits.Accessed) {=0D + PleB->Bits.Accessed =3D Attribute->Bits.Accessed;=0D + }=0D +=0D + if (Mask->Bits.Dirty) {=0D + PleB->Bits.Dirty =3D Attribute->Bits.Dirty;=0D + }=0D +=0D + if (Mask->Bits.Pat) {=0D + PleB->Bits.Pat =3D Attribute->Bits.Pat;=0D + }=0D +=0D + if (Mask->Bits.Global) {=0D + PleB->Bits.Global =3D Attribute->Bits.Global;=0D + }=0D +=0D + if (Mask->Bits.ProtectionKey) {=0D + PleB->Bits.ProtectionKey =3D Attribute->Bits.ProtectionKey;=0D + }=0D +=0D + if (Mask->Bits.Nx) {=0D + PleB->Bits.Nx =3D Attribute->Bits.Nx;=0D + }=0D +}=0D +=0D +/**=0D + Set the IA32_PDPTE_1G, IA32_PDE_2M or IA32_PTE_4K.=0D +=0D + @param[in] Level 3, 2 or 1.=0D + @param[in] Ple Pointer to PDPTE_1G, PDE_2M or IA32_PTE_4K, dependi= ng on the Level.=0D + @param[in] Offset The offset within the linear address range.=0D + @param[in] Attribute The attribute of the linear address range.=0D + All non-reserved fields in IA32_MAP_ATTRIBUTE are s= upported to set in the page table.=0D + Page table entry is reset to 0 before set to the ne= w attribute when a new physical base address is set.=0D + @param[in] Mask The mask used for attribute. The corresponding fiel= d in Attribute is ignored if that in Mask is 0.=0D +**/=0D +VOID=0D +PageTableLibSetPle (=0D + IN UINTN Level,=0D + IN IA32_PAGING_ENTRY *Ple,=0D + IN UINT64 Offset,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + )=0D +{=0D + if (Level =3D=3D 1) {=0D + PageTableLibSetPte4K (&Ple->Pte4K, Offset, Attribute, Mask);=0D + } else {=0D + ASSERT (Level =3D=3D 2 || Level =3D=3D 3);=0D + PageTableLibSetPleB (&Ple->PleB, Offset, Attribute, Mask);=0D + }=0D +}=0D +=0D +/**=0D + Set the IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE.=0D +=0D + @param[in] Pnle Pointer to IA32_PML5, IA32_PML4, IA32_PDPTE or IA32= _PDE. All share the same structure definition.=0D + @param[in] Attribute The attribute of the page directory referenced by t= he non-leaf.=0D +**/=0D +VOID=0D +PageTableLibSetPnle (=0D + IN IA32_PAGE_NON_LEAF_ENTRY *Pnle,=0D + IN IA32_MAP_ATTRIBUTE *Attribute=0D + )=0D +{=0D + Pnle->Bits.Present =3D Attribute->Bits.Present;=0D + Pnle->Bits.ReadWrite =3D Attribute->Bits.ReadWrite;=0D + Pnle->Bits.UserSupervisor =3D Attribute->Bits.UserSupervisor;=0D + Pnle->Bits.Nx =3D Attribute->Bits.Nx;=0D + Pnle->Bits.Accessed =3D 0;=0D +=0D + //=0D + // Set the attributes (WT, CD, A) to 0.=0D + // WT and CD determin the memory type used to access the 4K page directo= ry referenced by this entry.=0D + // So, it implictly requires PAT[0] is Write Back.=0D + // Create a new parameter if caller requires to use a different memory t= ype for accessing page directories.=0D + //=0D + Pnle->Bits.WriteThrough =3D 0;=0D + Pnle->Bits.CacheDisabled =3D 0;=0D +}=0D +=0D +/**=0D + Update page table to map [LinearAddress, LinearAddress + Length) with sp= ecified attribute in the specified level.=0D +=0D + @param[in] ParentPagingEntry The pointer to the page table entry to= update.=0D + @param[in] Modify FALSE to indicate Buffer is not used a= nd BufferSize is increased by the required buffer size.=0D + @param[in] Buffer The free buffer to be used for page ta= ble creation/updating.=0D + When Modify is TRUE, it's used from th= e end.=0D + When Modify is FALSE, it's ignored.=0D + @param[in, out] BufferSize The available buffer size.=0D + Return the remaining buffer size.=0D + @param[in] Level Page table level. Could be 5, 4, 3, 2,= or 1.=0D + @param[in] MaxLeafLevel Maximum level that can be a leaf entry= . Could be 1, 2 or 3 (if Page 1G is supported).=0D + @param[in] LinearAddress The start of the linear address range.= =0D + @param[in] Length The length of the linear address range= .=0D + @param[in] Offset The offset within the linear address r= ange.=0D + @param[in] Attribute The attribute of the linear address ra= nge.=0D + All non-reserved fields in IA32_MAP_AT= TRIBUTE are supported to set in the page table.=0D + Page table entries that map the linear= address range are reset to 0 before set to the new attribute=0D + when a new physical base address is se= t.=0D + @param[in] Mask The mask used for attribute. The corre= sponding field in Attribute is ignored if that in Mask is 0.=0D +=0D + @retval RETURN_SUCCESS PageTable is created/updated successfu= lly.=0D +**/=0D +RETURN_STATUS=0D +PageTableLibMapInLevel (=0D + IN IA32_PAGING_ENTRY *ParentPagingEntry,=0D + IN BOOLEAN Modify,=0D + IN VOID *Buffer,=0D + IN OUT INTN *BufferSize,=0D + IN UINTN Level,=0D + IN UINTN MaxLeafLevel,=0D + IN UINT64 LinearAddress,=0D + IN UINT64 Length,=0D + IN UINT64 Offset,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + )=0D +{=0D + RETURN_STATUS Status;=0D + UINTN BitStart;=0D + UINTN Index;=0D + IA32_PAGING_ENTRY *PagingEntry;=0D + UINT64 RegionLength;=0D + UINT64 SubLength;=0D + UINT64 SubOffset;=0D + UINT64 RegionMask;=0D + UINT64 RegionStart;=0D + IA32_MAP_ATTRIBUTE AllOneMask;=0D + IA32_MAP_ATTRIBUTE PleBAttribute;=0D + IA32_MAP_ATTRIBUTE NopAttribute;=0D + BOOLEAN CreateNew;=0D + IA32_PAGING_ENTRY OneOfPagingEntry;=0D +=0D + ASSERT (Level !=3D 0);=0D + ASSERT ((Attribute !=3D NULL) && (Mask !=3D NULL));=0D +=0D + CreateNew =3D FALSE;=0D + AllOneMask.Uint64 =3D ~0ull;=0D +=0D + NopAttribute.Uint64 =3D 0;=0D + NopAttribute.Bits.Present =3D 1;=0D + NopAttribute.Bits.ReadWrite =3D 1;=0D + NopAttribute.Bits.UserSupervisor =3D 1;=0D +=0D + //=0D + // ParentPagingEntry ONLY is deferenced for checking Present and MustBeO= ne bits=0D + // when Modify is FALSE.=0D + //=0D +=0D + if (ParentPagingEntry->Pce.Present =3D=3D 0) {=0D + //=0D + // The parent entry is CR3 or PML5E/PML4E/PDPTE/PDE.=0D + // It does NOT point to an existing page directory.=0D + //=0D + ASSERT (Buffer =3D=3D NULL || *BufferSize >=3D SIZE_4KB);=0D + CreateNew =3D TRUE;=0D + *BufferSize -=3D SIZE_4KB;=0D +=0D + if (Modify) {=0D + ParentPagingEntry->Uintn =3D (UINTN)Buffer + *BufferSize;=0D + ZeroMem ((VOID *)ParentPagingEntry->Uintn, SIZE_4KB);=0D + //=0D + // Set default attribute bits for PML5E/PML4E/PDPTE/PDE.=0D + //=0D + PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute);=0D + } else {=0D + //=0D + // Just make sure Present and MustBeZero (PageSize) bits are accurat= e.=0D + //=0D + OneOfPagingEntry.Pnle.Uint64 =3D 0;=0D + }=0D + } else if (IsPle (ParentPagingEntry, Level + 1)) {=0D + //=0D + // The parent entry is a PDPTE_1G or PDE_2M. Split to 2M or 4K pages.= =0D + // Note: it's impossible the parent entry is a PTE_4K.=0D + //=0D + //=0D + // Use NOP attributes as the attribute of grand-parents because CPU wi= ll consider=0D + // the actual attributes of grand-parents when determing the memory ty= pe.=0D + //=0D + PleBAttribute.Uint64 =3D PageTableLibGetPleBMapAttribute (&ParentPagin= gEntry->PleB, &NopAttribute);=0D + if ((IA32_MAP_ATTRIBUTE_ATTRIBUTES (&PleBAttribute) & IA32_MAP_ATTRIBU= TE_ATTRIBUTES (Mask))=0D + =3D=3D IA32_MAP_ATTRIBUTE_ATTRIBUTES (Attribute))=0D + {=0D + //=0D + // This function is called when the memory length is less than the r= egion length of the parent level.=0D + // No need to split the page when the attributes equal.=0D + //=0D + return RETURN_SUCCESS;=0D + }=0D +=0D + ASSERT (Buffer =3D=3D NULL || *BufferSize >=3D SIZE_4KB);=0D + CreateNew =3D TRUE;=0D + *BufferSize -=3D SIZE_4KB;=0D + PageTableLibSetPle (Level, &OneOfPagingEntry, 0, &PleBAttribute, &AllO= neMask);=0D + if (Modify) {=0D + //=0D + // Create 512 child-level entries that map to 2M/4K.=0D + //=0D + ParentPagingEntry->Uintn =3D (UINTN)Buffer + *BufferSize;=0D + ZeroMem ((VOID *)ParentPagingEntry->Uintn, SIZE_4KB);=0D +=0D + //=0D + // Set NOP attributes=0D + // Note: Should NOT inherit the attributes from the original entry b= ecause a zero RW bit=0D + // will make the entire region read-only even the child entrie= s set the RW bit.=0D + //=0D + PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute);=0D +=0D + RegionLength =3D REGION_LENGTH (Level);=0D + PagingEntry =3D (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BA= SE_ADDRESS (&ParentPagingEntry->Pnle);=0D + for (SubOffset =3D 0, Index =3D 0; Index < 512; Index++) {=0D + PagingEntry[Index].Uint64 =3D OneOfPagingEntry.Uint64 + SubOffset;= =0D + SubOffset +=3D RegionLength;=0D + }=0D + }=0D + }=0D +=0D + //=0D + // RegionLength: 256T (1 << 48) 512G (1 << 39), 1G (1 << 30), 2M (1 << 2= 1) or 4K (1 << 12).=0D + // RegionStart: points to the linear address that's aligned on RegionLe= ngth and lower than (LinearAddress + Offset).=0D + //=0D + BitStart =3D 12 + (Level - 1) * 9;=0D + Index =3D BitFieldRead64 (LinearAddress + Offset, BitStart, BitSt= art + 9 - 1);=0D + RegionLength =3D LShiftU64 (1, BitStart);=0D + RegionMask =3D RegionLength - 1;=0D + RegionStart =3D (LinearAddress + Offset) & ~RegionMask;=0D +=0D + //=0D + // Apply the attribute.=0D + //=0D + PagingEntry =3D (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_AD= DRESS (&ParentPagingEntry->Pnle);=0D + while (Offset < Length && Index < 512) {=0D + SubLength =3D MIN (Length - Offset, RegionStart + RegionLength - (Line= arAddress + Offset));=0D + if ((Level <=3D MaxLeafLevel) && (LinearAddress + Offset =3D=3D Region= Start) && (SubLength =3D=3D RegionLength)) {=0D + //=0D + // Create one entry mapping the entire region (1G, 2M or 4K).=0D + //=0D + if (Modify) {=0D + PageTableLibSetPle (Level, &PagingEntry[Index], Offset, Attribute,= Mask);=0D + }=0D + } else {=0D + //=0D + // Recursively call to create page table.=0D + // There are 3 cases:=0D + // a. Level cannot be a leaf entry which points to physical memory= .=0D + // a. Level can be a leaf entry but (LinearAddress + Offset) is NO= T aligned on the RegionStart.=0D + // b. Level can be a leaf entry and (LinearAddress + Offset) is al= igned on RegionStart,=0D + // but the length is SMALLER than the RegionLength.=0D + //=0D + Status =3D PageTableLibMapInLevel (=0D + (!Modify && CreateNew) ? &OneOfPagingEntry : &PagingEntry= [Index],=0D + Modify,=0D + Buffer,=0D + BufferSize,=0D + Level - 1,=0D + MaxLeafLevel,=0D + LinearAddress,=0D + Length,=0D + Offset,=0D + Attribute,=0D + Mask=0D + );=0D + if (RETURN_ERROR (Status)) {=0D + return Status;=0D + }=0D + }=0D +=0D + Offset +=3D SubLength;=0D + RegionStart +=3D RegionLength;=0D + Index++;=0D + }=0D +=0D + return RETURN_SUCCESS;=0D +}=0D +=0D +/**=0D + Create or update page table to map [LinearAddress, LinearAddress + Lengt= h) with specified attribute.=0D +=0D + @param[in, out] PageTable The pointer to the page table to update, = or pointer to NULL if a new page table is to be created.=0D + @param[in] PagingMode The paging mode.=0D + @param[in] Buffer The free buffer to be used for page table= creation/updating.=0D + @param[in, out] BufferSize The buffer size.=0D + On return, the remaining buffer size.=0D + The free buffer is used from the end so c= aller can supply the same Buffer pointer with an updated=0D + BufferSize in the second call to this API= .=0D + @param[in] LinearAddress The start of the linear address range.=0D + @param[in] Length The length of the linear address range.=0D + @param[in] Attribute The attribute of the linear address range= .=0D + All non-reserved fields in IA32_MAP_ATTRI= BUTE are supported to set in the page table.=0D + Page table entries that map the linear ad= dress range are reset to 0 before set to the new attribute=0D + when a new physical base address is set.= =0D + @param[in] Mask The mask used for attribute. The correspo= nding field in Attribute is ignored if that in Mask is 0.=0D +=0D + @retval RETURN_UNSUPPORTED PagingMode is not supported.=0D + @retval RETURN_INVALID_PARAMETER PageTable, BufferSize, Attribute or Ma= sk is NULL.=0D + @retval RETURN_INVALID_PARAMETER *BufferSize is not multiple of 4KB.=0D + @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for page table= creation/updating.=0D + BufferSize is updated to indicate the = expected buffer size.=0D + Caller may still get RETURN_BUFFER_TOO= _SMALL with the new BufferSize.=0D + @retval RETURN_SUCCESS PageTable is created/updated successfu= lly.=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +PageTableMap (=0D + IN OUT UINTN *PageTable OPTIONAL,=0D + IN PAGING_MODE PagingMode,=0D + IN VOID *Buffer,=0D + IN OUT UINTN *BufferSize,=0D + IN UINT64 LinearAddress,=0D + IN UINT64 Length,=0D + IN IA32_MAP_ATTRIBUTE *Attribute,=0D + IN IA32_MAP_ATTRIBUTE *Mask=0D + )=0D +{=0D + RETURN_STATUS Status;=0D + IA32_PAGING_ENTRY TopPagingEntry;=0D + INTN RequiredSize;=0D + UINT64 MaxLinearAddress;=0D + UINTN MaxLevel;=0D + UINTN MaxLeafLevel;=0D +=0D + if ((PagingMode =3D=3D Paging32bit) || (PagingMode =3D=3D PagingPae) || = (PagingMode >=3D PagingModeMax)) {=0D + //=0D + // 32bit paging is never supported.=0D + // PAE paging will be supported later.=0D + //=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + if ((PageTable =3D=3D NULL) || (BufferSize =3D=3D NULL) || (Attribute = =3D=3D NULL) || (Mask =3D=3D NULL)) {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + if (*BufferSize % SIZE_4KB !=3D 0) {=0D + //=0D + // BufferSize should be multiple of 4K.=0D + //=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + if ((*BufferSize !=3D 0) && (Buffer =3D=3D NULL)) {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + MaxLeafLevel =3D (UINT8)PagingMode;=0D + MaxLevel =3D (UINT8)(PagingMode >> 8);=0D + MaxLinearAddress =3D LShiftU64 (1, 12 + MaxLevel * 9);=0D +=0D + if ((LinearAddress > MaxLinearAddress) || (Length > MaxLinearAddress - L= inearAddress)) {=0D + //=0D + // Maximum linear address is (1 << 48) or (1 << 57)=0D + //=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + TopPagingEntry.Uintn =3D *PageTable;=0D + if (TopPagingEntry.Uintn !=3D 0) {=0D + TopPagingEntry.Pce.Present =3D 1;=0D + }=0D +=0D + //=0D + // Query the required buffer size without modifying the page table.=0D + //=0D + RequiredSize =3D 0;=0D + Status =3D PageTableLibMapInLevel (=0D + &TopPagingEntry,=0D + FALSE,=0D + NULL,=0D + &RequiredSize,=0D + MaxLevel,=0D + MaxLeafLevel,=0D + LinearAddress,=0D + Length,=0D + 0,=0D + Attribute,=0D + Mask=0D + );=0D + if (RETURN_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + RequiredSize =3D -RequiredSize;=0D +=0D + if ((UINTN)RequiredSize > *BufferSize) {=0D + *BufferSize =3D RequiredSize;=0D + return RETURN_BUFFER_TOO_SMALL;=0D + }=0D +=0D + if ((RequiredSize !=3D 0) && (Buffer =3D=3D NULL)) {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Update the page table when the supplied buffer is sufficient.=0D + //=0D + Status =3D PageTableLibMapInLevel (=0D + &TopPagingEntry,=0D + TRUE,=0D + Buffer,=0D + BufferSize,=0D + MaxLevel,=0D + MaxLeafLevel,=0D + LinearAddress,=0D + Length,=0D + 0,=0D + Attribute,=0D + Mask=0D + );=0D + if (!RETURN_ERROR (Status)) {=0D + *PageTable =3D (UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MAS= K_40);=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c b/UefiC= puPkg/Library/CpuPageTableLib/CpuPageTableParse.c new file mode 100644 index 0000000000..e66961e122 --- /dev/null +++ b/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c @@ -0,0 +1,330 @@ +/** @file=0D + This library implements CpuPageTableLib that are generic for IA32 family= CPU.=0D +=0D + Copyright (c) 2022, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "CpuPageTable.h"=0D +=0D +/**=0D + Return the attribute of a 2M/1G page table entry.=0D +=0D + @param[in] PleB Pointer to a 2M/1G page table entry.=0D + @param[in] ParentMapAttribute Pointer to the parent attribute.=0D +=0D + @return Attribute of the 2M/1G page table entry.=0D +**/=0D +UINT64=0D +PageTableLibGetPleBMapAttribute (=0D + IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE *PleB,=0D + IN IA32_MAP_ATTRIBUTE *ParentMapAttribute=0D + )=0D +{=0D + IA32_MAP_ATTRIBUTE MapAttribute;=0D +=0D + //=0D + // PageTableBaseAddress cannot be assigned field to field=0D + // because their bit positions are different in IA32_MAP_ATTRIBUTE and I= A32_PAGE_LEAF_ENTRY_BIG_PAGESIZE.=0D + //=0D + MapAttribute.Uint64 =3D IA32_PLEB_PAGE_TABLE_BASE_ADDRESS (PleB);=0D +=0D + MapAttribute.Bits.Present =3D ParentMapAttribute->Bits.Present & = PleB->Bits.Present;=0D + MapAttribute.Bits.ReadWrite =3D ParentMapAttribute->Bits.ReadWrite = & PleB->Bits.ReadWrite;=0D + MapAttribute.Bits.UserSupervisor =3D ParentMapAttribute->Bits.UserSuperv= isor & PleB->Bits.UserSupervisor;=0D + MapAttribute.Bits.Nx =3D ParentMapAttribute->Bits.Nx | PleB-= >Bits.Nx;=0D + MapAttribute.Bits.WriteThrough =3D PleB->Bits.WriteThrough;=0D + MapAttribute.Bits.CacheDisabled =3D PleB->Bits.CacheDisabled;=0D + MapAttribute.Bits.Accessed =3D PleB->Bits.Accessed;=0D +=0D + MapAttribute.Bits.Pat =3D PleB->Bits.Pat;=0D + MapAttribute.Bits.Dirty =3D PleB->Bits.Dirty;=0D + MapAttribute.Bits.Global =3D PleB->Bits.Global;=0D + MapAttribute.Bits.ProtectionKey =3D PleB->Bits.ProtectionKey;=0D +=0D + return MapAttribute.Uint64;=0D +}=0D +=0D +/**=0D + Return the attribute of a 4K page table entry.=0D +=0D + @param[in] Pte4K Pointer to a 4K page table entry.=0D + @param[in] ParentMapAttribute Pointer to the parent attribute.=0D +=0D + @return Attribute of the 4K page table entry.=0D +**/=0D +UINT64=0D +PageTableLibGetPte4KMapAttribute (=0D + IN IA32_PTE_4K *Pte4K,=0D + IN IA32_MAP_ATTRIBUTE *ParentMapAttribute=0D + )=0D +{=0D + IA32_MAP_ATTRIBUTE MapAttribute;=0D +=0D + MapAttribute.Uint64 =3D IA32_PTE4K_PAGE_TABLE_BASE_ADDRESS (Pte4K);=0D +=0D + MapAttribute.Bits.Present =3D ParentMapAttribute->Bits.Present & = Pte4K->Bits.Present;=0D + MapAttribute.Bits.ReadWrite =3D ParentMapAttribute->Bits.ReadWrite = & Pte4K->Bits.ReadWrite;=0D + MapAttribute.Bits.UserSupervisor =3D ParentMapAttribute->Bits.UserSuperv= isor & Pte4K->Bits.UserSupervisor;=0D + MapAttribute.Bits.Nx =3D ParentMapAttribute->Bits.Nx | Pte4K= ->Bits.Nx;=0D + MapAttribute.Bits.WriteThrough =3D Pte4K->Bits.WriteThrough;=0D + MapAttribute.Bits.CacheDisabled =3D Pte4K->Bits.CacheDisabled;=0D + MapAttribute.Bits.Accessed =3D Pte4K->Bits.Accessed;=0D +=0D + MapAttribute.Bits.Pat =3D Pte4K->Bits.Pat;=0D + MapAttribute.Bits.Dirty =3D Pte4K->Bits.Dirty;=0D + MapAttribute.Bits.Global =3D Pte4K->Bits.Global;=0D + MapAttribute.Bits.ProtectionKey =3D Pte4K->Bits.ProtectionKey;=0D +=0D + return MapAttribute.Uint64;=0D +}=0D +=0D +/**=0D + Return the attribute of a non-leaf page table entry.=0D +=0D + @param[in] Pnle Pointer to a non-leaf page table entry.=0D + @param[in] ParentMapAttribute Pointer to the parent attribute.=0D +=0D + @return Attribute of the non-leaf page table entry.=0D +**/=0D +UINT64=0D +PageTableLibGetPnleMapAttribute (=0D + IN IA32_PAGE_NON_LEAF_ENTRY *Pnle,=0D + IN IA32_MAP_ATTRIBUTE *ParentMapAttribute=0D + )=0D +{=0D + IA32_MAP_ATTRIBUTE MapAttribute;=0D +=0D + MapAttribute.Uint64 =3D Pnle->Uint64;=0D +=0D + MapAttribute.Bits.Present =3D ParentMapAttribute->Bits.Present & = Pnle->Bits.Present;=0D + MapAttribute.Bits.ReadWrite =3D ParentMapAttribute->Bits.ReadWrite = & Pnle->Bits.ReadWrite;=0D + MapAttribute.Bits.UserSupervisor =3D ParentMapAttribute->Bits.UserSuperv= isor & Pnle->Bits.UserSupervisor;=0D + MapAttribute.Bits.Nx =3D ParentMapAttribute->Bits.Nx | Pnle-= >Bits.Nx;=0D + MapAttribute.Bits.WriteThrough =3D Pnle->Bits.WriteThrough;=0D + MapAttribute.Bits.CacheDisabled =3D Pnle->Bits.CacheDisabled;=0D + MapAttribute.Bits.Accessed =3D Pnle->Bits.Accessed;=0D + return MapAttribute.Uint64;=0D +}=0D +=0D +/**=0D + Return TRUE when the page table entry is a leaf entry that points to the= physical address memory.=0D + Return FALSE when the page table entry is a non-leaf entry that points t= o the page table entries.=0D +=0D + @param[in] PagingEntry Pointer to the page table entry.=0D + @param[in] Level Page level where the page table entry resides in.= =0D +=0D + @retval TRUE It's a leaf entry.=0D + @retval FALSE It's a non-leaf entry.=0D +**/=0D +BOOLEAN=0D +IsPle (=0D + IN IA32_PAGING_ENTRY *PagingEntry,=0D + IN UINTN Level=0D + )=0D +{=0D + //=0D + // PML5E and PML4E are always non-leaf entries.=0D + //=0D + if (Level =3D=3D 1) {=0D + return TRUE;=0D + }=0D +=0D + if (((Level =3D=3D 3) || (Level =3D=3D 2))) {=0D + if (PagingEntry->PleB.Bits.MustBeOne =3D=3D 1) {=0D + return TRUE;=0D + }=0D + }=0D +=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Recursively parse the non-leaf page table entries.=0D +=0D + @param[in] PageTableBaseAddress The base address of the 512 non-lea= f page table entries in the specified level.=0D + @param[in] Level Page level. Could be 5, 4, 3, 2, 1.= =0D + @param[in] RegionStart The base linear address of the regi= on covered by the non-leaf page table entries.=0D + @param[in] ParentMapAttribute The mapping attribute of the parent= entries.=0D + @param[in, out] Map Pointer to an array that describes = multiple linear address ranges.=0D + @param[in, out] MapCount Pointer to a UINTN that hold the ac= tual number of entries in the Map.=0D + @param[in] MapCapacity The maximum number of entries the M= ap can hold.=0D + @param[in] LastEntry Pointer to last map entry.=0D + @param[in] OneEntry Pointer to a library internal stora= ge that holds one map entry.=0D + It's used when Map array is used up= .=0D +**/=0D +VOID=0D +PageTableLibParsePnle (=0D + IN UINT64 PageTableBaseAddress,=0D + IN UINTN Level,=0D + IN UINT64 RegionStart,=0D + IN IA32_MAP_ATTRIBUTE *ParentMapAttribute,=0D + IN OUT IA32_MAP_ENTRY *Map,=0D + IN OUT UINTN *MapCount,=0D + IN UINTN MapCapacity,=0D + IN IA32_MAP_ENTRY **LastEntry,=0D + IN IA32_MAP_ENTRY *OneEntry=0D + )=0D +{=0D + IA32_PAGING_ENTRY *PagingEntry;=0D + UINTN Index;=0D + IA32_MAP_ATTRIBUTE MapAttribute;=0D + UINT64 RegionLength;=0D +=0D + ASSERT (OneEntry !=3D NULL);=0D +=0D + PagingEntry =3D (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;=0D + RegionLength =3D REGION_LENGTH (Level);=0D +=0D + for (Index =3D 0; Index < 512; Index++, RegionStart +=3D RegionLength) {= =0D + if (PagingEntry[Index].Pce.Present =3D=3D 0) {=0D + continue;=0D + }=0D +=0D + if (IsPle (&PagingEntry[Index], Level)) {=0D + ASSERT (Level =3D=3D 1 || Level =3D=3D 2 || Level =3D=3D 3);=0D +=0D + if (Level =3D=3D 1) {=0D + MapAttribute.Uint64 =3D PageTableLibGetPte4KMapAttribute (&PagingE= ntry[Index].Pte4K, ParentMapAttribute);=0D + } else {=0D + MapAttribute.Uint64 =3D PageTableLibGetPleBMapAttribute (&PagingEn= try[Index].PleB, ParentMapAttribute);=0D + }=0D +=0D + if ((*LastEntry !=3D NULL) &&=0D + ((*LastEntry)->LinearAddress + (*LastEntry)->Length =3D=3D Regio= nStart) &&=0D + (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&(*LastEntry)->Attr= ibute) + (*LastEntry)->Length=0D + =3D=3D IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&MapAttribut= e)) &&=0D + (IA32_MAP_ATTRIBUTE_ATTRIBUTES (&(*LastEntry)->Attribute) =3D=3D= IA32_MAP_ATTRIBUTE_ATTRIBUTES (&MapAttribute))=0D + )=0D + {=0D + //=0D + // Extend LastEntry.=0D + //=0D + (*LastEntry)->Length +=3D RegionLength;=0D + } else {=0D + if (*MapCount < MapCapacity) {=0D + //=0D + // LastEntry points to next map entry in the array.=0D + //=0D + *LastEntry =3D &Map[*MapCount];=0D + } else {=0D + //=0D + // LastEntry points to library internal map entry.=0D + //=0D + *LastEntry =3D OneEntry;=0D + }=0D +=0D + //=0D + // Set LastEntry.=0D + //=0D + (*LastEntry)->LinearAddress =3D RegionStart;=0D + (*LastEntry)->Length =3D RegionLength;=0D + (*LastEntry)->Attribute.Uint64 =3D MapAttribute.Uint64;=0D + (*MapCount)++;=0D + }=0D + } else {=0D + MapAttribute.Uint64 =3D PageTableLibGetPnleMapAttribute (&PagingEntr= y[Index].Pnle, ParentMapAttribute);=0D + PageTableLibParsePnle (=0D + IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),=0D + Level - 1,=0D + RegionStart,=0D + &MapAttribute,=0D + Map,=0D + MapCount,=0D + MapCapacity,=0D + LastEntry,=0D + OneEntry=0D + );=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Parse page table.=0D +=0D + @param[in] PageTable Pointer to the page table.=0D + @param[in] PagingMode The paging mode.=0D + @param[out] Map Return an array that describes multiple linea= r address ranges.=0D + @param[in, out] MapCount On input, the maximum number of entries that = Map can hold.=0D + On output, the number of entries in Map.=0D +=0D + @retval RETURN_UNSUPPORTED PageLevel is not 5 or 4.=0D + @retval RETURN_INVALID_PARAMETER MapCount is NULL.=0D + @retval RETURN_INVALID_PARAMETER *MapCount is not 0 but Map is NULL.=0D + @retval RETURN_BUFFER_TOO_SMALL *MapCount is too small.=0D + @retval RETURN_SUCCESS Page table is parsed successfully.=0D +**/=0D +RETURN_STATUS=0D +EFIAPI=0D +PageTableParse (=0D + IN UINTN PageTable,=0D + IN PAGING_MODE PagingMode,=0D + OUT IA32_MAP_ENTRY *Map,=0D + IN OUT UINTN *MapCount=0D + )=0D +{=0D + UINTN MapCapacity;=0D + IA32_MAP_ATTRIBUTE NopAttribute;=0D + IA32_MAP_ENTRY *LastEntry;=0D + IA32_MAP_ENTRY OneEntry;=0D + UINTN MaxLevel;=0D +=0D + if ((PagingMode =3D=3D Paging32bit) || (PagingMode =3D=3D PagingPae) || = (PagingMode >=3D PagingModeMax)) {=0D + //=0D + // 32bit paging is never supported.=0D + // PAE paging will be supported later.=0D + //=0D + return RETURN_UNSUPPORTED;=0D + }=0D +=0D + if (MapCount =3D=3D NULL) {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + if ((*MapCount !=3D 0) && (Map =3D=3D NULL)) {=0D + return RETURN_INVALID_PARAMETER;=0D + }=0D +=0D + if (PageTable =3D=3D 0) {=0D + *MapCount =3D 0;=0D + return RETURN_SUCCESS;=0D + }=0D +=0D + //=0D + // Page table layout is as below:=0D + //=0D + // [IA32_CR3]=0D + // |=0D + // |=0D + // V=0D + // [IA32_PML5E]=0D + // ...=0D + // [IA32_PML5E] --> [IA32_PML4E]=0D + // ...=0D + // [IA32_PML4E] --> [IA32_PDPTE_1G] --> 1G aligned phys= ical address=0D + // ...=0D + // [IA32_PDPTE] --> [IA32_PDE_2M] --> = 2M aligned physical address=0D + // ...=0D + // [IA32_PDE] --> [IA= 32_PTE_4K] --> 4K aligned physical address=0D + // ...= =0D + // [IA= 32_PTE_4K] --> 4K aligned physical address=0D + //=0D +=0D + NopAttribute.Uint64 =3D 0;=0D + NopAttribute.Bits.Present =3D 1;=0D + NopAttribute.Bits.ReadWrite =3D 1;=0D + NopAttribute.Bits.UserSupervisor =3D 1;=0D +=0D + MaxLevel =3D (UINT8)(PagingMode >> 8);=0D + MapCapacity =3D *MapCount;=0D + *MapCount =3D 0;=0D + LastEntry =3D NULL;=0D + PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, 0, &NopAttribute, Ma= p, MapCount, MapCapacity, &LastEntry, &OneEntry);=0D +=0D + if (*MapCount > MapCapacity) {=0D + return RETURN_BUFFER_TOO_SMALL;=0D + }=0D +=0D + return RETURN_SUCCESS;=0D +}=0D diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 1951eb294c..4fe79cecbf 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -62,6 +62,9 @@ ## @libraryclass Provides function for loading microcode.=0D MicrocodeLib|Include/Library/MicrocodeLib.h=0D =0D + ## @libraryclass Provides function for manipulating x86 paging structu= res.=0D + CpuPageTableLib|Include/Library/CpuPageTableLib.h=0D +=0D [Guids]=0D gUefiCpuPkgTokenSpaceGuid =3D { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa,= 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}=0D gMsegSmramGuid =3D { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1,= 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}=0D diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index a0bbde9985..f694b3a77c 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -1,7 +1,7 @@ ## @file=0D # UefiCpuPkg Package=0D #=0D -# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.
= =0D +# Copyright (c) 2007 - 2022, Intel Corporation. All rights reserved.
= =0D #=0D # SPDX-License-Identifier: BSD-2-Clause-Patent=0D #=0D @@ -62,6 +62,7 @@ VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf=0D MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf=0D SmmCpuRendezvousLib|UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezv= ousLib.inf=0D + CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf=0D =0D [LibraryClasses.common.SEC]=0D PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.= inf=0D @@ -175,6 +176,7 @@ UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf=0D UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf=0D UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf=0D + UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf=0D =0D [BuildOptions]=0D *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES=0D --=20 2.35.1.windows.2