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