Modify CpuPageTableLib code to enable PAE paging. In PageTableMap() API: When creating new PAE page table, after creating page table, set all MustBeZero fields of 4 PDPTE to 0. The MustBeZero fields are treated as RW and other attributes by the common map logic. So they might be set to 1. When updating exsiting PAE page table, the special steps are: 1.Prepare 4K-aligned 32bytes memory in stack for 4 temp PDPTE. 2.Copy original 4 PDPTE to the 4 temp PDPTE and set the RW, UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. 4.After updating the page table, set the MustBeZero fields of 4 temp PDPTE to 0. 5.Copy the temp PDPTE to original PDPTE. In PageTableParse() API, also create 4 temp PDPTE in stack. Copy original 4 PDPTE to the 4 temp PDPTE. Then set the RW, UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. Finally use the address of temp PDPTE as the page table address. Signed-off-by: Dun Tan <dun.tan@intel.com> Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Tested-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
		
			
				
	
	
		
			234 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Internal header for CpuPageTableLib.
 | 
						|
 | 
						|
  Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#ifndef CPU_PAGE_TABLE_H_
 | 
						|
#define CPU_PAGE_TABLE_H_
 | 
						|
 | 
						|
#include <Base.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/CpuPageTableLib.h>
 | 
						|
 | 
						|
#define IA32_PE_BASE_ADDRESS_MASK_40  0xFFFFFFFFFF000ull
 | 
						|
#define IA32_PE_BASE_ADDRESS_MASK_39  0xFFFFFFFFFE000ull
 | 
						|
 | 
						|
#define REGION_LENGTH(l)  LShiftU64 (1, (l) * 9 + 3)
 | 
						|
 | 
						|
#define MAX_PAE_PDPTE_NUM  4
 | 
						|
 | 
						|
typedef enum {
 | 
						|
  Pte   = 1,
 | 
						|
  Pde   = 2,
 | 
						|
  Pdpte = 3,
 | 
						|
  Pml4  = 4,
 | 
						|
  Pml5  = 5
 | 
						|
} IA32_PAGE_LEVEL;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  UINT32    Present        : 1;       // 0 = Not present in memory, 1 = Present in memory
 | 
						|
  UINT32    ReadWrite      : 1;       // 0 = Read-Only, 1= Read/Write
 | 
						|
  UINT32    UserSupervisor : 1;       // 0 = Supervisor, 1=User
 | 
						|
  UINT32    Reserved0      : 29;
 | 
						|
  UINT32    Reserved1      : 31;
 | 
						|
  UINT32    Nx             : 1;        // No Execute bit
 | 
						|
} IA32_PAGE_COMMON_ENTRY;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a non-leaf entry that references a page table entry
 | 
						|
///
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    Present                  : 1;  // 0 = Not present in memory, 1 = Present in memory
 | 
						|
    UINT32    ReadWrite                : 1;  // 0 = Read-Only, 1= Read/Write
 | 
						|
    UINT32    UserSupervisor           : 1;  // 0 = Supervisor, 1=User
 | 
						|
    UINT32    WriteThrough             : 1;  // 0 = Write-Back caching, 1=Write-Through caching
 | 
						|
    UINT32    CacheDisabled            : 1;  // 0 = Cached, 1=Non-Cached
 | 
						|
    UINT32    Accessed                 : 1;  // 0 = Not accessed, 1 = Accessed (set by CPU)
 | 
						|
    UINT32    Available0               : 1;  // Ignored
 | 
						|
    UINT32    MustBeZero               : 1;  // Must Be Zero
 | 
						|
    UINT32    Available2               : 4;  // Ignored
 | 
						|
    UINT32    PageTableBaseAddressLow  : 20; // Page Table Base Address Low
 | 
						|
 | 
						|
    UINT32    PageTableBaseAddressHigh : 20; // Page Table Base Address High
 | 
						|
    UINT32    Available3               : 11; // Ignored
 | 
						|
    UINT32    Nx                       : 1;  // No Execute bit
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_PAGE_NON_LEAF_ENTRY;
 | 
						|
 | 
						|
#define IA32_PNLE_PAGE_TABLE_BASE_ADDRESS(pa)  ((pa)->Uint64 & IA32_PE_BASE_ADDRESS_MASK_40)
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a PML5 Entry (PML5E) that References a PML4 Table
 | 
						|
///
 | 
						|
typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PML5E;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a PML4 Entry (PML4E) that References a Page-Directory-Pointer Table
 | 
						|
///
 | 
						|
typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PML4E;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that References a Page Directory
 | 
						|
///
 | 
						|
typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PDPTE;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Directory Entry that References a Page Table
 | 
						|
///
 | 
						|
typedef IA32_PAGE_NON_LEAF_ENTRY IA32_PDE;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a leaf entry that Maps a 1-Gbyte or 2-MByte Page
 | 
						|
///
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    Present                  : 1;  // 0 = Not present in memory, 1 = Present in memory
 | 
						|
    UINT32    ReadWrite                : 1;  // 0 = Read-Only, 1= Read/Write
 | 
						|
    UINT32    UserSupervisor           : 1;  // 0 = Supervisor, 1=User
 | 
						|
    UINT32    WriteThrough             : 1;  // 0 = Write-Back caching, 1=Write-Through caching
 | 
						|
    UINT32    CacheDisabled            : 1;  // 0 = Cached, 1=Non-Cached
 | 
						|
    UINT32    Accessed                 : 1;  // 0 = Not accessed, 1 = Accessed (set by CPU)
 | 
						|
    UINT32    Dirty                    : 1;  // 0 = Not dirty, 1 = Dirty (set by CPU)
 | 
						|
    UINT32    MustBeOne                : 1;  // Page Size. Must Be One
 | 
						|
    UINT32    Global                   : 1;  // 0 = Not global, 1 = Global (if CR4.PGE = 1)
 | 
						|
    UINT32    Available1               : 3;  // Ignored
 | 
						|
    UINT32    Pat                      : 1;  // PAT
 | 
						|
    UINT32    PageTableBaseAddressLow  : 19; // Page Table Base Address Low
 | 
						|
 | 
						|
    UINT32    PageTableBaseAddressHigh : 20; // Page Table Base Address High
 | 
						|
    UINT32    Available3               : 7;  // Ignored
 | 
						|
    UINT32    ProtectionKey            : 4;  // Protection key
 | 
						|
    UINT32    Nx                       : 1;  // No Execute bit
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE;
 | 
						|
#define IA32_PLEB_PAGE_TABLE_BASE_ADDRESS(pa)  ((pa)->Uint64 & IA32_PE_BASE_ADDRESS_MASK_39)
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Directory Entry that Maps a 2-MByte Page
 | 
						|
///
 | 
						|
typedef IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE IA32_PDE_2M;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that Maps a 1-GByte Page
 | 
						|
///
 | 
						|
typedef IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE IA32_PDPTE_1G;
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Table Entry that Maps a 4-KByte Page
 | 
						|
///
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    Present                  : 1;  // 0 = Not present in memory, 1 = Present in memory
 | 
						|
    UINT32    ReadWrite                : 1;  // 0 = Read-Only, 1= Read/Write
 | 
						|
    UINT32    UserSupervisor           : 1;  // 0 = Supervisor, 1=User
 | 
						|
    UINT32    WriteThrough             : 1;  // 0 = Write-Back caching, 1=Write-Through caching
 | 
						|
    UINT32    CacheDisabled            : 1;  // 0 = Cached, 1=Non-Cached
 | 
						|
    UINT32    Accessed                 : 1;  // 0 = Not accessed, 1 = Accessed (set by CPU)
 | 
						|
    UINT32    Dirty                    : 1;  // 0 = Not dirty, 1 = Dirty (set by CPU)
 | 
						|
    UINT32    Pat                      : 1;  // PAT
 | 
						|
    UINT32    Global                   : 1;  // 0 = Not global, 1 = Global (if CR4.PGE = 1)
 | 
						|
    UINT32    Available1               : 3;  // Ignored
 | 
						|
    UINT32    PageTableBaseAddressLow  : 20; // Page Table Base Address Low
 | 
						|
 | 
						|
    UINT32    PageTableBaseAddressHigh : 20; // Page Table Base Address High
 | 
						|
    UINT32    Available3               : 7;  // Ignored
 | 
						|
    UINT32    ProtectionKey            : 4;  // Protection key
 | 
						|
    UINT32    Nx                       : 1;  // No Execute bit
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_PTE_4K;
 | 
						|
#define IA32_PTE4K_PAGE_TABLE_BASE_ADDRESS(pa)  ((pa)->Uint64 & IA32_PE_BASE_ADDRESS_MASK_40)
 | 
						|
 | 
						|
///
 | 
						|
/// Format of a Page-Directory-Pointer-Table Entry (PDPTE) that References a Page Directory (32bit PAE specific)
 | 
						|
///
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    Present                  : 1;  // 0 = Not present in memory, 1 = Present in memory
 | 
						|
    UINT32    MustBeZero               : 2;  // Must Be Zero
 | 
						|
    UINT32    WriteThrough             : 1;  // 0 = Write-Back caching, 1=Write-Through caching
 | 
						|
    UINT32    CacheDisabled            : 1;  // 0 = Cached, 1=Non-Cached
 | 
						|
    UINT32    MustBeZero2              : 4;  // Must Be Zero
 | 
						|
    UINT32    Available                : 3;  // Ignored
 | 
						|
    UINT32    PageTableBaseAddressLow  : 20; // Page Table Base Address Low
 | 
						|
 | 
						|
    UINT32    PageTableBaseAddressHigh : 20; // Page Table Base Address High
 | 
						|
    UINT32    MustBeZero3              : 12; // Must Be Zero
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_PDPTE_PAE;
 | 
						|
 | 
						|
typedef union {
 | 
						|
  IA32_PAGE_NON_LEAF_ENTRY             Pnle; // To access Pml5, Pml4, Pdpte and Pde.
 | 
						|
  IA32_PML5E                           Pml5;
 | 
						|
  IA32_PML4E                           Pml4;
 | 
						|
  IA32_PDPTE                           Pdpte;
 | 
						|
  IA32_PDE                             Pde;
 | 
						|
 | 
						|
  IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE    PleB; // to access Pdpte1G and Pde2M.
 | 
						|
  IA32_PDPTE_1G                        Pdpte1G;
 | 
						|
  IA32_PDE_2M                          Pde2M;
 | 
						|
 | 
						|
  IA32_PTE_4K                          Pte4K;
 | 
						|
 | 
						|
  IA32_PDPTE_PAE                       PdptePae;
 | 
						|
  IA32_PAGE_COMMON_ENTRY               Pce; // To access all common bits in above entries.
 | 
						|
 | 
						|
  UINT64                               Uint64;
 | 
						|
  UINTN                                Uintn;
 | 
						|
} IA32_PAGING_ENTRY;
 | 
						|
 | 
						|
/**
 | 
						|
  Return TRUE when the page table entry is a leaf entry that points to the physical address memory.
 | 
						|
  Return FALSE when the page table entry is a non-leaf entry that points to the page table entries.
 | 
						|
 | 
						|
  @param[in] PagingEntry Pointer to the page table entry.
 | 
						|
  @param[in] Level       Page level where the page table entry resides in.
 | 
						|
 | 
						|
  @retval TRUE  It's a leaf entry.
 | 
						|
  @retval FALSE It's a non-leaf entry.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsPle (
 | 
						|
  IN     IA32_PAGING_ENTRY  *PagingEntry,
 | 
						|
  IN     UINTN              Level
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Return the attribute of a 2M/1G page table entry.
 | 
						|
 | 
						|
  @param[in] PleB               Pointer to a 2M/1G page table entry.
 | 
						|
  @param[in] ParentMapAttribute Pointer to the parent attribute.
 | 
						|
 | 
						|
  @return Attribute of the 2M/1G page table entry.
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
PageTableLibGetPleBMapAttribute (
 | 
						|
  IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE  *PleB,
 | 
						|
  IN IA32_MAP_ATTRIBUTE                 *ParentMapAttribute
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Return the attribute of a non-leaf page table entry.
 | 
						|
 | 
						|
  @param[in] Pnle               Pointer to a non-leaf page table entry.
 | 
						|
  @param[in] ParentMapAttribute Pointer to the parent attribute.
 | 
						|
 | 
						|
  @return Attribute of the non-leaf page table entry.
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
PageTableLibGetPnleMapAttribute (
 | 
						|
  IN IA32_PAGE_NON_LEAF_ENTRY  *Pnle,
 | 
						|
  IN IA32_MAP_ATTRIBUTE        *ParentMapAttribute
 | 
						|
  );
 | 
						|
 | 
						|
#endif
 |