📄 efirom.c
字号:
fprintf(stdout, "ERROR: Failed to write all file bytes to output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
TotalSize -= FileSize;
//
// Pad the rest of the image to make it a multiple of 512 bytes
//
while (TotalSize > 0) {
putc (~0, OutFptr);
TotalSize--;
}
BailOut:
if (InFptr != NULL) {
fclose (InFptr);
}
if (Buffer != NULL) {
free (Buffer);
}
//
// Print the file name if errors occurred
//
if (Status != STATUS_SUCCESS) {
fprintf (stdout, "Error processing binary file %s\n", InFile->FileName);
}
return Status;
}
static
int
ProcessEfiFile (
FILE *OutFptr,
FILE_LIST *InFile,
UINT16 VendId,
UINT16 DevId,
UINT32 *Size
)
/*++
Routine Description:
Process a PE32 EFI file.
Arguments:
OutFptr - file pointer to output binary ROM image file we're creating
InFile - structure contains information on the PE32 file to process
VendId - vendor ID as required in the option ROM header
DevId - device ID as required in the option ROM header
Size - pointer to where to return the size added to the output file
Returns:
0 - successful
--*/
{
UINT32 Status;
FILE *InFptr;
EFI_PCI_EXPANSION_ROM_HEADER RomHdr;
PCI_DATA_STRUCTURE PciDs;
UINT32 FileSize, CompressedFileSize;
UINT8 *Buffer;
UINT8 *CompressedBuffer;
UINT8 *TempBufferPtr;
UINT32 TotalSize;
UINT32 HeaderSize;
UINT16 MachineType, SubSystem;
UINT32 HeaderPadBytes;
//
// 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;
}
//
// Initialize our buffer pointers to null.
//
Buffer = NULL;
CompressedBuffer = NULL;
//
// Double-check the file to make sure it's what we expect it to be
//
Status = CheckPE32File (InFptr, &MachineType, &SubSystem);
if (Status != STATUS_SUCCESS) {
goto BailOut;
}
//
// Seek to the end of the input file and get the file size
//
fseek (InFptr, 0, SEEK_END);
FileSize = ftell (InFptr);
//
// Get the size of the headers we're going to put in front of the image. The
// EFI header must be aligned on a 4-byte boundary, so pad accordingly.
//
if (sizeof (RomHdr) & 0x03) {
HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03);
} else {
HeaderPadBytes = 0;
}
HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes +
sizeof (EFI_PCI_EXPANSION_ROM_HEADER);
if (mOptions.Verbose) {
fprintf (stdout, " File size = 0x%X\n", FileSize);
}
//
// Allocate memory for the entire file (in case we have to compress), then
// seek back to the beginning of the file and read it into our buffer.
//
Buffer = (INT8 *) malloc (FileSize);
if (Buffer == NULL) {
fprintf (stdout, "ERROR: Memory allocation failed\n");
Status = STATUS_ERROR;
goto BailOut;
}
fseek (InFptr, 0, SEEK_SET);
if (fread (Buffer, FileSize, 1, InFptr) != 1) {
fprintf(stdout, "ERROR: Failed to read all bytes from input file\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Now determine the size of the final output file. It's either the header size
// plus the file's size, or the header size plus the compressed file size.
//
if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
//
// Allocate a buffer into which we can compress the image, compress it,
// and use that size as the new size.
//
CompressedBuffer = (INT8 *) malloc (FileSize);
if (CompressedBuffer == NULL) {
fprintf (stdout, "ERROR: Memory allocation failed\n");
Status = STATUS_ERROR;
goto BailOut;
}
CompressedFileSize = FileSize;
Status = Compress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize);
if (Status != STATUS_SUCCESS) {
fprintf (stdout, "ERROR: Compression failed\n");
goto BailOut;
}
//
// Now compute the size, then swap buffer pointers.
//
if (mOptions.Verbose) {
fprintf (stdout, " Comp size = 0x%X\n", CompressedFileSize);
}
TotalSize = CompressedFileSize + HeaderSize;
FileSize = CompressedFileSize;
TempBufferPtr = Buffer;
Buffer = CompressedBuffer;
CompressedBuffer = TempBufferPtr;
} else {
TotalSize = FileSize + HeaderSize;
}
//
// Total size must be an even multiple of 512 bytes
//
if (TotalSize & 0x1FF) {
TotalSize = (TotalSize + 0x200) & ~0x1ff;
}
//
// Check size
//
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;
//
// Now fill in the ROM header. These values come from chapter 18 of the
// EFI 1.02 specification.
//
memset (&RomHdr,0, sizeof (RomHdr));
RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
RomHdr.InitializationSize = (UINT16)(TotalSize / 512);
RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
RomHdr.EfiSubsystem = SubSystem;
RomHdr.EfiMachineType = MachineType;
RomHdr.EfiImageHeaderOffset = (UINT16)HeaderSize;
RomHdr.PcirOffset = (UINT16)(sizeof (RomHdr) + HeaderPadBytes);
//
// Set image as compressed or not
//
if (InFile->FileFlags & FILE_FLAG_COMPRESS) {
RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED;
}
//
// Fill in the PCI data structure
//
memset (&PciDs,0, sizeof (PCI_DATA_STRUCTURE));
PciDs.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
PciDs.VendorId = VendId;
PciDs.DeviceId = DevId;
PciDs.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE);
PciDs.Revision = 0;
//
// Class code and code revision from the command line (optional)
//
PciDs.ClassCode[0] = (UINT8)InFile->ClassCode;
PciDs.ClassCode[1] = (UINT8)(InFile->ClassCode >> 8);
PciDs.ClassCode[2] = (UINT8)(InFile->ClassCode >> 16);
PciDs.ImageLength = RomHdr.InitializationSize;
PciDs.CodeRevision = InFile->CodeRevision;
PciDs.CodeType = PCI_CODE_TYPE_EFI_IMAGE;
//
// If this is the last image, then set the LAST bit unless requested not
// to via the command-line -l argument.
//
if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {
PciDs.Indicator = INDICATOR_LAST;
}
//
// Write the ROM header to the output file
//
if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) {
fprintf (stdout, "ERROR: Failed to write ROM header to output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Write pad bytes to align the PciDs
//
while (HeaderPadBytes > 0) {
if (putc (0, OutFptr) == EOF) {
fprintf (stdout, "ERROR: Failed to write ROM header pad bytes to output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
HeaderPadBytes--;
}
//
// Write the PCI data structure header to the output file
//
if (fwrite (&PciDs, sizeof (PciDs), 1, OutFptr) != 1) {
fprintf (stdout, "ERROR: Failed to write PCI ROM header to output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
//
// Keep track of how many bytes left to write
//
TotalSize -= HeaderSize;
//
// Now dump the input file's contents to the output file
//
if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {
fprintf(stdout, "ERROR: Failed to write all file bytes to output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
TotalSize -= FileSize;
//
// Pad the rest of the image to make it a multiple of 512 bytes
//
while (TotalSize > 0) {
if (putc (~0, OutFptr) == EOF) {
fprintf (stdout, "ERROR: Failed to write trailing pad bytes output file\n");
Status = STATUS_ERROR;
goto BailOut;
}
TotalSize--;
}
BailOut:
if (InFptr != NULL) {
fclose (InFptr);
}
//
// Free up our buffers
//
if (Buffer != NULL) {
free (Buffer);
}
if (CompressedBuffer != NULL) {
free (CompressedBuffer);
}
//
// Print the file name if errors occurred
//
if (Status != STATUS_SUCCESS) {
fprintf (stdout, "Error processing EFI file %s\n", InFile->FileName);
}
return Status;
}
static
int
CheckPE32File (
FILE *Fptr,
UINT16 *MachineType,
UINT16 *SubSystem
)
{
/*++
Routine Description:
Given a file pointer to a supposed PE32 image file, verify that it is indeed a
PE32 image file, and then return the machine type in the supplied pointer.
Arguments:
Fptr File pointer to the already-opened PE32 file
MachineType Location to stuff the machine type of the PE32 file. This is needed
because the image may be Itanium-based, IA32, or EBC.
Returns:
0 success
non-zero otherwise
--*/
EFI_IMAGE_DOS_HEADER DosHeader;
EFI_IMAGE_FILE_HEADER FileHdr;
EFI_IMAGE_OPTIONAL_HEADER OptionalHdr;
UINT32 PESig;
//
// Position to the start of the file
//
fseek (Fptr, 0, SEEK_SET);
//
// Read the DOS header
//
if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) {
fprintf (stdout, "ERROR: Failed to read the DOS stub from the input file\n");
return STATUS_ERROR;
}
//
// Check the magic number (0x5A4D)
//
if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (magic number)\n");
return STATUS_ERROR;
}
//
// Position into the file and check the PE signature
//
fseek(Fptr, (long)DosHeader.e_lfanew, SEEK_SET);
if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) {
fprintf (stdout, "ERROR: Failed to read PE signature bytes from input file\n");
return STATUS_ERROR;
}
//
// Check the PE signature in the header "PE\0\0"
//
if (PESig != EFI_IMAGE_NT_SIGNATURE) {
fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (signature)\n");
return STATUS_ERROR;
}
//
// Read the file header and stuff their MachineType
//
if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) {
fprintf (stdout, "ERROR: Failed to read PE file header from input file\n");
return STATUS_ERROR;
}
memcpy ((char *)MachineType, &FileHdr.Machine, 2);
//
// Read the optional header so we can get the subsystem
//
if (fread (&OptionalHdr, sizeof(OptionalHdr), 1, Fptr) != 1) {
fprintf (stdout, "ERROR: Failed to read COFF optional header from input file\n");
return STATUS_ERROR;
}
*SubSystem = OptionalHdr.Subsystem;
if (mOptions.Verbose) {
fprintf (stdout, " Got subsystem = 0x%X from image\n", (int)*SubSystem);
}
//
// Good to go
//
return STATUS_SUCCESS;
}
static
int
ParseCommandLine (
int Argc,
char *Argv[],
OPTIONS *Options
)
/*++
Routine Description:
Given the Argc/Argv program arguments, and a pointer to an options structure,
parse the command-line options and check their validity.
Arguments:
Argc - standard C main() argument count
Argv - standard C main() argument list
Options - pointer to a structure to store the options in
Returns:
STATUS_SUCCESS success
non-zero otherwise
--*/
{
FILE_LIST *FileList, *PrevFileList;
UINT32 FileFlags;
UINT32 ClassCode;
UINT32 CodeRevision;
FileFlags = 0;
//
// Clear out the options
//
memset ((char *)Options, 0, sizeof (OPTIONS));
//
// To avoid compile warnings
//
FileList = PrevFileList = NULL;
ClassCode = 0;
CodeRevision = 0;
//
// Skip over the program name
//
Argc--;
Argv++;
//
// If no arguments, assume they want usage info
//
if (Argc == 0) {
Usage();
return STATUS_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -