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