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