1 /** @file 2 3 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 Paging.c 14 15 Abstract: 16 17 Revision History: 18 19 **/ 20 21 #include "HobGeneration.h" 22 #include "VirtualMemory.h" 23 24 // 25 // Create 2M-page table 26 // PML4 (47:39) 27 // PDPTE (38:30) 28 // PDE (29:21) 29 // 30 31 #define EFI_2M_PAGE_BITS_NUM 21 32 #define EFI_MAX_ENTRY_BITS_NUM 9 33 34 #define EFI_PAGE_SIZE_4K 0x1000 35 #define EFI_PAGE_SIZE_2M (1 << EFI_2M_PAGE_BITS_NUM) 36 37 #ifndef MIN 38 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 39 #endif 40 #define ENTRY_NUM(x) ((UINTN)1 << (x)) 41 42 UINT8 gPML4BitsNum; 43 UINT8 gPDPTEBitsNum; 44 UINT8 gPDEBitsNum; 45 46 UINTN gPageNum2M; 47 UINTN gPageNum4K; 48 49 VOID 50 EnableNullPointerProtection ( 51 UINT8 *PageTable 52 ) 53 { 54 X64_PAGE_TABLE_ENTRY_4K *PageTableEntry4KB; 55 56 PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *) (PageTable + gPageNum2M * EFI_PAGE_SIZE_4K); 57 // 58 // Fill in the Page Table entries 59 // Mark 0~4K as not present 60 // 61 PageTableEntry4KB->Bits.Present = 0; 62 63 return ; 64 } 65 66 VOID 67 X64Create4KPageTables ( 68 UINT8 *PageTable 69 ) 70 /*++ 71 Routine Description: 72 Create 4K-Page-Table for the low 2M memory. 73 This will change the previously created 2M-Page-Table-Entry. 74 --*/ 75 { 76 UINT64 PageAddress; 77 UINTN PTEIndex; 78 X64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4KB; 79 X64_PAGE_TABLE_ENTRY_4K *PageTableEntry4KB; 80 81 // 82 // Page Table structure 4 level 4K. 83 // 84 // PageMapLevel4Entry : bits 47-39 85 // PageDirectoryPointerEntry : bits 38-30 86 // Page Table 4K : PageDirectoryEntry4K : bits 29-21 87 // PageTableEntry : bits 20-12 88 // 89 90 PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *)(PageTable + gPageNum2M * EFI_PAGE_SIZE_4K); 91 92 PageDirectoryEntry4KB = (X64_PAGE_DIRECTORY_ENTRY_4K *) (PageTable + 2 * EFI_PAGE_SIZE_4K); 93 PageDirectoryEntry4KB->Uint64 = (UINT64)(UINTN)PageTableEntry4KB; 94 PageDirectoryEntry4KB->Bits.ReadWrite = 1; 95 PageDirectoryEntry4KB->Bits.Present = 1; 96 PageDirectoryEntry4KB->Bits.MustBeZero = 0; 97 98 for (PTEIndex = 0, PageAddress = 0; 99 PTEIndex < ENTRY_NUM (EFI_MAX_ENTRY_BITS_NUM); 100 PTEIndex++, PageTableEntry4KB++, PageAddress += EFI_PAGE_SIZE_4K 101 ) { 102 // 103 // Fill in the Page Table entries 104 // 105 PageTableEntry4KB->Uint64 = (UINT64)PageAddress; 106 PageTableEntry4KB->Bits.ReadWrite = 1; 107 PageTableEntry4KB->Bits.Present = 1; 108 } 109 110 return ; 111 } 112 113 VOID 114 X64Create2MPageTables ( 115 UINT8 *PageTable 116 ) 117 { 118 UINT64 PageAddress; 119 UINT8 *TempPageTable; 120 UINTN PML4Index; 121 UINTN PDPTEIndex; 122 UINTN PDEIndex; 123 X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry; 124 X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry; 125 X64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB; 126 127 TempPageTable = PageTable; 128 PageAddress = 0; 129 130 // 131 // Page Table structure 3 level 2MB. 132 // 133 // PageMapLevel4Entry : bits 47-39 134 // PageDirectoryPointerEntry : bits 38-30 135 // Page Table 2MB : PageDirectoryEntry2M : bits 29-21 136 // 137 138 PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable; 139 140 for (PML4Index = 0; PML4Index < ENTRY_NUM (gPML4BitsNum); PML4Index++, PageMapLevel4Entry++) { 141 // 142 // Each PML4 entry points to a page of Page Directory Pointer entires. 143 // 144 TempPageTable += EFI_PAGE_SIZE_4K; 145 PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable; 146 147 // 148 // Make a PML4 Entry 149 // 150 PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)(TempPageTable); 151 PageMapLevel4Entry->Bits.ReadWrite = 1; 152 PageMapLevel4Entry->Bits.Present = 1; 153 154 for (PDPTEIndex = 0; PDPTEIndex < ENTRY_NUM (gPDPTEBitsNum); PDPTEIndex++, PageDirectoryPointerEntry++) { 155 // 156 // Each Directory Pointer entries points to a page of Page Directory entires. 157 // 158 TempPageTable += EFI_PAGE_SIZE_4K; 159 PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)TempPageTable; 160 161 // 162 // Fill in a Page Directory Pointer Entries 163 // 164 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)(TempPageTable); 165 PageDirectoryPointerEntry->Bits.ReadWrite = 1; 166 PageDirectoryPointerEntry->Bits.Present = 1; 167 168 for (PDEIndex = 0; PDEIndex < ENTRY_NUM (gPDEBitsNum); PDEIndex++, PageDirectoryEntry2MB++) { 169 // 170 // Fill in the Page Directory entries 171 // 172 PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress; 173 PageDirectoryEntry2MB->Bits.ReadWrite = 1; 174 PageDirectoryEntry2MB->Bits.Present = 1; 175 PageDirectoryEntry2MB->Bits.MustBe1 = 1; 176 177 PageAddress += EFI_PAGE_SIZE_2M; 178 } 179 } 180 } 181 182 return ; 183 } 184 185 VOID * 186 PreparePageTable ( 187 VOID *PageNumberTop, 188 UINT8 SizeOfMemorySpace 189 ) 190 /*++ 191 Description: 192 Generate pagetable below PageNumberTop, 193 and return the bottom address of pagetable for putting other things later. 194 --*/ 195 { 196 VOID *PageNumberBase; 197 198 SizeOfMemorySpace -= EFI_2M_PAGE_BITS_NUM; 199 gPDEBitsNum = (UINT8) MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM); 200 SizeOfMemorySpace = (UINT8) (SizeOfMemorySpace - gPDEBitsNum); 201 gPDPTEBitsNum = (UINT8) MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM); 202 SizeOfMemorySpace = (UINT8) (SizeOfMemorySpace - gPDPTEBitsNum); 203 gPML4BitsNum = SizeOfMemorySpace; 204 if (gPML4BitsNum > EFI_MAX_ENTRY_BITS_NUM) { 205 return NULL; 206 } 207 208 // 209 // Suppose we have: 210 // 2MPage: 211 // Entry: PML4 -> PDPTE -> PDE -> Page 212 // EntryNum: a b c 213 // then 214 // Occupy4KPage: 1 a a*b 215 // 216 // 2M 4KPage: 217 // Entry: PTE -> Page 218 // EntryNum: 512 219 // then 220 // Occupy4KPage: 1 221 // 222 223 gPageNum2M = 1 + ENTRY_NUM (gPML4BitsNum) + ENTRY_NUM (gPML4BitsNum + gPDPTEBitsNum); 224 gPageNum4K = 1; 225 226 227 PageNumberBase = (VOID *)((UINTN)PageNumberTop - (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K); 228 ZeroMem (PageNumberBase, (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K); 229 230 X64Create2MPageTables (PageNumberBase); 231 X64Create4KPageTables (PageNumberBase); 232 // 233 // Not enable NULL Pointer Protection if using INTx call 234 // 235 // EnableNullPointerProtection (PageNumberBase); 236 237 return PageNumberBase; 238 } 239