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