]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/EfiRom/EfiRom.c
BaseTools/EfiRom: Fix potential memory leak
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
CommitLineData
30fdf114 1/** @file\r
97fa0ee9 2Utility program to create an EFI option ROM image from binary and EFI PE32 files.\r
30fdf114 3\r
02875ba2 4Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>\r
30fdf114
LG
5This program and the accompanying materials are licensed and made available \r
6under the terms and conditions of the BSD License which accompanies this \r
7distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
30fdf114
LG
13**/\r
14\r
15#include "EfiUtilityMsgs.h"\r
16#include "ParseInf.h"\r
17#include "EfiRom.h"\r
18\r
19UINT64 DebugLevel = 0;\r
20\r
21int\r
22main (\r
23 int Argc,\r
24 char *Argv[]\r
25 )\r
26/*++\r
27\r
28Routine Description:\r
29 \r
30 Given an EFI image filename, create a ROM-able image by creating an option \r
31 ROM header and PCI data structure, filling them in, and then writing the\r
32 option ROM header + PCI data structure + EFI image out to the output file.\r
33\r
34Arguments:\r
35\r
36 Argc - standard C main() argument count\r
37\r
38 Argv - standard C main() argument list\r
39\r
40Returns:\r
41\r
42 0 success\r
43 non-zero otherwise\r
44\r
45--*/\r
46{\r
47 CHAR8 *Ext;\r
48 FILE *FptrOut;\r
49 UINT32 Status;\r
50 FILE_LIST *FList;\r
51 UINT32 TotalSize;\r
52 UINT32 Size;\r
53 CHAR8 *Ptr0;\r
54\r
55 SetUtilityName(UTILITY_NAME);\r
56\r
57 Status = STATUS_SUCCESS;\r
58 FptrOut = NULL;\r
59\r
60 //\r
61 // Parse the command line arguments\r
62 //\r
63 if (ParseCommandLine (Argc, Argv, &mOptions)) {\r
64 return STATUS_ERROR;\r
65 }\r
66\r
67 if (mOptions.Quiet) {\r
68 SetPrintLevel(40);\r
69 } else if (mOptions.Verbose) {\r
70 SetPrintLevel(15);\r
71 } else if (mOptions.Debug) {\r
72 SetPrintLevel(DebugLevel);\r
73 }\r
74 \r
75 if (mOptions.Verbose) {\r
76 VerboseMsg("%s tool start.\n", UTILITY_NAME);\r
77 }\r
78 \r
79 //\r
80 // If dumping an image, then do that and quit\r
81 //\r
82 if (mOptions.DumpOption == 1) {\r
fd171542 83 if (mOptions.FileList != NULL) {\r
84 if ((Ptr0 = strstr ((CONST CHAR8 *) mOptions.FileList->FileName, DEFAULT_OUTPUT_EXTENSION)) != NULL) {\r
30fdf114
LG
85 DumpImage (mOptions.FileList);\r
86 goto BailOut;\r
87 } else {\r
88 Error (NULL, 0, 1002, "No PciRom input file", "No *.rom input file");\r
89 goto BailOut;\r
90 }\r
91 }\r
92 }\r
93 //\r
94 // Determine the output filename. Either what they specified on\r
95 // the command line, or the first input filename with a different extension.\r
96 //\r
97 if (!mOptions.OutFileName[0]) {\r
02875ba2
HW
98 if (mOptions.FileList != NULL) {\r
99 strcpy (mOptions.OutFileName, mOptions.FileList->FileName);\r
100 //\r
101 // Find the last . on the line and replace the filename extension with\r
102 // the default\r
103 //\r
104 for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
105 (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
106 Ext--\r
107 )\r
108 ;\r
109 //\r
110 // If dot here, then insert extension here, otherwise append\r
111 //\r
112 if (*Ext != '.') {\r
113 Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
114 }\r
30fdf114 115\r
02875ba2
HW
116 strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
117 }\r
30fdf114
LG
118 }\r
119 //\r
120 // Make sure we don't have the same filename for input and output files\r
121 //\r
122 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
123 if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {\r
124 Status = STATUS_ERROR;\r
99e55970 125 Error (NULL, 0, 1002, "Invalid input parameter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);\r
30fdf114
LG
126 goto BailOut;\r
127 }\r
128 }\r
129 //\r
130 // Now open our output file\r
131 //\r
1be2ed90 132 if ((FptrOut = fopen (LongFilePath (mOptions.OutFileName), "wb")) == NULL) {\r
30fdf114
LG
133 Error (NULL, 0, 0001, "Error opening file", "Error opening file %s", mOptions.OutFileName);\r
134 goto BailOut;\r
135 }\r
136 //\r
137 // Process all our files\r
138 //\r
139 TotalSize = 0;\r
140 for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
141 Size = 0;\r
142 if ((FList->FileFlags & FILE_FLAG_EFI) != 0) {\r
143 if (mOptions.Verbose) {\r
144 VerboseMsg("Processing EFI file %s\n", FList->FileName);\r
145 }\r
146\r
147 Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);\r
148 } else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {\r
149 if (mOptions.Verbose) {\r
150 VerboseMsg("Processing binary file %s\n", FList->FileName);\r
151 }\r
152\r
153 Status = ProcessBinFile (FptrOut, FList, &Size);\r
154 } else {\r
155 Error (NULL, 0, 2000, "Invalid parameter", "File type not specified, it must be either an EFI or binary file: %s.", FList->FileName);\r
156 Status = STATUS_ERROR;\r
157 }\r
158\r
159 if (mOptions.Verbose) {\r
fd171542 160 VerboseMsg(" Output size = 0x%X\n", (unsigned) Size);\r
30fdf114
LG
161 }\r
162\r
163 if (Status != STATUS_SUCCESS) {\r
164 break;\r
165 }\r
166\r
167 TotalSize += Size;\r
168 }\r
169 //\r
170 // Check total size\r
171 //\r
172 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
99e55970 173 Error (NULL, 0, 2000, "Invalid parameter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);\r
30fdf114
LG
174 Status = STATUS_ERROR;\r
175 }\r
176\r
177BailOut:\r
178 if (Status == STATUS_SUCCESS) {\r
179 if (FptrOut != NULL) {\r
180 fclose (FptrOut);\r
181 }\r
182 //\r
183 // Clean up our file list\r
184 //\r
185 while (mOptions.FileList != NULL) {\r
186 FList = mOptions.FileList->Next;\r
187 free (mOptions.FileList);\r
188 mOptions.FileList = FList;\r
189 }\r
190 }\r
191\r
192 if (mOptions.Verbose) {\r
193 VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());\r
194 }\r
195\r
196 return GetUtilityStatus (); \r
197}\r
198\r
199static\r
200int\r
201ProcessBinFile (\r
202 FILE *OutFptr,\r
203 FILE_LIST *InFile,\r
204 UINT32 *Size\r
205 )\r
206/*++\r
207\r
208Routine Description:\r
209 \r
210 Process a binary input file.\r
211\r
212Arguments:\r
213\r
214 OutFptr - file pointer to output binary ROM image file we're creating\r
215 InFile - structure contains information on the binary file to process\r
216 Size - pointer to where to return the size added to the output file\r
217\r
218Returns:\r
219\r
220 0 - successful\r
221\r
222--*/\r
223{\r
224 FILE *InFptr;\r
225 UINT32 TotalSize;\r
226 UINT32 FileSize;\r
227 UINT8 *Buffer;\r
228 UINT32 Status;\r
229 PCI_EXPANSION_ROM_HEADER *RomHdr;\r
230 PCI_DATA_STRUCTURE *PciDs23;\r
231 PCI_3_0_DATA_STRUCTURE *PciDs30;\r
232 UINT32 Index;\r
233 UINT8 ByteCheckSum;\r
2bc3256c 234 UINT16 CodeType;\r
30fdf114 235 \r
fd171542 236 PciDs23 = NULL;\r
237 PciDs30 = NULL;\r
30fdf114
LG
238 Status = STATUS_SUCCESS;\r
239\r
240 //\r
241 // Try to open the input file\r
242 //\r
1be2ed90 243 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
30fdf114
LG
244 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
245 return STATUS_ERROR;\r
246 }\r
247 //\r
248 // Seek to the end of the input file and get the file size. Then allocate\r
249 // a buffer to read it in to.\r
250 //\r
251 fseek (InFptr, 0, SEEK_END);\r
252 FileSize = ftell (InFptr);\r
253 if (mOptions.Verbose) {\r
fd171542 254 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
255 }\r
256\r
257 fseek (InFptr, 0, SEEK_SET);\r
258 Buffer = (UINT8 *) malloc (FileSize);\r
259 if (Buffer == NULL) {\r
260 Error (NULL, 0, 4003, "Resource", "memory cannot be allocated!");\r
261 Status = STATUS_ERROR;\r
262 goto BailOut;\r
263 }\r
264\r
265 if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
266 Error (NULL, 0, 2000, "Invalid", "Failed to read all bytes from input file.");\r
267 Status = STATUS_ERROR;\r
268 goto BailOut;\r
269 }\r
270 //\r
271 // Total size must be an even multiple of 512 bytes, and can't exceed\r
272 // the option ROM image size.\r
273 //\r
274 TotalSize = FileSize;\r
275 if (TotalSize & 0x1FF) {\r
276 TotalSize = (TotalSize + 0x200) &~0x1ff;\r
277 }\r
278\r
279 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
280 Error (NULL, 0, 3001, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);\r
281 Status = STATUS_ERROR;\r
282 goto BailOut;\r
283 }\r
284 //\r
285 // Return the size to the caller so they can keep track of the running total.\r
286 //\r
287 *Size = TotalSize;\r
288\r
289 //\r
290 // Crude check to make sure it's a legitimate ROM image\r
291 //\r
292 RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer;\r
293 if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {\r
294 Error (NULL, 0, 2000, "Invalid parameter", "ROM image file has an invalid ROM signature.");\r
295 Status = STATUS_ERROR;\r
296 goto BailOut;\r
297 }\r
298 //\r
299 // Make sure the pointer to the PCI data structure is within the size of the image.\r
300 // Then check it for valid signature.\r
301 //\r
302 if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {\r
303 Error (NULL, 0, 2000, "Invalid parameter", "Invalid PCI data structure offset.");\r
304 Status = STATUS_ERROR;\r
305 goto BailOut;\r
306 }\r
307\r
308 //\r
309 // Check the header is conform to PCI2.3 or PCI3.0\r
310 //\r
311 if (mOptions.Pci23 == 1) {\r
312 PciDs23 = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset);\r
313 if (PciDs23->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
314 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");\r
315 Status = STATUS_ERROR;\r
316 goto BailOut;\r
317 }\r
318 } else {\r
319 //\r
320 // Default setting is PCI3.0 header\r
321 //\r
322 PciDs30 = (PCI_3_0_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);\r
323 if (PciDs30->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {\r
324 Error (NULL, 0, 2000, "Invalid parameter", "PCI data structure has an invalid signature.");\r
325 Status = STATUS_ERROR;\r
326 goto BailOut;\r
327 }\r
328 }\r
329\r
330 //\r
331 // ReSet Option Rom size\r
332 //\r
333 if (mOptions.Pci23 == 1) {\r
334 PciDs23->ImageLength = (UINT16) (TotalSize / 512);\r
2bc3256c 335 CodeType = PciDs23->CodeType;\r
30fdf114
LG
336 } else {\r
337 PciDs30->ImageLength = (UINT16) (TotalSize / 512);\r
2bc3256c 338 CodeType = PciDs30->CodeType;\r
30fdf114
LG
339 }\r
340\r
341 //\r
342 // If this is the last image, then set the LAST bit unless requested not\r
343 // to via the command-line -n argument. Otherwise, make sure you clear it.\r
344 //\r
345 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
346 if (mOptions.Pci23 == 1) {\r
347 PciDs23->Indicator = INDICATOR_LAST;\r
348 } else {\r
349 PciDs30->Indicator = INDICATOR_LAST;\r
350 }\r
351 } else {\r
352 if (mOptions.Pci23 == 1) {\r
353 PciDs23->Indicator = 0;\r
354 } else {\r
355 PciDs30->Indicator = 0;\r
356 }\r
357 }\r
358\r
2bc3256c
LG
359 if (CodeType != PCI_CODE_TYPE_EFI_IMAGE) {\r
360 ByteCheckSum = 0;\r
361 for (Index = 0; Index < FileSize - 1; Index++) {\r
362 ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);\r
363 }\r
30fdf114 364\r
2bc3256c
LG
365 Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);\r
366 if (mOptions.Verbose) {\r
367 VerboseMsg(" Checksum = %02x\n\n", Buffer[FileSize - 1]);\r
368 }\r
30fdf114
LG
369 }\r
370\r
371 //\r
372 // Now copy the input file contents out to the output file\r
373 //\r
374 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
375 Error (NULL, 0, 0005, "Failed to write all file bytes to output file.", NULL);\r
376 Status = STATUS_ERROR;\r
377 goto BailOut;\r
378 }\r
379\r
380 TotalSize -= FileSize;\r
381 //\r
382 // Pad the rest of the image to make it a multiple of 512 bytes\r
383 //\r
384 while (TotalSize > 0) {\r
385 putc (~0, OutFptr);\r
386 TotalSize--;\r
387 }\r
388\r
389BailOut:\r
390 if (InFptr != NULL) {\r
391 fclose (InFptr);\r
392 }\r
393\r
394 if (Buffer != NULL) {\r
395 free (Buffer);\r
396 }\r
397 //\r
398 // Print the file name if errors occurred\r
399 //\r
400 if (Status != STATUS_SUCCESS) {\r
401 Error (NULL, 0, 0003, "Error", "Error parsing file: %s", InFile->FileName);\r
402 }\r
403\r
404 return Status;\r
405}\r
406\r
407static\r
408int\r
409ProcessEfiFile (\r
410 FILE *OutFptr,\r
411 FILE_LIST *InFile,\r
412 UINT16 VendId,\r
413 UINT16 DevId,\r
414 UINT32 *Size\r
415 )\r
416/*++\r
417\r
418Routine Description:\r
419 \r
420 Process a PE32 EFI file.\r
421\r
422Arguments:\r
423\r
424 OutFptr - file pointer to output binary ROM image file we're creating\r
425 InFile - structure contains information on the PE32 file to process\r
426 VendId - vendor ID as required in the option ROM header\r
427 DevId - device ID as required in the option ROM header\r
428 Size - pointer to where to return the size added to the output file\r
429\r
430Returns:\r
431\r
432 0 - successful\r
433\r
434--*/\r
435{\r
436 UINT32 Status;\r
437 FILE *InFptr;\r
438 EFI_PCI_EXPANSION_ROM_HEADER RomHdr;\r
439 PCI_DATA_STRUCTURE PciDs23;\r
440 PCI_3_0_DATA_STRUCTURE PciDs30;\r
441 UINT32 FileSize;\r
442 UINT32 CompressedFileSize;\r
443 UINT8 *Buffer;\r
444 UINT8 *CompressedBuffer;\r
445 UINT8 *TempBufferPtr;\r
446 UINT32 TotalSize;\r
447 UINT32 HeaderSize;\r
448 UINT16 MachineType;\r
449 UINT16 SubSystem;\r
450 UINT32 HeaderPadBytes;\r
2bc3256c
LG
451 UINT32 PadBytesBeforeImage;\r
452 UINT32 PadBytesAfterImage;\r
30fdf114
LG
453\r
454 //\r
455 // Try to open the input file\r
456 //\r
1be2ed90 457 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
30fdf114
LG
458 Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);\r
459 return STATUS_ERROR;\r
460 }\r
461 //\r
462 // Initialize our buffer pointers to null.\r
463 //\r
464 Buffer = NULL;\r
465 CompressedBuffer = NULL;\r
466\r
467 //\r
468 // Double-check the file to make sure it's what we expect it to be\r
469 //\r
470 Status = CheckPE32File (InFptr, &MachineType, &SubSystem);\r
471 if (Status != STATUS_SUCCESS) {\r
472 goto BailOut;\r
473 }\r
474 //\r
475 // Seek to the end of the input file and get the file size\r
476 //\r
477 fseek (InFptr, 0, SEEK_END);\r
478 FileSize = ftell (InFptr);\r
479\r
480 //\r
481 // Get the size of the headers we're going to put in front of the image. The\r
482 // EFI header must be aligned on a 4-byte boundary, so pad accordingly.\r
483 //\r
484 if (sizeof (RomHdr) & 0x03) {\r
485 HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);\r
486 } else {\r
487 HeaderPadBytes = 0;\r
488 }\r
489 \r
490 //\r
491 // For Pci3.0 to use the different data structure.\r
492 //\r
493 if (mOptions.Pci23 == 1) {\r
494 HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
495 } else {\r
496 HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
497 }\r
498\r
499 if (mOptions.Verbose) {\r
fd171542 500 VerboseMsg(" File size = 0x%X\n", (unsigned) FileSize);\r
30fdf114
LG
501 }\r
502 //\r
503 // Allocate memory for the entire file (in case we have to compress), then\r
504 // seek back to the beginning of the file and read it into our buffer.\r
505 //\r
506 Buffer = (UINT8 *) malloc (FileSize);\r
507 if (Buffer == NULL) {\r
508 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
509 Status = STATUS_ERROR;\r
510 goto BailOut;\r
511 }\r
512\r
513 fseek (InFptr, 0, SEEK_SET);\r
514 if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
515 Error (NULL, 0, 0004, "Error reading file", "File %s", InFile->FileName);\r
516 Status = STATUS_ERROR;\r
517 goto BailOut;\r
518 }\r
519 //\r
520 // Now determine the size of the final output file. It's either the header size\r
521 // plus the file's size, or the header size plus the compressed file size.\r
522 //\r
523 if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {\r
524 //\r
525 // Allocate a buffer into which we can compress the image, compress it,\r
526 // and use that size as the new size.\r
527 //\r
528 CompressedBuffer = (UINT8 *) malloc (FileSize);\r
529 if (CompressedBuffer == NULL) {\r
530 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
531 Status = STATUS_ERROR;\r
532 goto BailOut;\r
533 }\r
534\r
535 CompressedFileSize = FileSize;\r
536 Status = EfiCompress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);\r
537 if (Status != STATUS_SUCCESS) {\r
538 Error (NULL, 0, 0007, "Error compressing file!", NULL);\r
539 goto BailOut;\r
540 }\r
541 //\r
542 // Now compute the size, then swap buffer pointers.\r
543 //\r
544 if (mOptions.Verbose) {\r
fd171542 545 VerboseMsg(" Comp size = 0x%X\n", (unsigned) CompressedFileSize);\r
30fdf114
LG
546 }\r
547\r
548 TotalSize = CompressedFileSize + HeaderSize;\r
549 FileSize = CompressedFileSize;\r
550 TempBufferPtr = Buffer;\r
551 Buffer = CompressedBuffer;\r
552 CompressedBuffer = TempBufferPtr;\r
553 } else {\r
554 TotalSize = FileSize + HeaderSize;\r
555 }\r
556 //\r
557 // Total size must be an even multiple of 512 bytes\r
558 //\r
559 if (TotalSize & 0x1FF) {\r
560 TotalSize = (TotalSize + 0x200) &~0x1ff;\r
561 }\r
562 //\r
2bc3256c
LG
563 // Workaround:\r
564 // If compressed, put the pad bytes after the image,\r
565 // else put the pad bytes before the image.\r
566 //\r
567 if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {\r
568 PadBytesBeforeImage = 0;\r
569 PadBytesAfterImage = TotalSize - (FileSize + HeaderSize);\r
570 } else {\r
571 PadBytesBeforeImage = TotalSize - (FileSize + HeaderSize);\r
572 PadBytesAfterImage = 0;\r
573 }\r
574 //\r
30fdf114
LG
575 // Check size\r
576 //\r
577 if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
578 Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE); \r
579 Status = STATUS_ERROR;\r
580 goto BailOut;\r
581 }\r
582 //\r
583 // Return the size to the caller so they can keep track of the running total.\r
584 //\r
585 *Size = TotalSize;\r
586\r
587 //\r
588 // Now fill in the ROM header. These values come from chapter 18 of the\r
589 // EFI 1.02 specification.\r
590 //\r
591 memset (&RomHdr, 0, sizeof (RomHdr));\r
592 RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;\r
593 RomHdr.InitializationSize = (UINT16) (TotalSize / 512);\r
594 RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;\r
595 RomHdr.EfiSubsystem = SubSystem;\r
596 RomHdr.EfiMachineType = MachineType;\r
2bc3256c 597 RomHdr.EfiImageHeaderOffset = (UINT16) (HeaderSize + PadBytesBeforeImage);\r
30fdf114
LG
598 RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);\r
599 //\r
600 // Set image as compressed or not\r
601 //\r
602 if (InFile->FileFlags & FILE_FLAG_COMPRESS) {\r
603 RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;\r
604 }\r
605 //\r
606 // Fill in the PCI data structure\r
607 //\r
608 if (mOptions.Pci23 == 1) {\r
609 memset (&PciDs23, 0, sizeof (PCI_DATA_STRUCTURE));\r
610 } else {\r
611 memset (&PciDs30, 0, sizeof (PCI_3_0_DATA_STRUCTURE));\r
612 }\r
613\r
614 if (mOptions.Pci23 == 1) {\r
615 PciDs23.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
616 PciDs23.VendorId = VendId;\r
617 PciDs23.DeviceId = DevId;\r
618 PciDs23.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);\r
619 PciDs23.Revision = 0;\r
620 //\r
621 // Class code and code revision from the command line (optional)\r
622 //\r
623 PciDs23.ClassCode[0] = (UINT8) InFile->ClassCode;\r
624 PciDs23.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);\r
625 PciDs23.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);\r
626 PciDs23.ImageLength = RomHdr.InitializationSize;\r
627 PciDs23.CodeRevision = InFile->CodeRevision;\r
628 PciDs23.CodeType = PCI_CODE_TYPE_EFI_IMAGE;\r
629 } else {\r
630 PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
631 PciDs30.VendorId = VendId;\r
632 PciDs30.DeviceId = DevId;\r
633 PciDs30.DeviceListOffset = 0; // to be fixed\r
634 PciDs30.Length = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);\r
635 PciDs30.Revision = 0x3;\r
636 //\r
637 // Class code and code revision from the command line (optional)\r
638 //\r
639 PciDs30.ClassCode[0] = (UINT8) InFile->ClassCode;\r
640 PciDs30.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8);\r
641 PciDs30.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16);\r
642 PciDs30.ImageLength = RomHdr.InitializationSize;\r
643 PciDs30.CodeRevision = InFile->CodeRevision;\r
644 PciDs30.CodeType = PCI_CODE_TYPE_EFI_IMAGE;\r
645 PciDs30.MaxRuntimeImageLength = 0; // to be fixed\r
646 PciDs30.ConfigUtilityCodeHeaderOffset = 0; // to be fixed\r
647 PciDs30.DMTFCLPEntryPointOffset = 0; // to be fixed\r
648 }\r
649 //\r
650 // If this is the last image, then set the LAST bit unless requested not\r
651 // to via the command-line -n argument.\r
652 //\r
653 if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
654 if (mOptions.Pci23 == 1) {\r
655 PciDs23.Indicator = INDICATOR_LAST;\r
656 } else {\r
657 PciDs30.Indicator = INDICATOR_LAST;}\r
658 } else {\r
659 if (mOptions.Pci23 == 1) {\r
660 PciDs23.Indicator = 0;\r
661 } else {\r
662 PciDs30.Indicator = 0;\r
663 }\r
664 }\r
665 //\r
666 // Write the ROM header to the output file\r
667 //\r
668 if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {\r
669 Error (NULL, 0, 0002, "Failed to write ROM header to output file!", NULL);\r
670 Status = STATUS_ERROR;\r
671 goto BailOut;\r
672 }\r
673\r
674 //\r
675 // Write pad bytes to align the PciDs\r
676 //\r
677 while (HeaderPadBytes > 0) {\r
678 if (putc (0, OutFptr) == EOF) {\r
679 Error (NULL, 0, 0002, "Failed to write ROM header pad bytes to output file!", NULL);\r
680 Status = STATUS_ERROR;\r
681 goto BailOut;\r
682 }\r
683\r
684 HeaderPadBytes--;\r
685 }\r
686 //\r
687 // Write the PCI data structure header to the output file\r
688 //\r
689 if (mOptions.Pci23 == 1) {\r
690 if (fwrite (&PciDs23, sizeof (PciDs23), 1, OutFptr) != 1) {\r
691 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
692 Status = STATUS_ERROR;\r
693 goto BailOut;\r
694 } \r
695 } else {\r
696 if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {\r
697 Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
698 Status = STATUS_ERROR;\r
699 goto BailOut;\r
700 } \r
701 }\r
2bc3256c 702\r
30fdf114 703 //\r
2bc3256c 704 // Pad head to make it a multiple of 512 bytes\r
30fdf114 705 //\r
2bc3256c
LG
706 while (PadBytesBeforeImage > 0) {\r
707 if (putc (~0, OutFptr) == EOF) {\r
708 Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
709 Status = STATUS_ERROR;\r
710 goto BailOut;\r
711 }\r
712 PadBytesBeforeImage--;\r
713 }\r
30fdf114
LG
714 //\r
715 // Now dump the input file's contents to the output file\r
716 //\r
717 if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
718 Error (NULL, 0, 0002, "Failed to write all file bytes to output file!", NULL);\r
719 Status = STATUS_ERROR;\r
720 goto BailOut;\r
721 }\r
722\r
30fdf114
LG
723 //\r
724 // Pad the rest of the image to make it a multiple of 512 bytes\r
725 //\r
2bc3256c 726 while (PadBytesAfterImage > 0) {\r
30fdf114
LG
727 if (putc (~0, OutFptr) == EOF) {\r
728 Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
729 Status = STATUS_ERROR;\r
730 goto BailOut;\r
731 }\r
732\r
2bc3256c 733 PadBytesAfterImage--;\r
30fdf114
LG
734 }\r
735\r
736BailOut:\r
737 if (InFptr != NULL) {\r
738 fclose (InFptr);\r
739 }\r
740 //\r
741 // Free up our buffers\r
742 //\r
743 if (Buffer != NULL) {\r
744 free (Buffer);\r
745 }\r
746\r
747 if (CompressedBuffer != NULL) {\r
748 free (CompressedBuffer);\r
749 }\r
750 //\r
751 // Print the file name if errors occurred\r
752 //\r
753 if (Status != STATUS_SUCCESS) {\r
754 Error (NULL, 0, 0003, "Error parsing", "Error parsing file: %s", InFile->FileName);\r
755 }\r
756\r
757 return Status;\r
758}\r
759\r
760static\r
761int\r
762CheckPE32File (\r
763 FILE *Fptr,\r
764 UINT16 *MachineType,\r
765 UINT16 *SubSystem\r
766 )\r
767/*++\r
768\r
769Routine Description:\r
770 \r
771 Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
772 PE32 image file, and then return the machine type in the supplied pointer.\r
773\r
774Arguments:\r
775\r
776 Fptr File pointer to the already-opened PE32 file\r
777 MachineType Location to stuff the machine type of the PE32 file. This is needed\r
778 because the image may be Itanium-based, IA32, or EBC.\r
779\r
780Returns:\r
781\r
782 0 success\r
783 non-zero otherwise\r
784\r
785--*/\r
786{\r
787 EFI_IMAGE_DOS_HEADER DosHeader;\r
788 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
789\r
790 //\r
791 // Position to the start of the file\r
792 //\r
793 fseek (Fptr, 0, SEEK_SET);\r
794\r
795 //\r
796 // Read the DOS header\r
797 //\r
798 if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {\r
799 Error (NULL, 0, 0004, "Failed to read the DOS stub from the input file!", NULL);\r
800 return STATUS_ERROR;\r
801 }\r
802 //\r
803 // Check the magic number (0x5A4D)\r
804 //\r
805 if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
806 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (magic number)!");\r
807 return STATUS_ERROR;\r
808 }\r
809 //\r
810 // Position into the file and check the PE signature\r
811 //\r
812 fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET);\r
813\r
814 //\r
815 // Read PE headers\r
816 //\r
817 if (fread (&PeHdr, sizeof (PeHdr), 1, Fptr) != 1) {\r
818 Error (NULL, 0, 0004, "Failed to read PE/COFF headers from input file!", NULL);\r
819 return STATUS_ERROR;\r
820 }\r
821\r
822\r
823 //\r
824 // Check the PE signature in the header "PE\0\0"\r
825 //\r
826 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
827 Error (NULL, 0, 2000, "Invalid parameter", "Input file does not appear to be a PE32 image (signature)!");\r
828 return STATUS_ERROR;\r
829 }\r
830\r
831 memcpy ((char *) MachineType, &PeHdr.Pe32.FileHeader.Machine, 2);\r
832\r
833 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
834 *SubSystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
835 } else if (PeHdr.Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
836 *SubSystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
837 } else {\r
838 Error (NULL, 0, 2000, "Invalid parameter", "Unable to find subsystem type!");\r
839 return STATUS_ERROR;\r
840 }\r
841\r
842 if (mOptions.Verbose) {\r
fd171542 843 VerboseMsg(" Got subsystem = 0x%X from image\n", *SubSystem);\r
30fdf114
LG
844 }\r
845\r
846 //\r
847 // File was successfully identified as a PE32\r
848 //\r
849 return STATUS_SUCCESS;\r
850}\r
851\r
852static\r
853int\r
854ParseCommandLine (\r
855 int Argc,\r
856 char *Argv[],\r
857 OPTIONS *Options\r
858 )\r
859/*++\r
860\r
861Routine Description:\r
862 \r
863 Given the Argc/Argv program arguments, and a pointer to an options structure,\r
864 parse the command-line options and check their validity.\r
865\r
866\r
867Arguments:\r
868\r
869 Argc - standard C main() argument count\r
870 Argv[] - standard C main() argument list\r
871 Options - pointer to a structure to store the options in\r
872\r
873Returns:\r
874\r
875 STATUS_SUCCESS success\r
876 non-zero otherwise\r
877\r
878--*/\r
879{\r
880 FILE_LIST *FileList;\r
881 FILE_LIST *PrevFileList;\r
882 UINT32 FileFlags;\r
883 UINT32 ClassCode;\r
884 UINT32 CodeRevision;\r
885 EFI_STATUS Status;\r
fb4ea38c 886 INTN ReturnStatus;\r
30fdf114
LG
887 BOOLEAN EfiRomFlag;\r
888 UINT64 TempValue;\r
889\r
fb4ea38c 890 ReturnStatus = 0;\r
30fdf114
LG
891 FileFlags = 0;\r
892 EfiRomFlag = FALSE;\r
893\r
894 //\r
895 // Clear out the options\r
896 //\r
897 memset ((char *) Options, 0, sizeof (OPTIONS));\r
898\r
899 //\r
900 // To avoid compile warnings\r
901 //\r
902 FileList = PrevFileList = NULL;\r
903\r
904 ClassCode = 0;\r
905 CodeRevision = 0;\r
906 //\r
907 // Skip over the program name\r
908 //\r
909 Argc--;\r
910 Argv++;\r
911\r
912 //\r
913 // If no arguments, assume they want usage info\r
914 //\r
915 if (Argc == 0) {\r
916 Usage ();\r
917 return STATUS_ERROR;\r
918 }\r
919 \r
920 if ((stricmp(Argv[0], "-h") == 0) || (stricmp(Argv[0], "--help") == 0)) {\r
921 Usage();\r
922 return STATUS_ERROR;\r
923 }\r
924 \r
925 if ((stricmp(Argv[0], "--version") == 0)) {\r
926 Version();\r
927 return STATUS_ERROR;\r
928 }\r
929\r
930 //\r
931 // Process until no more arguments\r
932 //\r
933 while (Argc > 0) {\r
934 if (Argv[0][0] == '-') {\r
935 //\r
936 // Vendor ID specified with -f\r
937 //\r
938 if (stricmp (Argv[0], "-f") == 0) {\r
939 //\r
940 // Make sure there's another parameter\r
941 //\r
942 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
943 if (EFI_ERROR (Status)) {\r
944 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
945 ReturnStatus = 1;\r
946 goto Done;\r
30fdf114
LG
947 }\r
948 if (TempValue >= 0x10000) {\r
949 Error (NULL, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv[1]);\r
fb4ea38c
HW
950 ReturnStatus = 1;\r
951 goto Done;\r
30fdf114
LG
952 }\r
953 Options->VendId = (UINT16) TempValue;\r
954 Options->VendIdValid = 1;\r
955\r
956 Argv++;\r
957 Argc--;\r
958 } else if (stricmp (Argv[0], "-i") == 0) {\r
959 //\r
960 // Device ID specified with -i\r
961 // Make sure there's another parameter\r
962 //\r
963 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
964 if (EFI_ERROR (Status)) {\r
965 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
966 ReturnStatus = 1;\r
967 goto Done;\r
30fdf114
LG
968 }\r
969 if (TempValue >= 0x10000) {\r
970 Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);\r
fb4ea38c
HW
971 ReturnStatus = 1;\r
972 goto Done;\r
30fdf114
LG
973 }\r
974 Options->DevId = (UINT16) TempValue;\r
975 Options->DevIdValid = 1;\r
976\r
977 Argv++;\r
978 Argc--;\r
979 } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {\r
980 //\r
981 // Output filename specified with -o\r
982 // Make sure there's another parameter\r
983 //\r
984 if (Argv[1] == NULL || Argv[1][0] == '-') {\r
985 Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv[0]);\r
fb4ea38c
HW
986 ReturnStatus = STATUS_ERROR;\r
987 goto Done;\r
30fdf114 988 }\r
47affb48
HW
989 if (strlen (Argv[1]) > MAX_PATH - 1) {\r
990 Error (NULL, 0, 2000, "Invalid parameter", "Output file name %s is too long!", Argv[1]);\r
fb4ea38c
HW
991 ReturnStatus = STATUS_ERROR;\r
992 goto Done;\r
47affb48
HW
993 }\r
994 strncpy (Options->OutFileName, Argv[1], MAX_PATH - 1);\r
995 Options->OutFileName[MAX_PATH - 1] = 0;\r
30fdf114
LG
996\r
997 Argv++;\r
998 Argc--;\r
999 } else if ((stricmp (Argv[0], "-h") == 0) || (stricmp (Argv[0], "--help") == 0)) {\r
1000 //\r
1001 // Help option\r
1002 //\r
1003 Usage ();\r
fb4ea38c
HW
1004 ReturnStatus = STATUS_ERROR;\r
1005 goto Done;\r
30fdf114
LG
1006 } else if (stricmp (Argv[0], "-b") == 0) {\r
1007 //\r
1008 // Specify binary files with -b\r
1009 //\r
1010 FileFlags = FILE_FLAG_BINARY;\r
1011 } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) {\r
1012 //\r
1013 // Specify EFI files with -e. Specify EFI-compressed with -c.\r
1014 //\r
1015 FileFlags = FILE_FLAG_EFI;\r
1016 if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) {\r
1017 FileFlags |= FILE_FLAG_COMPRESS;\r
1018 }\r
1019 //\r
1020 // Specify not to set the LAST bit in the last file with -n\r
1021 //\r
1022 } else if (stricmp (Argv[0], "-n") == 0) {\r
1023 Options->NoLast = 1;\r
1024 } else if (((stricmp (Argv[0], "-v") == 0)) || ((stricmp (Argv[0], "--verbose") == 0))) {\r
1025 //\r
1026 // -v for verbose\r
1027 //\r
1028 Options->Verbose = 1;\r
1029 } else if (stricmp (Argv[0], "--debug") == 0) {\r
1030 Status = AsciiStringToUint64(Argv[1], FALSE, &DebugLevel);\r
1031 if (EFI_ERROR (Status)) {\r
1032 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1033 ReturnStatus = 1;\r
1034 goto Done;\r
30fdf114
LG
1035 }\r
1036 if (DebugLevel > 9) {\r
fd171542 1037 Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv[1]);\r
fb4ea38c
HW
1038 ReturnStatus = 1;\r
1039 goto Done;\r
30fdf114
LG
1040 }\r
1041 if (DebugLevel>=5 && DebugLevel<=9) {\r
1042 Options->Debug = TRUE;\r
1043 } else {\r
1044 Options->Debug = FALSE;\r
1045 }\r
1046 Argv++;\r
1047 Argc--;\r
1048 } else if ((stricmp (Argv[0], "--quiet") == 0) || (stricmp (Argv[0], "-q") == 0)) {\r
1049 Options->Quiet = TRUE;\r
1050 } else if ((stricmp (Argv[0], "--dump") == 0) || (stricmp (Argv[0], "-d") == 0)) {\r
1051 //\r
1052 // -dump for dumping a ROM image. In this case, say that the device id\r
1053 // and vendor id are valid so we don't have to specify bogus ones on the\r
1054 // command line.\r
1055 //\r
1056 Options->DumpOption = 1;\r
1057\r
1058 Options->VendIdValid = 1;\r
1059 Options->DevIdValid = 1;\r
1060 FileFlags = FILE_FLAG_BINARY;\r
1061 } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {\r
1062 //\r
1063 // Class code value for the next file in the list.\r
1064 // Make sure there's another parameter\r
1065 //\r
1066 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
1067 if (EFI_ERROR (Status)) {\r
1068 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1069 ReturnStatus = 1;\r
1070 goto Done;\r
30fdf114
LG
1071 }\r
1072 ClassCode = (UINT32) TempValue;\r
1073 if (ClassCode & 0xFF000000) {\r
1074 Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);\r
fb4ea38c
HW
1075 ReturnStatus = STATUS_ERROR;\r
1076 goto Done;\r
30fdf114
LG
1077 }\r
1078 if (FileList != NULL && FileList->ClassCode == 0) {\r
1079 FileList->ClassCode = ClassCode;\r
1080 }\r
1081 Argv++;\r
1082 Argc--;\r
1083 } else if ((stricmp (Argv[0], "-r") == 0) || (stricmp (Argv[0], "--Revision") == 0)) {\r
1084 //\r
1085 // Code revision in the PCI data structure. The value is for the next\r
1086 // file in the list.\r
1087 // Make sure there's another parameter\r
1088 //\r
1089 Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
1090 if (EFI_ERROR (Status)) {\r
1091 Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
fb4ea38c
HW
1092 ReturnStatus = 1;\r
1093 goto Done;\r
30fdf114
LG
1094 }\r
1095 CodeRevision = (UINT32) TempValue;\r
1096 if (CodeRevision & 0xFFFF0000) {\r
1097 Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);\r
fb4ea38c
HW
1098 ReturnStatus = STATUS_ERROR;\r
1099 goto Done;\r
30fdf114
LG
1100 }\r
1101 if (FileList != NULL && FileList->CodeRevision == 0) {\r
1102 FileList->CodeRevision = (UINT16) CodeRevision;\r
1103 }\r
1104 Argv++;\r
1105 Argc--;\r
1106 } else if ((stricmp (Argv[0], "-p") == 0) || (stricmp (Argv[0], "--pci23") == 0)) {\r
1107 //\r
1108 // Default layout meets PCI 3.0 specifications, specifying this flag will for a PCI 2.3 layout.\r
1109 //\r
1110 mOptions.Pci23 = 1;\r
1111 } else {\r
1112 Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);\r
fb4ea38c
HW
1113 ReturnStatus = STATUS_ERROR;\r
1114 goto Done;\r
30fdf114
LG
1115 }\r
1116 } else {\r
1117 //\r
1118 // Not a slash-option argument. Must be a file name. Make sure they've specified\r
1119 // -e or -b already.\r
1120 //\r
1121 if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {\r
1122 Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);\r
fb4ea38c
HW
1123 ReturnStatus = STATUS_ERROR;\r
1124 goto Done;\r
30fdf114
LG
1125 }\r
1126 //\r
1127 // Check Efi Option RomImage\r
1128 //\r
1129 if ((FileFlags & FILE_FLAG_EFI) == FILE_FLAG_EFI) {\r
1130 EfiRomFlag = TRUE;\r
1131 }\r
1132 //\r
1133 // Create a new file structure\r
1134 //\r
1135 FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
1136 if (FileList == NULL) {\r
1137 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);\r
fb4ea38c
HW
1138 ReturnStatus = STATUS_ERROR;\r
1139 goto Done;\r
30fdf114
LG
1140 }\r
1141 \r
1142 //\r
1143 // set flag and class code for this image.\r
1144 //\r
1145 memset ((char *) FileList, 0, sizeof (FILE_LIST));\r
1146 FileList->FileName = Argv[0];\r
1147 FileList->FileFlags = FileFlags;\r
1148 FileList->ClassCode = ClassCode;\r
1149 FileList->CodeRevision = (UINT16) CodeRevision;\r
1150 ClassCode = 0;\r
1151 CodeRevision = 0;\r
1152\r
1153 if (Options->FileList == NULL) {\r
1154 Options->FileList = FileList;\r
1155 } else {\r
1156 if (PrevFileList == NULL) {\r
1157 PrevFileList = FileList;\r
1158 } else { \r
1159 PrevFileList->Next = FileList;\r
1160 }\r
1161 }\r
1162\r
1163 PrevFileList = FileList;\r
1164 }\r
1165 //\r
1166 // Next argument\r
1167 //\r
1168 Argv++;\r
1169 Argc--;\r
1170 }\r
1171\r
1172 //\r
1173 // Must have specified some files\r
1174 //\r
1175 if (Options->FileList == NULL) {\r
1176 Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");\r
fb4ea38c
HW
1177 //\r
1178 // No memory allocation, return directly.\r
1179 //\r
30fdf114
LG
1180 return STATUS_ERROR;\r
1181 }\r
1182\r
1183 //\r
1184 // For EFI OptionRom image, Make sure a device ID and vendor ID are both specified.\r
1185 //\r
1186 if (EfiRomFlag) {\r
1187 if (!Options->VendIdValid) {\r
1188 Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);\r
fb4ea38c
HW
1189 ReturnStatus = STATUS_ERROR;\r
1190 goto Done;\r
30fdf114
LG
1191 }\r
1192 \r
1193 if (!Options->DevIdValid) {\r
1194 Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);\r
fb4ea38c
HW
1195 ReturnStatus = STATUS_ERROR;\r
1196 goto Done;\r
1197 }\r
1198 }\r
1199\r
1200Done:\r
1201 if (ReturnStatus != 0) {\r
1202 while (Options->FileList != NULL) {\r
1203 FileList = Options->FileList->Next;\r
1204 free (Options->FileList);\r
1205 Options->FileList = FileList;\r
30fdf114
LG
1206 }\r
1207 }\r
1208\r
fb4ea38c 1209 return ReturnStatus;\r
30fdf114
LG
1210}\r
1211\r
1212static\r
1213void\r
1214Version (\r
1215 VOID\r
1216 )\r
1217/*++\r
1218\r
1219Routine Description:\r
1220 \r
1221 Print version information for this utility.\r
1222\r
1223Arguments:\r
1224\r
1225 None.\r
1226\r
1227Returns:\r
1228\r
1229 Nothing.\r
1230--*/\r
1231{\r
b36d134f 1232 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
30fdf114
LG
1233}\r
1234 \r
1235static\r
1236void\r
1237Usage (\r
1238 VOID\r
1239 )\r
1240/*++\r
1241\r
1242Routine Description:\r
1243 \r
1244 Print usage information for this utility.\r
1245\r
1246Arguments:\r
1247\r
1248 None.\r
1249\r
1250Returns:\r
1251\r
1252 Nothing.\r
1253\r
1254--*/\r
1255{\r
1256 //\r
1257 // Summary usage\r
1258 //\r
d0acc87a 1259 fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME);\r
30fdf114
LG
1260 \r
1261 //\r
1262 // Copyright declaration\r
1263 // \r
1be2ed90 1264 fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");\r
30fdf114
LG
1265\r
1266 //\r
1267 // Details Option\r
1268 //\r
1269 fprintf (stdout, "Options:\n");\r
1270 fprintf (stdout, " -o FileName, --output FileName\n\\r
d0acc87a 1271 File will be created to store the output content.\n");\r
30fdf114
LG
1272 fprintf (stdout, " -e EfiFileName\n\\r
1273 EFI PE32 image files.\n");\r
1274 fprintf (stdout, " -ec EfiFileName\n\\r
1275 EFI PE32 image files and will be compressed.\n");\r
1276 fprintf (stdout, " -b BinFileName\n\\r
1277 Legacy binary files.\n");\r
1278 fprintf (stdout, " -l ClassCode\n\\r
1279 Hex ClassCode in the PCI data structure header.\n");\r
1280 fprintf (stdout, " -r Rev Hex Revision in the PCI data structure header.\n");\r
1281 fprintf (stdout, " -n Not to automatically set the LAST bit in the last file.\n");\r
1282 fprintf (stdout, " -f VendorId\n\\r
d0acc87a 1283 Hex PCI Vendor ID for the device OpROM, must be specified\n");\r
30fdf114 1284 fprintf (stdout, " -i DeviceId\n\\r
d0acc87a 1285 Hex PCI Device ID for the device OpROM, must be specified\n");\r
30fdf114
LG
1286 fprintf (stdout, " -p, --pci23\n\\r
1287 Default layout meets PCI 3.0 specifications\n\\r
1288 specifying this flag will for a PCI 2.3 layout.\n");\r
1289 fprintf (stdout, " -d, --dump\n\\r
1290 Dump the headers of an existing option ROM image.\n");\r
1291 fprintf (stdout, " -v, --verbose\n\\r
1292 Turn on verbose output with informational messages.\n");\r
1293 fprintf (stdout, " --version Show program's version number and exit.\n");\r
1294 fprintf (stdout, " -h, --help\n\\r
1295 Show this help message and exit.\n");\r
1296 fprintf (stdout, " -q, --quiet\n\\r
1297 Disable all messages except FATAL ERRORS.\n");\r
1298 fprintf (stdout, " --debug [#,0-9]\n\\r
1299 Enable debug messages at level #.\n"); \r
1300}\r
1301\r
1302static\r
1303void\r
1304DumpImage (\r
1305 FILE_LIST *InFile\r
1306 )\r
1307/*++\r
1308\r
1309Routine Description:\r
1310\r
1311 Dump the headers of an existing option ROM image\r
1312\r
1313Arguments:\r
1314\r
1315 InFile - the file name of an existing option ROM image\r
1316\r
1317Returns:\r
1318\r
1319 none\r
1320\r
1321--*/\r
1322{\r
1323 PCI_EXPANSION_ROM_HEADER PciRomHdr;\r
1324 FILE *InFptr;\r
1325 UINT32 ImageStart;\r
1326 UINT32 ImageCount;\r
1327 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr;\r
1328 PCI_DATA_STRUCTURE PciDs23;\r
1329 PCI_3_0_DATA_STRUCTURE PciDs30;\r
1330\r
1331 //\r
1332 // Open the input file\r
1333 //\r
1be2ed90 1334 if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
30fdf114
LG
1335 Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
1336 return ;\r
1337 }\r
1338 //\r
1339 // Go through the image and dump the header stuff for each\r
1340 //\r
1341 ImageCount = 0;\r
1342 for (;;) {\r
1343 //\r
1344 // Save our postition in the file, since offsets in the headers\r
1345 // are relative to the particular image.\r
1346 //\r
1347 ImageStart = ftell (InFptr);\r
1348 ImageCount++;\r
1349\r
1350 //\r
1351 // Read the option ROM header. Have to assume a raw binary image for now.\r
1352 //\r
1353 if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) {\r
1354 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI ROM header from file!");\r
1355 goto BailOut;\r
1356 }\r
1357\r
1358 //\r
1359 // Dump the contents of the header\r
1360 //\r
fd171542 1361 fprintf (stdout, "Image %u -- Offset 0x%X\n", (unsigned) ImageCount, (unsigned) ImageStart);\r
30fdf114 1362 fprintf (stdout, " ROM header contents\n");\r
fd171542 1363 fprintf (stdout, " Signature 0x%04X\n", PciRomHdr.Signature);\r
1364 fprintf (stdout, " PCIR offset 0x%04X\n", PciRomHdr.PcirOffset);\r
30fdf114
LG
1365 //\r
1366 // Find PCI data structure\r
1367 //\r
1368 if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) {\r
1369 Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI data structure!");\r
1370 goto BailOut;\r
1371 }\r
1372 //\r
1373 // Read and dump the PCI data structure\r
1374 //\r
1375 memset (&PciDs23, 0, sizeof (PciDs23));\r
1376 memset (&PciDs30, 0, sizeof (PciDs30));\r
1377 if (mOptions.Pci23 == 1) {\r
1378 if (fread (&PciDs23, sizeof (PciDs23), 1, InFptr) != 1) {\r
1379 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);\r
1380 goto BailOut;\r
1381 }\r
1382 } else {\r
1383 if (fread (&PciDs30, sizeof (PciDs30), 1, InFptr) != 1) {\r
1384 Error (NULL, 0, 3001, "Not supported", "Failed to read PCI data structure from file %s!", InFile->FileName);\r
1385 goto BailOut;\r
1386 }\r
1387 }\r
1388 if (mOptions.Verbose) {\r
1389 VerboseMsg("Read PCI data structure from file %s", InFile->FileName);\r
1390 }\r
1391\r
1392 //fprintf (stdout, " PCI Data Structure\n");\r
1393 if (mOptions.Pci23 == 1) {\r
1394 fprintf (\r
1395 stdout,\r
1396 " Signature %c%c%c%c\n",\r
1397 (char) PciDs23.Signature,\r
1398 (char) (PciDs23.Signature >> 8),\r
1399 (char) (PciDs23.Signature >> 16),\r
1400 (char) (PciDs23.Signature >> 24)\r
1401 );\r
1402 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs23.VendorId);\r
1403 fprintf (stdout, " Device ID 0x%04X\n", PciDs23.DeviceId);\r
1404 fprintf (stdout, " Length 0x%04X\n", PciDs23.Length);\r
1405 fprintf (stdout, " Revision 0x%04X\n", PciDs23.Revision);\r
1406 fprintf (\r
1407 stdout,\r
1408 " Class Code 0x%06X\n",\r
fd171542 1409 (unsigned) (PciDs23.ClassCode[0] | (PciDs23.ClassCode[1] << 8) | (PciDs23.ClassCode[2] << 16))\r
30fdf114 1410 );\r
fd171542 1411 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs23.ImageLength * 512);\r
30fdf114 1412 fprintf (stdout, " Code revision: 0x%04X\n", PciDs23.CodeRevision);\r
fd171542 1413 fprintf (stdout, " Indicator 0x%02X", PciDs23.Indicator);\r
30fdf114
LG
1414 } else {\r
1415 fprintf (\r
1416 stdout,\r
1417 " Signature %c%c%c%c\n",\r
1418 (char) PciDs30.Signature,\r
1419 (char) (PciDs30.Signature >> 8),\r
1420 (char) (PciDs30.Signature >> 16),\r
1421 (char) (PciDs30.Signature >> 24)\r
1422 );\r
1423 fprintf (stdout, " Vendor ID 0x%04X\n", PciDs30.VendorId);\r
1424 fprintf (stdout, " Device ID 0x%04X\n", PciDs30.DeviceId);\r
1425 fprintf (stdout, " Length 0x%04X\n", PciDs30.Length);\r
1426 fprintf (stdout, " Revision 0x%04X\n", PciDs30.Revision);\r
fd171542 1427 fprintf (stdout, " DeviceListOffset 0x%02X\n", PciDs30.DeviceListOffset); \r
30fdf114
LG
1428 fprintf (\r
1429 stdout,\r
1430 " Class Code 0x%06X\n",\r
fd171542 1431 (unsigned) (PciDs30.ClassCode[0] | (PciDs30.ClassCode[1] << 8) | (PciDs30.ClassCode[2] << 16))\r
30fdf114 1432 );\r
fd171542 1433 fprintf (stdout, " Image size 0x%X\n", (unsigned) PciDs30.ImageLength * 512);\r
30fdf114 1434 fprintf (stdout, " Code revision: 0x%04X\n", PciDs30.CodeRevision);\r
fd171542 1435 fprintf (stdout, " MaxRuntimeImageLength 0x%02X\n", PciDs30.MaxRuntimeImageLength);\r
1436 fprintf (stdout, " ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);\r
1437 fprintf (stdout, " DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset); \r
1438 fprintf (stdout, " Indicator 0x%02X", PciDs30.Indicator); \r
30fdf114
LG
1439 }\r
1440 //\r
1441 // Print the indicator, used to flag the last image\r
1442 //\r
1443 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {\r
1444 fprintf (stdout, " (last image)\n");\r
1445 } else {\r
1446 fprintf (stdout, "\n");\r
1447 }\r
1448 //\r
1449 // Print the code type. If EFI code, then we can provide more info.\r
1450 //\r
1451 if (mOptions.Pci23 == 1) {\r
fd171542 1452 fprintf (stdout, " Code type 0x%02X", PciDs23.CodeType);\r
30fdf114 1453 } else {\r
fd171542 1454 fprintf (stdout, " Code type 0x%02X", PciDs30.CodeType); \r
30fdf114
LG
1455 }\r
1456 if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
1457 fprintf (stdout, " (EFI image)\n");\r
1458 //\r
1459 // Re-read the header as an EFI ROM header, then dump more info\r
1460 //\r
1461 fprintf (stdout, " EFI ROM header contents\n");\r
1462 if (fseek (InFptr, ImageStart, SEEK_SET)) {\r
1463 Error (NULL, 0, 5001, "Failed to re-seek to ROM header structure!", NULL);\r
1464 goto BailOut;\r
1465 }\r
1466\r
1467 if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) {\r
1468 Error (NULL, 0, 5001, "Failed to read EFI PCI ROM header from file!", NULL);\r
1469 goto BailOut;\r
1470 }\r
1471 //\r
1472 // Now dump more info\r
1473 //\r
fd171542 1474 fprintf (stdout, " EFI Signature 0x%04X\n", (unsigned) EfiRomHdr.EfiSignature);\r
30fdf114
LG
1475 fprintf (\r
1476 stdout,\r
1477 " Compression Type 0x%04X ",\r
fd171542 1478 EfiRomHdr.CompressionType\r
30fdf114
LG
1479 );\r
1480 if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {\r
1481 fprintf (stdout, "(compressed)\n");\r
1482 } else {\r
1483 fprintf (stdout, "(not compressed)\n");\r
1484 }\r
1485\r
1486 fprintf (\r
1487 stdout,\r
1488 " Machine type 0x%04X (%s)\n",\r
1489 EfiRomHdr.EfiMachineType,\r
1490 GetMachineTypeStr (EfiRomHdr.EfiMachineType)\r
1491 );\r
1492 fprintf (\r
1493 stdout,\r
1494 " Subsystem 0x%04X (%s)\n",\r
1495 EfiRomHdr.EfiSubsystem,\r
1496 GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem)\r
1497 );\r
1498 fprintf (\r
1499 stdout,\r
1500 " EFI image offset 0x%04X (@0x%X)\n",\r
fd171542 1501 EfiRomHdr.EfiImageHeaderOffset,\r
1502 EfiRomHdr.EfiImageHeaderOffset + (unsigned) ImageStart\r
30fdf114
LG
1503 );\r
1504\r
1505 } else {\r
1506 //\r
1507 // Not an EFI image\r
1508 //\r
1509 fprintf (stdout, "\n");\r
1510 }\r
1511 //\r
1512 // If code type is EFI image, then dump it as well?\r
1513 //\r
1514 // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
1515 // }\r
1516 //\r
1517 // If last image, then we're done\r
1518 //\r
1519 if (PciDs23.Indicator == INDICATOR_LAST || PciDs30.Indicator == INDICATOR_LAST) {\r
1520 goto BailOut;\r
1521 }\r
1522 //\r
1523 // Seek to the start of the next image\r
1524 //\r
1525 if (mOptions.Pci23 == 1) {\r
1526 if (fseek (InFptr, ImageStart + (PciDs23.ImageLength * 512), SEEK_SET)) {\r
1527 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");\r
1528 goto BailOut;\r
1529 }\r
1530 } else {\r
1531 if (fseek (InFptr, ImageStart + (PciDs30.ImageLength * 512), SEEK_SET)) {\r
1532 Error (NULL, 0, 3001, "Not supported", "Failed to seek to next image!");\r
1533 goto BailOut;\r
1534 }\r
1535 }\r
1536 }\r
1537\r
1538BailOut:\r
1539 fclose (InFptr);\r
1540}\r
1541\r
1542char *\r
1543GetMachineTypeStr (\r
1544 UINT16 MachineType\r
1545 )\r
1546/*++\r
1547\r
1548Routine Description:\r
1549\r
1550 GC_TODO: Add function description\r
1551\r
1552Arguments:\r
1553\r
1554 MachineType - GC_TODO: add argument description\r
1555\r
1556Returns:\r
1557\r
1558 GC_TODO: add return values\r
1559\r
1560--*/\r
1561{\r
1562 int Index;\r
1563\r
1564 for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) {\r
1565 if (mMachineTypes[Index].Value == MachineType) {\r
1566 return mMachineTypes[Index].Name;\r
1567 }\r
1568 }\r
1569\r
1570 return "unknown";\r
1571}\r
1572\r
1573static\r
1574char *\r
1575GetSubsystemTypeStr (\r
1576 UINT16 SubsystemType\r
1577 )\r
1578/*++\r
1579\r
1580Routine Description:\r
1581\r
1582 GC_TODO: Add function description\r
1583\r
1584Arguments:\r
1585\r
1586 SubsystemType - GC_TODO: add argument description\r
1587\r
1588Returns:\r
1589\r
1590 GC_TODO: add return values\r
1591\r
1592--*/\r
1593{\r
1594 int Index;\r
1595\r
1596 for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) {\r
1597 if (mSubsystemTypes[Index].Value == SubsystemType) {\r
1598 return mSubsystemTypes[Index].Name;\r
1599 }\r
1600 }\r
1601\r
1602 return "unknown";\r
1603}\r