dac55889d512bbd944217151b45452312e48a54a
[efi/edk2/.git] / edk2 / BaseTools / Source / C / GenPage / GenPage.c
1 /** @file\r
2 \r
3 Copyright 2006 - 2008, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13   GenPage.c\r
14   \r
15 Abstract:\r
16   Pre-Create a 4G page table (2M pages).\r
17   It's used in DUET x64 build needed to enter LongMode.\r
18  \r
19   Create 4G page table (2M pages)\r
20  \r
21                               Linear Address\r
22     63    48 47   39 38           30 29       21 20                          0\r
23    +--------+-------+---------------+-----------+-----------------------------+\r
24                PML4   Directory-Ptr   Directory                 Offset\r
25 \r
26    Paging-Structures :=\r
27                         PML4\r
28                         (\r
29                           Directory-Ptr Directory {512}\r
30                         ) {4}\r
31 **/\r
32 \r
33 #include <stdio.h>\r
34 #include <stdlib.h>\r
35 #include <string.h>\r
36 #include "VirtualMemory.h"\r
37 #include "EfiUtilityMsgs.h"\r
38 #include "ParseInf.h"\r
39 \r
40 #define EFI_PAGE_BASE_OFFSET_IN_LDR 0x70000\r
41 #define EFI_PAGE_BASE_ADDRESS       (EFI_PAGE_BASE_OFFSET_IN_LDR + 0x20000)\r
42 \r
43 UINT32 gPageTableBaseAddress  = EFI_PAGE_BASE_ADDRESS;\r
44 UINT32 gPageTableOffsetInFile = EFI_PAGE_BASE_OFFSET_IN_LDR;\r
45 \r
46 #define EFI_MAX_ENTRY_NUM     512\r
47 \r
48 #define EFI_PML4_ENTRY_NUM    1\r
49 #define EFI_PDPTE_ENTRY_NUM   4\r
50 #define EFI_PDE_ENTRY_NUM     EFI_MAX_ENTRY_NUM\r
51 \r
52 #define EFI_PML4_PAGE_NUM     1\r
53 #define EFI_PDPTE_PAGE_NUM    EFI_PML4_ENTRY_NUM\r
54 #define EFI_PDE_PAGE_NUM      (EFI_PML4_ENTRY_NUM * EFI_PDPTE_ENTRY_NUM)\r
55 \r
56 #define EFI_PAGE_NUMBER       (EFI_PML4_PAGE_NUM + EFI_PDPTE_PAGE_NUM + EFI_PDE_PAGE_NUM)\r
57 \r
58 #define EFI_SIZE_OF_PAGE      0x1000\r
59 #define EFI_PAGE_SIZE_2M      0x200000\r
60 \r
61 #define CONVERT_BIN_PAGE_ADDRESS(a)  ((UINT8 *) a - PageTable + gPageTableBaseAddress)\r
62 \r
63 //\r
64 // Utility Name\r
65 //\r
66 #define UTILITY_NAME  "GenBootSector"\r
67 \r
68 //\r
69 // Utility version information\r
70 //\r
71 #define UTILITY_MAJOR_VERSION 0\r
72 #define UTILITY_MINOR_VERSION 1\r
73 \r
74 void\r
75 Version (\r
76   void\r
77   )\r
78 /*++\r
79 \r
80 Routine Description:\r
81 \r
82   Displays the standard utility information to SDTOUT\r
83 \r
84 Arguments:\r
85 \r
86   None\r
87 \r
88 Returns:\r
89 \r
90   None\r
91 \r
92 --*/\r
93 {\r
94   printf ("%s v%d.%d -Utility to generate the EfiLoader image containing page table.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
95   printf ("Copyright (c) 2008 - 2009 Intel Corporation. All rights reserved.\n");\r
96 }\r
97 \r
98 VOID\r
99 Usage (\r
100   void\r
101   )\r
102 {\r
103   Version();\r
104   printf ("\nUsage: \n\\r
105    GenPage\n\\r
106      -o, --output Filename containing page table\n\\r
107      [-b, --baseaddr baseaddress of page table]\n\\r
108      [-f, --offset offset in the file that page table will reside]\n\\r
109      [-v, --verbose]\n\\r
110      [--version]\n\\r
111      [-q, --quiet disable all messages except fatal errors]\n\\r
112      [-d, --debug[#]\n\\r
113      [-h, --help]\n\\r
114      EfiLoaderImageName\n");\r
115 \r
116 }\r
117 \r
118 void *\r
119 CreateIdentityMappingPageTables (\r
120   void\r
121   )\r
122 /*++\r
123 \r
124 Routine Description:\r
125   To create 4G PAE 2M pagetable\r
126 \r
127 Return:\r
128   void * - buffer containing created pagetable\r
129 \r
130 --*/\r
131 {\r
132   UINT64                                        PageAddress;\r
133   UINT8                                         *PageTable;\r
134   UINT8                                         *PageTablePtr;\r
135   int                                           PML4Index;\r
136   int                                           PDPTEIndex;\r
137   int                                           PDEIndex;\r
138   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageMapLevel4Entry;\r
139   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageDirectoryPointerEntry;\r
140   X64_PAGE_TABLE_ENTRY_2M                       *PageDirectoryEntry2MB;\r
141 \r
142   PageTable = (void *)malloc (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE);\r
143   memset (PageTable, 0, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE));\r
144   PageTablePtr = PageTable;\r
145 \r
146   PageAddress = 0;\r
147 \r
148   //\r
149   //  Page Table structure 3 level 2MB.\r
150   //\r
151   //                   Page-Map-Level-4-Table        : bits 47-39\r
152   //                   Page-Directory-Pointer-Table  : bits 38-30\r
153   //\r
154   //  Page Table 2MB : Page-Directory(2M)            : bits 29-21\r
155   //\r
156   //\r
157 \r
158   PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;\r
159 \r
160   for (PML4Index = 0; PML4Index < EFI_PML4_ENTRY_NUM; PML4Index++, PageMapLevel4Entry++) {\r
161     //\r
162     // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry\r
163     //  \r
164     PageTablePtr += EFI_SIZE_OF_PAGE;\r
165     PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;\r
166 \r
167     //\r
168     // Make a Page-Map-Level-4-Table Entry\r
169     //\r
170     PageMapLevel4Entry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry));\r
171     PageMapLevel4Entry->Bits.ReadWrite = 1;\r
172     PageMapLevel4Entry->Bits.Present = 1;\r
173 \r
174     for (PDPTEIndex = 0; PDPTEIndex < EFI_PDPTE_ENTRY_NUM; PDPTEIndex++, PageDirectoryPointerEntry++) {\r
175       //\r
176       // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry\r
177       //       \r
178       PageTablePtr += EFI_SIZE_OF_PAGE;\r
179       PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)PageTablePtr;\r
180 \r
181       //\r
182       // Make a Page-Directory-Pointer-Table Entry\r
183       //\r
184       PageDirectoryPointerEntry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB));\r
185       PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
186       PageDirectoryPointerEntry->Bits.Present = 1;\r
187 \r
188       for (PDEIndex = 0; PDEIndex < EFI_PDE_ENTRY_NUM; PDEIndex++, PageDirectoryEntry2MB++) {\r
189         //\r
190         // Make a Page-Directory Entry\r
191         //\r
192         PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;\r
193         PageDirectoryEntry2MB->Bits.ReadWrite = 1;\r
194         PageDirectoryEntry2MB->Bits.Present = 1;\r
195         PageDirectoryEntry2MB->Bits.MustBe1 = 1;\r
196 \r
197         PageAddress += EFI_PAGE_SIZE_2M;\r
198       }\r
199     }\r
200   }\r
201 \r
202   return PageTable;\r
203 }\r
204 \r
205 INT32\r
206 GenBinPage (\r
207   void *BaseMemory,\r
208   char *NoPageFileName,\r
209   char *PageFileName\r
210   )\r
211 /*++\r
212 \r
213 Routine Description:\r
214   Write the buffer containing page table to file at a specified offset.\r
215   Here the offset is defined as EFI_PAGE_BASE_OFFSET_IN_LDR.\r
216 \r
217 Arguments:\r
218   BaseMemory     - buffer containing page table\r
219   NoPageFileName - file to write page table\r
220   PageFileName   - file save to after writing\r
221 \r
222 return:\r
223   0  : successful\r
224   -1 : failed\r
225 \r
226 --*/\r
227 {\r
228   FILE  *PageFile;\r
229   FILE  *NoPageFile;\r
230   UINT8 Data;\r
231   unsigned long FileSize;\r
232 \r
233   //\r
234   // Open files\r
235   //\r
236   PageFile = fopen (PageFileName, "w+b");\r
237   if (PageFile == NULL) {\r
238     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Output File %s open failure", PageFileName);\r
239     return -1;\r
240   }\r
241 \r
242   NoPageFile = fopen (NoPageFileName, "r+b");\r
243   if (NoPageFile == NULL) {\r
244     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input File %s open failure", NoPageFileName);\r
245     fclose (PageFile);\r
246     return -1;\r
247   }\r
248 \r
249   //\r
250   // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR\r
251   //\r
252   fseek (NoPageFile, 0, SEEK_END);\r
253   FileSize = ftell (NoPageFile);\r
254   fseek (NoPageFile, 0, SEEK_SET);\r
255   if (FileSize > gPageTableOffsetInFile) {\r
256     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input file size (0x%lx) exceeds the Page Table Offset (0x%x)", FileSize, (unsigned) gPageTableOffsetInFile);\r
257     fclose (PageFile);\r
258     fclose (NoPageFile);\r
259     return -1;\r
260   }\r
261 \r
262   //\r
263   // Write data\r
264   //\r
265   while (fread (&Data, sizeof(UINT8), 1, NoPageFile)) {\r
266     fwrite (&Data, sizeof(UINT8), 1, PageFile);\r
267   }\r
268 \r
269   //\r
270   // Write PageTable\r
271   //\r
272   fseek (PageFile, gPageTableOffsetInFile, SEEK_SET);\r
273   fwrite (BaseMemory, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE), 1, PageFile);\r
274 \r
275   //\r
276   // Close files\r
277   //\r
278   fclose (PageFile);\r
279   fclose (NoPageFile);\r
280 \r
281   return 0;\r
282 }\r
283 \r
284 int\r
285 main (\r
286   int argc,\r
287   char **argv\r
288   )\r
289 {\r
290   VOID        *BaseMemory;\r
291   INTN        result;\r
292   CHAR8       *OutputFile = NULL;\r
293   CHAR8       *InputFile = NULL;\r
294   EFI_STATUS  Status;\r
295   UINT64      TempValue;\r
296 \r
297   SetUtilityName("GenPage");\r
298 \r
299   if (argc == 1) {\r
300     Usage();\r
301     return STATUS_ERROR;\r
302   }\r
303   \r
304   argc --;\r
305   argv ++;\r
306 \r
307   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
308     Usage();\r
309     return 0;    \r
310   }\r
311 \r
312   if (stricmp (argv[0], "--version") == 0) {\r
313     Version();\r
314     return 0;    \r
315   }\r
316   \r
317   while (argc > 0) {\r
318     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {\r
319       if (argv[1] == NULL || argv[1][0] == '-') {\r
320         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");\r
321         return STATUS_ERROR;\r
322       }\r
323       OutputFile = argv[1];\r
324       argc -= 2;\r
325       argv += 2;\r
326       continue; \r
327     }\r
328     \r
329     if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) {\r
330       if (argv[1] == NULL || argv[1][0] == '-') {\r
331         Error (NULL, 0, 1003, "Invalid option value", "Base address is missing for -b option");\r
332         return STATUS_ERROR;\r
333       }\r
334       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);\r
335       if (EFI_ERROR (Status)) {\r
336         Error (NULL, 0, 1003, "Invalid option value", "Base address is not valid intergrator");\r
337         return STATUS_ERROR;\r
338       }\r
339       gPageTableBaseAddress = (UINT32) TempValue;\r
340       argc -= 2;\r
341       argv += 2;\r
342       continue; \r
343     }\r
344     \r
345     if ((stricmp (argv[0], "-f") == 0) || (stricmp (argv[0], "--offset") == 0)) {\r
346       if (argv[1] == NULL || argv[1][0] == '-') {\r
347         Error (NULL, 0, 1003, "Invalid option value", "Offset is missing for -f option");\r
348         return STATUS_ERROR;\r
349       }\r
350       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);\r
351       if (EFI_ERROR (Status)) {\r
352         Error (NULL, 0, 1003, "Invalid option value", "Offset is not valid intergrator");\r
353         return STATUS_ERROR;\r
354       }\r
355       gPageTableOffsetInFile = (UINT32) TempValue;\r
356       argc -= 2;\r
357       argv += 2;\r
358       continue; \r
359     }\r
360 \r
361     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {\r
362       argc --;\r
363       argv ++;\r
364       continue; \r
365     }\r
366     \r
367     if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) {\r
368       argc --;\r
369       argv ++;\r
370       continue; \r
371     }\r
372     \r
373     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {\r
374       if (argv[1] == NULL || argv[1][0] == '-') {\r
375         Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not specified.");\r
376         return STATUS_ERROR;\r
377       }\r
378       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);\r
379       if (EFI_ERROR (Status)) {\r
380         Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator.");\r
381         return STATUS_ERROR;\r
382       }\r
383       if (TempValue > 9) {\r
384         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue);\r
385         return STATUS_ERROR;\r
386       }\r
387       argc -= 2;\r
388       argv += 2;\r
389       continue; \r
390     }\r
391 \r
392     if (argv[0][0] == '-') {\r
393       Error (NULL, 0, 1000, "Unknown option", argv[0]);\r
394       return STATUS_ERROR;\r
395     }\r
396     \r
397     //\r
398     // Don't recognize the paramter.\r
399     //\r
400     InputFile = argv[0];\r
401     argc--;\r
402     argv++;\r
403   }\r
404   \r
405   if (InputFile == NULL) {\r
406     Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified");\r
407     return STATUS_ERROR;\r
408   }\r
409   \r
410   //\r
411   // Create X64 page table\r
412   //\r
413   BaseMemory = CreateIdentityMappingPageTables ();\r
414 \r
415   //\r
416   // Add page table to binary file\r
417   //\r
418   result = GenBinPage (BaseMemory, InputFile, OutputFile);\r
419   if (result < 0) {\r
420     return STATUS_ERROR;\r
421   }\r
422 \r
423   return 0;\r
424 }\r
425 \r