📄 efirom.c
字号:
/*++
Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
EfiRom.c
Abstract:
Utility program to create an EFI option ROM image from binary and
EFI PE32 files.
--*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//
// Includes for EFI 1.1 build
//
#include "Efi.h" // required defines for Compress.h
#include "EfiImage.h" // for PE32 structure definitions
#include "Compress.h" // for compression function
#include "Pci22.h" // for option ROM header structures
//
// Version of this utility
//
#define UTILITY_VERSION "v2.5"
//
// Define some status return values
//
#define STATUS_SUCCESS 0
#define STATUS_WARNING 1
#define STATUS_ERROR 2
//
// Define the max length of a filename
//
#define MAX_PATH 200
#define DEFAULT_OUTPUT_EXTENSION ".rom"
//
// Max size for an option ROM image
//
#define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB
//
// Values for the indicator field in the PCI data structure
//
#define INDICATOR_LAST 0x80 // last file in series of files
//
// Masks for the FILE_LIST.FileFlags field
//
#define FILE_FLAG_BINARY 0x01
#define FILE_FLAG_EFI 0x02
#define FILE_FLAG_COMPRESS 0x04
//
// Use this linked list structure to keep track of all the filenames
// specified on the command line.
//
typedef struct _FILE_LIST {
struct _FILE_LIST *Next;
INT8 *FileName;
UINT32 FileFlags;
UINT32 ClassCode;
UINT16 CodeRevision;
} FILE_LIST;
//
// Use this to track our command-line options
//
typedef struct {
INT8 OutFileName[MAX_PATH];
INT8 NoLast;
INT8 Verbose;
INT8 DumpOption;
UINT8 DevIdValid;
UINT8 VendIdValid;
UINT16 VendId;
UINT16 DevId;
FILE_LIST *FileList;
} OPTIONS;
//
// Make a global structure to keep track of command-line options
//
static OPTIONS mOptions;
//
// Use these to convert from machine type value to a named type
//
typedef struct {
UINT16 Value;
char *Name;
} STRING_LOOKUP;
static STRING_LOOKUP mMachineTypes[] = {
EFI_IMAGE_MACHINE_IA32, "IA32",
EFI_IMAGE_MACHINE_IA64, "IA64",
EFI_IMAGE_MACHINE_EBC, "EBC",
0, NULL
};
static STRING_LOOKUP mSubsystemTypes[] = {
EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application",
EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver",
EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver",
0, NULL
};
//
// Function prototypes
//
static
void
Usage ();
static
int
ParseCommandLine (
int Argc,
char *Argv[],
OPTIONS *Options
);
static
int
CheckPE32File (
FILE *Fptr,
UINT16 *MachineType,
UINT16 *SubSystem
);
static
int
ProcessEfiFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT16 VendId,
UINT16 DevId,
UINT32 *Size
);
static
int
ProcessBinFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT32 *Size
);
static
void
DumpImage (
FILE_LIST *InFile
);
char *
GetMachineTypeStr (
UINT16 MachineType
);
static
char *
GetSubsystemTypeStr (
UINT16 SubsystemType
);
main(
int Argc,
char *Argv[]
)
/*++
Routine Description:
Given an EFI image filename, create a ROM-able image by creating an option
ROM header and PCI data structure, filling them in, and then writing the
option ROM header + PCI data structure + EFI image out to the output file.
Arguments:
Argc - standard C main() argument count
Argv - standard C main() argument list
Returns:
0 success
non-zero otherwise
--*/
{
INT8 *Ext;
FILE *FptrOut;
UINT32 Status;
FILE_LIST *FList;
UINT32 TotalSize, Size;
Status = STATUS_SUCCESS;
FptrOut = NULL;
//
// Parse the command line arguments
//
if (ParseCommandLine(Argc, Argv, &mOptions)) {
return STATUS_ERROR;
}
//
// If dumping an image, then do that and quit
//
if (mOptions.DumpOption) {
DumpImage (mOptions.FileList);
goto BailOut;
}
//
// Determine the output filename. Either what they specified on
// the command line, or the first input filename with a different extension.
//
if (!mOptions.OutFileName[0]) {
strcpy (mOptions.OutFileName, mOptions.FileList->FileName);
//
// Find the last . on the line and replace the filename extension with
// the default
//
for (Ext = mOptions.OutFileName + strlen(mOptions.OutFileName) - 1;
(Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\') ;
Ext--);
//
// If dot here, then insert extension here, otherwise append
//
if (*Ext != '.')
Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);
strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);
}
//
// Make sure we don't have the same filename for input and output files
//
for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
if (stricmp(mOptions.OutFileName, FList->FileName) == 0) {
Status = STATUS_ERROR;
fprintf(stdout, "ERROR: Input and output file names must be different - %s = %s\n",
FList->FileName, mOptions.OutFileName);
goto BailOut;
}
}
//
// Now open our output file
//
if ((FptrOut = fopen (mOptions.OutFileName, "w+b")) == NULL) {
fprintf (stdout, "ERROR: Failed to open output file %s\n", mOptions.OutFileName);
goto BailOut;
}
//
// Process all our files
//
TotalSize = 0;
for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {
Size = 0;
if (FList->FileFlags & FILE_FLAG_EFI) {
if (mOptions.Verbose) {
fprintf (stdout, "Processing EFI file %s\n", FList->FileName);
}
Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);
} else if (FList->FileFlags & FILE_FLAG_BINARY) {
if (mOptions.Verbose) {
fprintf (stdout, "Processing binary file %s\n", FList->FileName);
}
Status = ProcessBinFile (FptrOut, FList, &Size);
} else {
fprintf (stdout, "ERROR: File not specified as EFI or binary: %s\n", FList->FileName);
Status = STATUS_ERROR;
}
if (mOptions.Verbose) {
fprintf (stdout, " Output size = 0x%X\n", Size);
}
if (Status != STATUS_SUCCESS) {
break;
}
TotalSize += Size;
}
//
// Check total size
//
if (TotalSize > MAX_OPTION_ROM_SIZE) {
fprintf (stdout, "ERROR: Option ROM image size exceeds limit 0x%X bytes\n",
MAX_OPTION_ROM_SIZE);
Status = STATUS_ERROR;
}
BailOut:
if (FptrOut != NULL) {
fclose (FptrOut);
}
//
// Clean up our file list
//
while (mOptions.FileList != NULL) {
FList = mOptions.FileList->Next;
free (mOptions.FileList);
mOptions.FileList = FList;
}
return Status;
}
static
int
ProcessBinFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT32 *Size
)
/*++
Routine Description:
Process a binary input file.
Arguments:
OutFptr - file pointer to output binary ROM image file we're creating
InFile - structure contains information on the binary file to process
Size - pointer to where to return the size added to the output file
Returns:
0 - successful
--*/
{
FILE *InFptr;
UINT32 TotalSize;
UINT32 FileSize;
UINT8 *Buffer;
UINT32 Status;
PCI_EXPANSION_ROM_HEADER *RomHdr;
PCI_DATA_STRUCTURE *PciDs;
UINT32 Index;
UINT8 ByteCheckSum;
Status = STATUS_SUCCESS;
//
// Try to open the input file
//
if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {
fprintf (stdout, "ERROR: Failed to open input file %s\n", InFile->FileName);
return STATUS_ERROR;
}
//
// Seek to the end of the input file and get the file size. Then allocate
// a buffer to read it in to.
//
fseek (InFptr, 0, SEEK_END);
FileSize = ftell (InFptr);
if (mOptions.Verbose) {
fprintf (stdout, " File size = 0x%X\n", FileSize);
}
fseek (InFptr, 0, SEEK_SET);
Buffer = (INT8 *)malloc (FileSize);
if (Buffer == NULL) {
fprintf (stdout, "ERROR: Memory allocation failed\n");
Status = STATUS_ERROR;
goto BailOut;
}
if (fread (Buffer, FileSize, 1, InFptr) != 1) {
fprintf(stdout, "ERROR: Failed to read all bytes from input file\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Total size must be an even multiple of 512 bytes, and can't exceed
// the option ROM image size.
//
TotalSize = FileSize;
if (TotalSize & 0x1FF) {
TotalSize = (TotalSize + 0x200) & ~0x1ff;
}
if (TotalSize > MAX_OPTION_ROM_SIZE) {
fprintf (stdout, "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n",
InFile->FileName, MAX_OPTION_ROM_SIZE);
Status = STATUS_ERROR;
goto BailOut;
}
//
// Return the size to the caller so they can keep track of the running total.
//
*Size = TotalSize;
//
// Crude check to make sure it's a legitimate ROM image
//
RomHdr = (PCI_EXPANSION_ROM_HEADER *)Buffer;
if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
fprintf (stdout, "ERROR: ROM image file has invalid ROM signature\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Make sure the pointer to the PCI data structure is within the size of the image.
// Then check it for valid signature.
//
if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) {
fprintf (stdout, "ERROR: Invalid PCI data structure offset\n");
Status = STATUS_ERROR;
goto BailOut;
}
PciDs = (PCI_DATA_STRUCTURE *)(Buffer + RomHdr->PcirOffset);
if (PciDs->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
fprintf (stdout, "ERROR: PCI data structure has invalid signature\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// If this is the last image, then set the LAST bit unless requested not
// to via the command-line -l argument. Otherwise, make sure you clear it.
//
if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
PciDs->Indicator = INDICATOR_LAST;
} else {
PciDs->Indicator = 0;
}
ByteCheckSum = 0;
for (Index = 0; Index < FileSize - 1; Index++) {
ByteCheckSum = (UINT8)(ByteCheckSum + Buffer[Index]);
}
Buffer[FileSize-1] = (UINT8)((~ByteCheckSum) + 1);
fprintf (stdout, "CheckSUm = %02x\n", (UINT32)Buffer[FileSize-1]);
//
// Now copy the input file contents out to the output file
//
if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -