• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Pre-Create a 4G page table (2M pages).
3   It's used in DUET x64 build needed to enter LongMode.
4 
5   Create 4G page table (2M pages)
6 
7                               Linear Address
8     63    48 47   39 38           30 29       21 20                          0
9    +--------+-------+---------------+-----------+-----------------------------+
10                PML4   Directory-Ptr   Directory                 Offset
11 
12    Paging-Structures :=
13                         PML4
14                         (
15                           Directory-Ptr Directory {512}
16                         ) {4}
17 
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
23 
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.
26 
27 **/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "VirtualMemory.h"
33 #include "EfiUtilityMsgs.h"
34 #include "ParseInf.h"
35 
36 #define EFI_PAGE_BASE_OFFSET_IN_LDR 0x70000
37 #define EFI_PAGE_BASE_ADDRESS       (EFI_PAGE_BASE_OFFSET_IN_LDR + 0x20000)
38 
39 UINT32 gPageTableBaseAddress  = EFI_PAGE_BASE_ADDRESS;
40 UINT32 gPageTableOffsetInFile = EFI_PAGE_BASE_OFFSET_IN_LDR;
41 
42 #define EFI_MAX_ENTRY_NUM     512
43 
44 #define EFI_PML4_ENTRY_NUM    1
45 #define EFI_PDPTE_ENTRY_NUM   4
46 #define EFI_PDE_ENTRY_NUM     EFI_MAX_ENTRY_NUM
47 
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)
51 
52 #define EFI_PAGE_NUMBER       (EFI_PML4_PAGE_NUM + EFI_PDPTE_PAGE_NUM + EFI_PDE_PAGE_NUM)
53 
54 #define EFI_SIZE_OF_PAGE      0x1000
55 #define EFI_PAGE_SIZE_2M      0x200000
56 
57 #define CONVERT_BIN_PAGE_ADDRESS(a)  ((UINT8 *) a - PageTable + gPageTableBaseAddress)
58 
59 //
60 // Utility Name
61 //
62 #define UTILITY_NAME  "GenPage"
63 
64 //
65 // Utility version information
66 //
67 #define UTILITY_MAJOR_VERSION 0
68 #define UTILITY_MINOR_VERSION 2
69 
70 void
Version(void)71 Version (
72   void
73   )
74 /*++
75 
76 Routine Description:
77 
78   Displays the standard utility information to SDTOUT
79 
80 Arguments:
81 
82   None
83 
84 Returns:
85 
86   None
87 
88 --*/
89 {
90   printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
91 }
92 
93 VOID
Usage(void)94 Usage (
95   void
96   )
97 {
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\
106                         - 9 (max)\n\
107   -v, --verbose         Print informational statements\n\
108   -q, --quiet           Returns the exit code, error messages will be\n\
109                         displayed\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\
114                         the page table\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\
119                         output file\n\
120   --sfo                 Reserved for future use\n");
121 
122 }
123 
124 void *
CreateIdentityMappingPageTables(void)125 CreateIdentityMappingPageTables (
126   void
127   )
128 /*++
129 
130 Routine Description:
131   To create 4G PAE 2M pagetable
132 
133 Return:
134   void * - buffer containing created pagetable
135 
136 --*/
137 {
138   UINT64                                        PageAddress;
139   UINT8                                         *PageTable;
140   UINT8                                         *PageTablePtr;
141   int                                           PML4Index;
142   int                                           PDPTEIndex;
143   int                                           PDEIndex;
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;
147 
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;
151 
152   PageAddress = 0;
153 
154   //
155   //  Page Table structure 3 level 2MB.
156   //
157   //                   Page-Map-Level-4-Table        : bits 47-39
158   //                   Page-Directory-Pointer-Table  : bits 38-30
159   //
160   //  Page Table 2MB : Page-Directory(2M)            : bits 29-21
161   //
162   //
163 
164   PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
165 
166   for (PML4Index = 0; PML4Index < EFI_PML4_ENTRY_NUM; PML4Index++, PageMapLevel4Entry++) {
167     //
168     // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry
169     //
170     PageTablePtr += EFI_SIZE_OF_PAGE;
171     PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
172 
173     //
174     // Make a Page-Map-Level-4-Table Entry
175     //
176     PageMapLevel4Entry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry));
177     PageMapLevel4Entry->Bits.ReadWrite = 1;
178     PageMapLevel4Entry->Bits.Present = 1;
179 
180     for (PDPTEIndex = 0; PDPTEIndex < EFI_PDPTE_ENTRY_NUM; PDPTEIndex++, PageDirectoryPointerEntry++) {
181       //
182       // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry
183       //
184       PageTablePtr += EFI_SIZE_OF_PAGE;
185       PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)PageTablePtr;
186 
187       //
188       // Make a Page-Directory-Pointer-Table Entry
189       //
190       PageDirectoryPointerEntry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB));
191       PageDirectoryPointerEntry->Bits.ReadWrite = 1;
192       PageDirectoryPointerEntry->Bits.Present = 1;
193 
194       for (PDEIndex = 0; PDEIndex < EFI_PDE_ENTRY_NUM; PDEIndex++, PageDirectoryEntry2MB++) {
195         //
196         // Make a Page-Directory Entry
197         //
198         PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
199         PageDirectoryEntry2MB->Bits.ReadWrite = 1;
200         PageDirectoryEntry2MB->Bits.Present = 1;
201         PageDirectoryEntry2MB->Bits.MustBe1 = 1;
202 
203         PageAddress += EFI_PAGE_SIZE_2M;
204       }
205     }
206   }
207 
208   return PageTable;
209 }
210 
211 INT32
GenBinPage(void * BaseMemory,char * NoPageFileName,char * PageFileName)212 GenBinPage (
213   void *BaseMemory,
214   char *NoPageFileName,
215   char *PageFileName
216   )
217 /*++
218 
219 Routine Description:
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.
222 
223 Arguments:
224   BaseMemory     - buffer containing page table
225   NoPageFileName - file to write page table
226   PageFileName   - file save to after writing
227 
228 return:
229   0  : successful
230   -1 : failed
231 
232 --*/
233 {
234   FILE  *PageFile;
235   FILE  *NoPageFile;
236   UINT8 Data;
237   unsigned long FileSize;
238 
239   //
240   // Open files
241   //
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);
245     return -1;
246   }
247 
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);
251     fclose (PageFile);
252     return -1;
253   }
254 
255   //
256   // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR
257   //
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);
263     fclose (PageFile);
264     fclose (NoPageFile);
265     return -1;
266   }
267 
268   //
269   // Write data
270   //
271   while (fread (&Data, sizeof(UINT8), 1, NoPageFile)) {
272     fwrite (&Data, sizeof(UINT8), 1, PageFile);
273   }
274 
275   //
276   // Write PageTable
277   //
278   fseek (PageFile, gPageTableOffsetInFile, SEEK_SET);
279   fwrite (BaseMemory, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE), 1, PageFile);
280 
281   //
282   // Close files
283   //
284   fclose (PageFile);
285   fclose (NoPageFile);
286 
287   return 0;
288 }
289 
290 int
main(int argc,char ** argv)291 main (
292   int argc,
293   char **argv
294   )
295 {
296   VOID        *BaseMemory;
297   INTN        result;
298   CHAR8       *OutputFile = NULL;
299   CHAR8       *InputFile = NULL;
300   EFI_STATUS  Status;
301   UINT64      TempValue;
302 
303   SetUtilityName("GenPage");
304 
305   if (argc == 1) {
306     Usage();
307     return STATUS_ERROR;
308   }
309 
310   argc --;
311   argv ++;
312 
313   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
314     Usage();
315     return 0;
316   }
317 
318   if (stricmp (argv[0], "--version") == 0) {
319     Version();
320     return 0;
321   }
322 
323   while (argc > 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");
327         return STATUS_ERROR;
328       }
329       OutputFile = argv[1];
330       argc -= 2;
331       argv += 2;
332       continue;
333     }
334 
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");
338         return STATUS_ERROR;
339       }
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");
343         return STATUS_ERROR;
344       }
345       gPageTableBaseAddress = (UINT32) TempValue;
346       argc -= 2;
347       argv += 2;
348       continue;
349     }
350 
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");
354         return STATUS_ERROR;
355       }
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");
359         return STATUS_ERROR;
360       }
361       gPageTableOffsetInFile = (UINT32) TempValue;
362       argc -= 2;
363       argv += 2;
364       continue;
365     }
366 
367     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
368       argc --;
369       argv ++;
370       continue;
371     }
372 
373     if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) {
374       argc --;
375       argv ++;
376       continue;
377     }
378 
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.");
382         return STATUS_ERROR;
383       }
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.");
387         return STATUS_ERROR;
388       }
389       if (TempValue > 9) {
390         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue);
391         return STATUS_ERROR;
392       }
393       argc -= 2;
394       argv += 2;
395       continue;
396     }
397 
398     if (argv[0][0] == '-') {
399       Error (NULL, 0, 1000, "Unknown option", argv[0]);
400       return STATUS_ERROR;
401     }
402 
403     //
404     // Don't recognize the paramter.
405     //
406     InputFile = argv[0];
407     argc--;
408     argv++;
409   }
410 
411   if (InputFile == NULL) {
412     Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified");
413     return STATUS_ERROR;
414   }
415 
416   //
417   // Create X64 page table
418   //
419   BaseMemory = CreateIdentityMappingPageTables ();
420 
421   //
422   // Add page table to binary file
423   //
424   result = GenBinPage (BaseMemory, InputFile, OutputFile);
425   if (result < 0) {
426     return STATUS_ERROR;
427   }
428 
429   return 0;
430 }
431 
432