Add support for.sdata sections
[mirror_edk2.git] / Tools / CCode / Source / GenAcpiTable / GenAcpiTable.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 2004-2006 Intel Corporation. All rights reserved\r
4This program and the accompanying materials are licensed and made available \r
5under the terms and conditions of the BSD License which accompanies this \r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
d25c4bf0 11\r
12Module Name:\r
13\r
14 GenAcpiTable.c\r
15 \r
16Abstract:\r
17\r
18 A utility that extracts the .DATA section from a PE/COFF image.\r
19\r
20--*/\r
21\r
22#include <stdio.h>\r
23#include <string.h>\r
24#include <stdlib.h>\r
25\r
ce53a8c3 26#include <Common/UefiBaseTypes.h>\r
27#include <Common/EfiImage.h> // for PE32 structure definitions\r
28\r
29#include "CommonLib.h"\r
d25c4bf0 30#include "EfiUtilityMsgs.h"\r
31\r
32//\r
33// Version of this utility\r
34//\r
35#define UTILITY_NAME "GenAcpiTable"\r
36#define UTILITY_VERSION "v0.11"\r
37\r
38//\r
39// Define the max length of a filename\r
40//\r
41#define MAX_PATH 256\r
42#define DEFAULT_OUTPUT_EXTENSION ".acpi"\r
43\r
44//\r
45// Use this to track our command-line options and globals\r
46//\r
47struct {\r
48 INT8 OutFileName[MAX_PATH];\r
49 INT8 InFileName[MAX_PATH];\r
50} mOptions;\r
51\r
52//\r
53// Use these to convert from machine type value to a named type\r
54//\r
55typedef struct {\r
56 UINT16 Value;\r
57 INT8 *Name;\r
58} STRING_LOOKUP;\r
59\r
60static STRING_LOOKUP mMachineTypes[] = {\r
61 EFI_IMAGE_MACHINE_IA32,\r
62 "IA32",\r
63 EFI_IMAGE_MACHINE_IA64,\r
64 "IA64",\r
65 EFI_IMAGE_MACHINE_EBC,\r
66 "EBC",\r
67 0,\r
68 NULL\r
69};\r
70\r
71static STRING_LOOKUP mSubsystemTypes[] = {\r
72 EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,\r
73 "EFI application",\r
74 EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,\r
75 "EFI boot service driver",\r
76 EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,\r
77 "EFI runtime driver",\r
78 0,\r
79 NULL\r
80};\r
81//\r
82// Function prototypes\r
83//\r
84static\r
85void\r
86Usage (\r
87 VOID\r
88 );\r
89\r
90static\r
91STATUS\r
92ParseCommandLine (\r
93 int Argc,\r
94 char *Argv[]\r
95 );\r
96\r
97static\r
98STATUS\r
99CheckPE32File (\r
100 INT8 *FileName,\r
101 FILE *Fptr,\r
102 UINT16 *MachineType,\r
103 UINT16 *SubSystem\r
104 );\r
105\r
106static\r
107STATUS\r
108ProcessFile (\r
109 INT8 *InFileName,\r
110 INT8 *OutFileName\r
111 );\r
112\r
113static\r
114void\r
115DumpImage (\r
116 INT8 *FileName\r
117 );\r
118\r
119main (\r
120 int Argc,\r
121 char *Argv[]\r
122 )\r
123/*++\r
124\r
125Routine Description:\r
126 \r
127\r
128Arguments:\r
129\r
130 Argc - standard C main() argument count\r
131\r
132 Argv - standard C main() argument list\r
133\r
134Returns:\r
135\r
136 0 success\r
137 non-zero otherwise\r
138\r
139--*/\r
140// GC_TODO: ] - add argument and description to function comment\r
141{\r
142 UINT32 Status;\r
143\r
144 SetUtilityName (UTILITY_NAME);\r
145 //\r
146 // Parse the command line arguments\r
147 //\r
148 if (ParseCommandLine (Argc, Argv)) {\r
149 return STATUS_ERROR;\r
150 }\r
151 //\r
152 // Make sure we don't have the same filename for input and output files\r
153 //\r
154 if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) {\r
155 Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different");\r
156 goto Finish;\r
157 }\r
158 //\r
159 // Process the file\r
160 //\r
161 ProcessFile (mOptions.InFileName, mOptions.OutFileName);\r
162Finish:\r
163 Status = GetUtilityStatus ();\r
164 return Status;\r
165}\r
166\r
167static\r
168STATUS\r
169ProcessFile (\r
170 INT8 *InFileName,\r
171 INT8 *OutFileName\r
172 )\r
173/*++\r
174\r
175Routine Description:\r
176 \r
177 Process a PE32 EFI file.\r
178\r
179Arguments:\r
180\r
181 InFileName - Name of the PE32 EFI file to process.\r
182 OutFileName - Name of the output file for the processed data.\r
183\r
184Returns:\r
185\r
186 0 - successful\r
187\r
188--*/\r
189{\r
190 STATUS Status;\r
191 UINTN Index;\r
192 FILE *InFptr;\r
193 FILE *OutFptr;\r
194 UINT16 MachineType;\r
195 UINT16 SubSystem;\r
196 UINT32 PESigOffset;\r
197 EFI_IMAGE_FILE_HEADER FileHeader;\r
198 EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32;\r
928fbe8f 199 EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64;\r
d25c4bf0 200 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
201 UINT8 *Buffer;\r
202 long SaveFilePosition;\r
203\r
204 InFptr = NULL;\r
205 OutFptr = NULL;\r
206 Buffer = NULL;\r
207 Status = STATUS_ERROR;\r
208 //\r
209 // Try to open the input file\r
210 //\r
211 if ((InFptr = fopen (InFileName, "rb")) == NULL) {\r
212 Error (NULL, 0, 0, InFileName, "failed to open input file for reading");\r
213 return STATUS_ERROR;\r
214 }\r
215 //\r
216 // Double-check the file to make sure it's what we expect it to be\r
217 //\r
218 if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) {\r
219 goto Finish;\r
220 }\r
221 //\r
222 // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit\r
223 // offset (from the start of the file) to the PE signature, which always\r
224 // follows the MSDOS stub. The PE signature is immediately followed by the\r
225 // COFF file header.\r
226 //\r
227 //\r
228 if (fseek (InFptr, 0x3C, SEEK_SET) != 0) {\r
229 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL);\r
230 goto Finish;\r
231 }\r
232\r
233 if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) {\r
234 Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file");\r
235 goto Finish;\r
236 }\r
237\r
238 if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) {\r
239 Error (NULL, 0, 0, InFileName, "failed to seek to PE signature");\r
240 goto Finish;\r
241 }\r
242 //\r
243 // We should now be at the COFF file header. Read it in and verify it's\r
244 // of an image type we support.\r
245 //\r
246 if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) {\r
247 Error (NULL, 0, 0, InFileName, "failed to read file header from image");\r
248 goto Finish;\r
249 }\r
250\r
251 if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64) && (FileHeader.Machine != EFI_IMAGE_MACHINE_X64)) {\r
252 Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine);\r
253 goto Finish;\r
254 }\r
255 //\r
256 // Read in the optional header. Assume PE32, and if not, then re-read as PE32+\r
257 //\r
258 SaveFilePosition = ftell (InFptr);\r
259 if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) {\r
260 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
261 goto Finish;\r
262 }\r
263\r
264 if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
265 if (fseek (InFptr, SaveFilePosition, SEEK_SET) != 0) {\r
266 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
267 goto Finish;\r
268 }\r
269\r
928fbe8f 270 if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) {\r
d25c4bf0 271 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
272 goto Finish;\r
273 }\r
274 }\r
275 //\r
276 // Search for the ".data" section\r
277 //\r
278 for (Index = 0; Index < FileHeader.NumberOfSections; Index++) {\r
279 if (fread (&SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER), 1, InFptr) != 1) {\r
280 Error (NULL, 0, 0, InFileName, "failed to read optional header from input file");\r
281 goto Finish;\r
282 }\r
283\r
c6137cfd 284 if (strcmp (SectionHeader.Name, ".data") == 0 || strcmp (SectionHeader.Name, ".sdata") == 0) {\r
d25c4bf0 285 if (fseek (InFptr, SectionHeader.PointerToRawData, SEEK_SET) != 0) {\r
286 Error (NULL, 0, 0, InFileName, "failed to seek to .data section");\r
287 goto Finish;\r
288 }\r
289\r
290 Buffer = (UINT8 *) malloc (SectionHeader.Misc.VirtualSize);\r
291 if (Buffer == NULL) {\r
292 Status = EFI_OUT_OF_RESOURCES;\r
293 goto Finish;\r
294 }\r
295 if (fread (Buffer, SectionHeader.Misc.VirtualSize, 1, InFptr) != 1) {\r
296 Error (NULL, 0, 0, InFileName, "failed to .data section");\r
297 goto Finish;\r
298 }\r
299 //\r
300 // Now open our output file\r
301 //\r
302 if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
303 Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
304 goto Finish;\r
305 }\r
306\r
307 if (fwrite (Buffer, SectionHeader.Misc.VirtualSize, 1, OutFptr) != 1) {\r
308 Error (NULL, 0, 0, OutFileName, "failed to write .data section");\r
309 goto Finish;\r
310 }\r
311\r
312 Status = STATUS_SUCCESS;\r
313 goto Finish;\r
314 }\r
315 }\r
316\r
317 Status = STATUS_ERROR;\r
318\r
319Finish:\r
320 if (InFptr != NULL) {\r
321 fclose (InFptr);\r
322 }\r
323 //\r
324 // Close the output file. If there was an error, delete the output file so\r
325 // that a subsequent build will rebuild it.\r
326 //\r
327 if (OutFptr != NULL) {\r
328 fclose (OutFptr);\r
329 if (GetUtilityStatus () == STATUS_ERROR) {\r
330 remove (OutFileName);\r
331 }\r
332 }\r
333\r
334 //\r
335 // Free up our buffer\r
336 //\r
337 if (Buffer != NULL) {\r
338 free (Buffer);\r
339 }\r
340\r
341 return Status;\r
342}\r
343\r
344static\r
345STATUS\r
346CheckPE32File (\r
347 INT8 *FileName,\r
348 FILE *Fptr,\r
349 UINT16 *MachineType,\r
350 UINT16 *SubSystem\r
351 )\r
352/*++\r
353\r
354Routine Description:\r
355\r
356 GC_TODO: Add function description\r
357\r
358Arguments:\r
359\r
360 FileName - GC_TODO: add argument description\r
361 Fptr - GC_TODO: add argument description\r
362 MachineType - GC_TODO: add argument description\r
363 SubSystem - GC_TODO: add argument description\r
364\r
365Returns:\r
366\r
367 GC_TODO: add return values\r
368\r
369--*/\r
370{\r
371 /*++\r
372\r
373Routine Description:\r
374 \r
375 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
376 PE32 image file, and then return the machine type in the supplied pointer.\r
377\r
378Arguments:\r
379\r
380 Fptr File pointer to the already-opened PE32 file\r
381 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
382 because the image may be Itanium-based, IA32, or EBC.\r
383\r
384Returns:\r
385\r
386 0 success\r
387 non-zero otherwise\r
388\r
389--*/\r
390 EFI_IMAGE_DOS_HEADER DosHeader;\r
391 EFI_IMAGE_FILE_HEADER FileHdr;\r
392 EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;\r
393 UINT32 PESig;\r
394 STATUS Status;\r
395\r
396 Status = STATUS_ERROR;\r
397 //\r
398 // Position to the start of the file\r
399 //\r
400 fseek (Fptr, 0, SEEK_SET);\r
401 //\r
402 // Read the DOS header\r
403 //\r
404 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
405 Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file");\r
406 goto Finish;\r
407 }\r
408 //\r
409 // Check the magic number (0x5A4D)\r
410 //\r
411 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
412 Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)");\r
413 goto Finish;\r
414 }\r
415 //\r
416 // Position into the file and check the PE signature\r
417 //\r
418 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
419 if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {\r
420 Error (NULL, 0, 0, FileName, "failed to read PE signature bytes");\r
421 goto Finish;\r
422 }\r
423 //\r
424 // Check the PE signature in the header "PE\0\0"\r
425 //\r
426 if (PESig != EFI_IMAGE_NT_SIGNATURE) {\r
427 Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)");\r
428 goto Finish;\r
429 }\r
430 //\r
431 // Read the file header\r
432 //\r
433 if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {\r
434 Error (NULL, 0, 0, FileName, "failed to read PE file header from input file");\r
435 goto Finish;\r
436 }\r
437 //\r
438 // Read the optional header so we can get the subsystem\r
439 //\r
440 if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) {\r
441 Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file");\r
442 goto Finish;\r
443 }\r
444\r
445 *SubSystem = OptionalHdr.Subsystem;\r
446 //\r
447 // Good to go\r
448 //\r
449 Status = STATUS_SUCCESS;\r
450Finish:\r
451 fseek (Fptr, 0, SEEK_SET);\r
452 return Status;\r
453}\r
454\r
455static\r
456int\r
457ParseCommandLine (\r
458 int Argc,\r
459 char *Argv[]\r
460 )\r
461/*++\r
462\r
463Routine Description:\r
464 \r
465 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
466 parse the command-line options and check their validity.\r
467\r
468\r
469Arguments:\r
470\r
471 Argc - standard C main() argument count\r
472 Argv - standard C main() argument list\r
473\r
474Returns:\r
475\r
476 STATUS_SUCCESS success\r
477 non-zero otherwise\r
478\r
479--*/\r
480// GC_TODO: ] - add argument and description to function comment\r
481{\r
482 //\r
483 // Clear out the options\r
484 //\r
485 memset ((char *) &mOptions, 0, sizeof (mOptions));\r
486 //\r
487 // Skip over the program name\r
488 //\r
489 Argc--;\r
490 Argv++;\r
491\r
492 if (Argc != 2) {\r
493 Usage ();\r
494 return STATUS_ERROR;\r
495 }\r
496\r
497 strcpy (mOptions.InFileName, Argv[0]);\r
498 //\r
499 // Next argument\r
500 //\r
501 Argv++;\r
502 Argc--;\r
503\r
504 strcpy (mOptions.OutFileName, Argv[0]);\r
505\r
506 return STATUS_SUCCESS;\r
507}\r
508\r
509static\r
510void\r
511Usage (\r
512 VOID\r
513 )\r
514/*++\r
515\r
516Routine Description:\r
517 \r
518 Print usage information for this utility.\r
519\r
520Arguments:\r
521\r
522 None.\r
523\r
524Returns:\r
525\r
526 Nothing.\r
527\r
528--*/\r
529{\r
530 int Index;\r
531 static const char *Msg[] = {\r
532 UTILITY_NAME " version "UTILITY_VERSION " - Generate ACPI Table image utility",\r
533 " Generate an ACPI Table image from an EFI PE32 image",\r
534 " Usage: "UTILITY_NAME " InFileName OutFileName",\r
535 " where:",\r
536 " InFileName - name of the input PE32 file",\r
537 " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION,\r
538 "",\r
539 NULL\r
540 };\r
541 for (Index = 0; Msg[Index] != NULL; Index++) {\r
542 fprintf (stdout, "%s\n", Msg[Index]);\r
543 }\r
544}\r