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