]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenPage/GenPage.c
BaseTools/GenPage: Fix potential memory leak
[mirror_edk2.git] / BaseTools / Source / C / GenPage / GenPage.c
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 - 2016, 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
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
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 *
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 if (PageTable == NULL) {
150 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
151 return NULL;
152 }
153 memset (PageTable, 0, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE));
154 PageTablePtr = PageTable;
155
156 PageAddress = 0;
157
158 //
159 // Page Table structure 3 level 2MB.
160 //
161 // Page-Map-Level-4-Table : bits 47-39
162 // Page-Directory-Pointer-Table : bits 38-30
163 //
164 // Page Table 2MB : Page-Directory(2M) : bits 29-21
165 //
166 //
167
168 PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
169
170 for (PML4Index = 0; PML4Index < EFI_PML4_ENTRY_NUM; PML4Index++, PageMapLevel4Entry++) {
171 //
172 // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry
173 //
174 PageTablePtr += EFI_SIZE_OF_PAGE;
175 PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
176
177 //
178 // Make a Page-Map-Level-4-Table Entry
179 //
180 PageMapLevel4Entry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry));
181 PageMapLevel4Entry->Bits.ReadWrite = 1;
182 PageMapLevel4Entry->Bits.Present = 1;
183
184 for (PDPTEIndex = 0; PDPTEIndex < EFI_PDPTE_ENTRY_NUM; PDPTEIndex++, PageDirectoryPointerEntry++) {
185 //
186 // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry
187 //
188 PageTablePtr += EFI_SIZE_OF_PAGE;
189 PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)PageTablePtr;
190
191 //
192 // Make a Page-Directory-Pointer-Table Entry
193 //
194 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB));
195 PageDirectoryPointerEntry->Bits.ReadWrite = 1;
196 PageDirectoryPointerEntry->Bits.Present = 1;
197
198 for (PDEIndex = 0; PDEIndex < EFI_PDE_ENTRY_NUM; PDEIndex++, PageDirectoryEntry2MB++) {
199 //
200 // Make a Page-Directory Entry
201 //
202 PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
203 PageDirectoryEntry2MB->Bits.ReadWrite = 1;
204 PageDirectoryEntry2MB->Bits.Present = 1;
205 PageDirectoryEntry2MB->Bits.MustBe1 = 1;
206
207 PageAddress += EFI_PAGE_SIZE_2M;
208 }
209 }
210 }
211
212 return PageTable;
213 }
214
215 INT32
216 GenBinPage (
217 void *BaseMemory,
218 char *NoPageFileName,
219 char *PageFileName
220 )
221 /*++
222
223 Routine Description:
224 Write the buffer containing page table to file at a specified offset.
225 Here the offset is defined as EFI_PAGE_BASE_OFFSET_IN_LDR.
226
227 Arguments:
228 BaseMemory - buffer containing page table
229 NoPageFileName - file to write page table
230 PageFileName - file save to after writing
231
232 return:
233 0 : successful
234 -1 : failed
235
236 --*/
237 {
238 FILE *PageFile;
239 FILE *NoPageFile;
240 UINT8 Data;
241 unsigned long FileSize;
242
243 //
244 // Open files
245 //
246 PageFile = fopen (LongFilePath (PageFileName), "w+b");
247 if (PageFile == NULL) {
248 Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Output File %s open failure", PageFileName);
249 return -1;
250 }
251
252 NoPageFile = fopen (LongFilePath (NoPageFileName), "r+b");
253 if (NoPageFile == NULL) {
254 Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input File %s open failure", NoPageFileName);
255 fclose (PageFile);
256 return -1;
257 }
258
259 //
260 // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR
261 //
262 fseek (NoPageFile, 0, SEEK_END);
263 FileSize = ftell (NoPageFile);
264 fseek (NoPageFile, 0, SEEK_SET);
265 if (FileSize > gPageTableOffsetInFile) {
266 Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input file size (0x%lx) exceeds the Page Table Offset (0x%x)", FileSize, (unsigned) gPageTableOffsetInFile);
267 fclose (PageFile);
268 fclose (NoPageFile);
269 return -1;
270 }
271
272 //
273 // Write data
274 //
275 while (fread (&Data, sizeof(UINT8), 1, NoPageFile)) {
276 fwrite (&Data, sizeof(UINT8), 1, PageFile);
277 }
278
279 //
280 // Write PageTable
281 //
282 fseek (PageFile, gPageTableOffsetInFile, SEEK_SET);
283 fwrite (BaseMemory, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE), 1, PageFile);
284
285 //
286 // Close files
287 //
288 fclose (PageFile);
289 fclose (NoPageFile);
290
291 return 0;
292 }
293
294 int
295 main (
296 int argc,
297 char **argv
298 )
299 {
300 VOID *BaseMemory;
301 INTN result;
302 CHAR8 *OutputFile = NULL;
303 CHAR8 *InputFile = NULL;
304 EFI_STATUS Status;
305 UINT64 TempValue;
306
307 SetUtilityName("GenPage");
308
309 if (argc == 1) {
310 Usage();
311 return STATUS_ERROR;
312 }
313
314 argc --;
315 argv ++;
316
317 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
318 Usage();
319 return 0;
320 }
321
322 if (stricmp (argv[0], "--version") == 0) {
323 Version();
324 return 0;
325 }
326
327 while (argc > 0) {
328 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
329 if (argv[1] == NULL || argv[1][0] == '-') {
330 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
331 return STATUS_ERROR;
332 }
333 OutputFile = argv[1];
334 argc -= 2;
335 argv += 2;
336 continue;
337 }
338
339 if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) {
340 if (argv[1] == NULL || argv[1][0] == '-') {
341 Error (NULL, 0, 1003, "Invalid option value", "Base address is missing for -b option");
342 return STATUS_ERROR;
343 }
344 Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
345 if (EFI_ERROR (Status)) {
346 Error (NULL, 0, 1003, "Invalid option value", "Base address is not valid intergrator");
347 return STATUS_ERROR;
348 }
349 gPageTableBaseAddress = (UINT32) TempValue;
350 argc -= 2;
351 argv += 2;
352 continue;
353 }
354
355 if ((stricmp (argv[0], "-f") == 0) || (stricmp (argv[0], "--offset") == 0)) {
356 if (argv[1] == NULL || argv[1][0] == '-') {
357 Error (NULL, 0, 1003, "Invalid option value", "Offset is missing for -f option");
358 return STATUS_ERROR;
359 }
360 Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
361 if (EFI_ERROR (Status)) {
362 Error (NULL, 0, 1003, "Invalid option value", "Offset is not valid intergrator");
363 return STATUS_ERROR;
364 }
365 gPageTableOffsetInFile = (UINT32) TempValue;
366 argc -= 2;
367 argv += 2;
368 continue;
369 }
370
371 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
372 argc --;
373 argv ++;
374 continue;
375 }
376
377 if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) {
378 argc --;
379 argv ++;
380 continue;
381 }
382
383 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
384 if (argv[1] == NULL || argv[1][0] == '-') {
385 Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not specified.");
386 return STATUS_ERROR;
387 }
388 Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
389 if (EFI_ERROR (Status)) {
390 Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator.");
391 return STATUS_ERROR;
392 }
393 if (TempValue > 9) {
394 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue);
395 return STATUS_ERROR;
396 }
397 argc -= 2;
398 argv += 2;
399 continue;
400 }
401
402 if (argv[0][0] == '-') {
403 Error (NULL, 0, 1000, "Unknown option", argv[0]);
404 return STATUS_ERROR;
405 }
406
407 //
408 // Don't recognize the parameter.
409 //
410 InputFile = argv[0];
411 argc--;
412 argv++;
413 }
414
415 if (InputFile == NULL) {
416 Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified");
417 return STATUS_ERROR;
418 }
419
420 //
421 // Create X64 page table
422 //
423 BaseMemory = CreateIdentityMappingPageTables ();
424 if (BaseMemory == NULL) {
425 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
426 return STATUS_ERROR;
427 }
428
429 //
430 // Add page table to binary file
431 //
432 result = GenBinPage (BaseMemory, InputFile, OutputFile);
433 if (result < 0) {
434 free (BaseMemory);
435 return STATUS_ERROR;
436 }
437
438 free (BaseMemory);
439 return 0;
440 }
441