2 Pre-Create a 4G page table (2M pages).
3 It's used in DUET x64 build needed to enter LongMode.
5 Create 4G page table (2M pages)
8 63 48 47 39 38 30 29 21 20 0
9 +--------+-------+---------------+-----------+-----------------------------+
10 PML4 Directory-Ptr Directory Offset
15 Directory-Ptr Directory {512}
18 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
19 This program and the accompanying materials
20 are licensed and made available under the terms and conditions of the BSD License
21 which accompanies this distribution. The full text of the license may be found at
22 http://opensource.org/licenses/bsd-license.php
24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
25 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
32 #include "VirtualMemory.h"
33 #include "EfiUtilityMsgs.h"
36 #define EFI_PAGE_BASE_OFFSET_IN_LDR 0x70000
37 #define EFI_PAGE_BASE_ADDRESS (EFI_PAGE_BASE_OFFSET_IN_LDR + 0x20000)
39 UINT32 gPageTableBaseAddress
= EFI_PAGE_BASE_ADDRESS
;
40 UINT32 gPageTableOffsetInFile
= EFI_PAGE_BASE_OFFSET_IN_LDR
;
42 #define EFI_MAX_ENTRY_NUM 512
44 #define EFI_PML4_ENTRY_NUM 1
45 #define EFI_PDPTE_ENTRY_NUM 4
46 #define EFI_PDE_ENTRY_NUM EFI_MAX_ENTRY_NUM
48 #define EFI_PML4_PAGE_NUM 1
49 #define EFI_PDPTE_PAGE_NUM EFI_PML4_ENTRY_NUM
50 #define EFI_PDE_PAGE_NUM (EFI_PML4_ENTRY_NUM * EFI_PDPTE_ENTRY_NUM)
52 #define EFI_PAGE_NUMBER (EFI_PML4_PAGE_NUM + EFI_PDPTE_PAGE_NUM + EFI_PDE_PAGE_NUM)
54 #define EFI_SIZE_OF_PAGE 0x1000
55 #define EFI_PAGE_SIZE_2M 0x200000
57 #define CONVERT_BIN_PAGE_ADDRESS(a) ((UINT8 *) a - PageTable + gPageTableBaseAddress)
62 #define UTILITY_NAME "GenPage"
65 // Utility version information
67 #define UTILITY_MAJOR_VERSION 0
68 #define UTILITY_MINOR_VERSION 2
78 Displays the standard utility information to SDTOUT
90 printf ("%s Version %d.%d %s\n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
, __BUILD_VERSION
);
98 printf ("Usage: GenPage.exe [options] EfiLoaderImageName \n\n\
99 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.\n\n\
100 Utility to generate the EfiLoader image containing a page table.\n\n\
101 optional arguments:\n\
102 -h, --help Show this help message and exit\n\
103 --version Show program's version number and exit\n\
104 -d [DEBUG], --debug [DEBUG]\n\
105 Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
107 -v, --verbose Print informational statements\n\
108 -q, --quiet Returns the exit code, error messages will be\n\
110 -s, --silent Returns only the exit code; informational and error\n\
111 messages are not displayed\n\
112 -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
113 Output file contain both the non-page table part and\n\
115 -b BASE_ADDRESS, --baseaddr BASE_ADDRESS\n\
116 The page table location\n\
117 -f OFFSET, --offset OFFSET\n\
118 The position that the page table will appear in the\n\
120 --sfo Reserved for future use\n");
125 CreateIdentityMappingPageTables (
131 To create 4G PAE 2M pagetable
134 void * - buffer containing created pagetable
144 X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K
*PageMapLevel4Entry
;
145 X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K
*PageDirectoryPointerEntry
;
146 X64_PAGE_TABLE_ENTRY_2M
*PageDirectoryEntry2MB
;
148 PageTable
= (void *)malloc (EFI_PAGE_NUMBER
* EFI_SIZE_OF_PAGE
);
149 memset (PageTable
, 0, (EFI_PAGE_NUMBER
* EFI_SIZE_OF_PAGE
));
150 PageTablePtr
= PageTable
;
155 // Page Table structure 3 level 2MB.
157 // Page-Map-Level-4-Table : bits 47-39
158 // Page-Directory-Pointer-Table : bits 38-30
160 // Page Table 2MB : Page-Directory(2M) : bits 29-21
164 PageMapLevel4Entry
= (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K
*)PageTablePtr
;
166 for (PML4Index
= 0; PML4Index
< EFI_PML4_ENTRY_NUM
; PML4Index
++, PageMapLevel4Entry
++) {
168 // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry
170 PageTablePtr
+= EFI_SIZE_OF_PAGE
;
171 PageDirectoryPointerEntry
= (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K
*)PageTablePtr
;
174 // Make a Page-Map-Level-4-Table Entry
176 PageMapLevel4Entry
->Uint64
= (UINT64
)(UINT32
)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry
));
177 PageMapLevel4Entry
->Bits
.ReadWrite
= 1;
178 PageMapLevel4Entry
->Bits
.Present
= 1;
180 for (PDPTEIndex
= 0; PDPTEIndex
< EFI_PDPTE_ENTRY_NUM
; PDPTEIndex
++, PageDirectoryPointerEntry
++) {
182 // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry
184 PageTablePtr
+= EFI_SIZE_OF_PAGE
;
185 PageDirectoryEntry2MB
= (X64_PAGE_TABLE_ENTRY_2M
*)PageTablePtr
;
188 // Make a Page-Directory-Pointer-Table Entry
190 PageDirectoryPointerEntry
->Uint64
= (UINT64
)(UINT32
)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB
));
191 PageDirectoryPointerEntry
->Bits
.ReadWrite
= 1;
192 PageDirectoryPointerEntry
->Bits
.Present
= 1;
194 for (PDEIndex
= 0; PDEIndex
< EFI_PDE_ENTRY_NUM
; PDEIndex
++, PageDirectoryEntry2MB
++) {
196 // Make a Page-Directory Entry
198 PageDirectoryEntry2MB
->Uint64
= (UINT64
)PageAddress
;
199 PageDirectoryEntry2MB
->Bits
.ReadWrite
= 1;
200 PageDirectoryEntry2MB
->Bits
.Present
= 1;
201 PageDirectoryEntry2MB
->Bits
.MustBe1
= 1;
203 PageAddress
+= EFI_PAGE_SIZE_2M
;
214 char *NoPageFileName
,
220 Write the buffer containing page table to file at a specified offset.
221 Here the offset is defined as EFI_PAGE_BASE_OFFSET_IN_LDR.
224 BaseMemory - buffer containing page table
225 NoPageFileName - file to write page table
226 PageFileName - file save to after writing
237 unsigned long FileSize
;
242 PageFile
= fopen (LongFilePath (PageFileName
), "w+b");
243 if (PageFile
== NULL
) {
244 Error (NoPageFileName
, 0, 0x4002, "Invalid parameter option", "Output File %s open failure", PageFileName
);
248 NoPageFile
= fopen (LongFilePath (NoPageFileName
), "r+b");
249 if (NoPageFile
== NULL
) {
250 Error (NoPageFileName
, 0, 0x4002, "Invalid parameter option", "Input File %s open failure", NoPageFileName
);
256 // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR
258 fseek (NoPageFile
, 0, SEEK_END
);
259 FileSize
= ftell (NoPageFile
);
260 fseek (NoPageFile
, 0, SEEK_SET
);
261 if (FileSize
> gPageTableOffsetInFile
) {
262 Error (NoPageFileName
, 0, 0x4002, "Invalid parameter option", "Input file size (0x%lx) exceeds the Page Table Offset (0x%x)", FileSize
, (unsigned) gPageTableOffsetInFile
);
271 while (fread (&Data
, sizeof(UINT8
), 1, NoPageFile
)) {
272 fwrite (&Data
, sizeof(UINT8
), 1, PageFile
);
278 fseek (PageFile
, gPageTableOffsetInFile
, SEEK_SET
);
279 fwrite (BaseMemory
, (EFI_PAGE_NUMBER
* EFI_SIZE_OF_PAGE
), 1, PageFile
);
298 CHAR8
*OutputFile
= NULL
;
299 CHAR8
*InputFile
= NULL
;
303 SetUtilityName("GenPage");
313 if ((stricmp (argv
[0], "-h") == 0) || (stricmp (argv
[0], "--help") == 0)) {
318 if (stricmp (argv
[0], "--version") == 0) {
324 if ((stricmp (argv
[0], "-o") == 0) || (stricmp (argv
[0], "--output") == 0)) {
325 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
326 Error (NULL
, 0, 1003, "Invalid option value", "Output file is missing for -o option");
329 OutputFile
= argv
[1];
335 if ((stricmp (argv
[0], "-b") == 0) || (stricmp (argv
[0], "--baseaddr") == 0)) {
336 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
337 Error (NULL
, 0, 1003, "Invalid option value", "Base address is missing for -b option");
340 Status
= AsciiStringToUint64 (argv
[1], FALSE
, &TempValue
);
341 if (EFI_ERROR (Status
)) {
342 Error (NULL
, 0, 1003, "Invalid option value", "Base address is not valid intergrator");
345 gPageTableBaseAddress
= (UINT32
) TempValue
;
351 if ((stricmp (argv
[0], "-f") == 0) || (stricmp (argv
[0], "--offset") == 0)) {
352 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
353 Error (NULL
, 0, 1003, "Invalid option value", "Offset is missing for -f option");
356 Status
= AsciiStringToUint64 (argv
[1], FALSE
, &TempValue
);
357 if (EFI_ERROR (Status
)) {
358 Error (NULL
, 0, 1003, "Invalid option value", "Offset is not valid intergrator");
361 gPageTableOffsetInFile
= (UINT32
) TempValue
;
367 if ((stricmp (argv
[0], "-q") == 0) || (stricmp (argv
[0], "--quiet") == 0)) {
373 if ((stricmp (argv
[0], "-v") ==0) || (stricmp (argv
[0], "--verbose") == 0)) {
379 if ((stricmp (argv
[0], "-d") == 0) || (stricmp (argv
[0], "--debug") == 0)) {
380 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
381 Error (NULL
, 0, 1003, "Invalid option value", "Debug Level is not specified.");
384 Status
= AsciiStringToUint64 (argv
[1], FALSE
, &TempValue
);
385 if (EFI_ERROR (Status
)) {
386 Error (NULL
, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator.");
390 Error (NULL
, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue
);
398 if (argv
[0][0] == '-') {
399 Error (NULL
, 0, 1000, "Unknown option", argv
[0]);
404 // Don't recognize the paramter.
411 if (InputFile
== NULL
) {
412 Error (NULL
, 0, 1003, "Invalid option value", "Input file is not specified");
417 // Create X64 page table
419 BaseMemory
= CreateIdentityMappingPageTables ();
422 // Add page table to binary file
424 result
= GenBinPage (BaseMemory
, InputFile
, OutputFile
);