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