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