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