| /*++ | |
| Copyright (c) 1999-2006 Intel Corporation. All rights reserved | |
| This program and the accompanying materials are licensed and made available | |
| under the terms and conditions of the BSD License which accompanies this | |
| distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| SecFixup.c | |
| Abstract: | |
| This utility is part of build process for IA32 SEC FFS file. | |
| It fixup the reset vector data. The reset vector data binary file | |
| will be wrapped as a RAW section and be located immediately after | |
| the PE/TE section. | |
| The SEC EXE file can be either PE or TE file. | |
| --*/ | |
| #include <stdio.h> | |
| #include <Common/UefiBaseTypes.h> | |
| #include <Common/EfiImage.h> | |
| #include <Common/FirmwareVolumeImageFormat.h> | |
| #include "EfiUtilityMsgs.c" | |
| #include "SecFixup.h" | |
| VOID | |
| Version ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Displays the standard utility information to SDTOUT | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| printf ("%s v%d.%d -Tiano IA32 SEC Fixup Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION); | |
| printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n"); | |
| } | |
| VOID | |
| Usage ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Displays the utility usage syntax to STDOUT | |
| Arguments: | |
| None | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| Version(); | |
| printf ("\nUsage: %s SecExeFile ResetVectorDataFile OutputFile\n", UTILITY_NAME); | |
| printf (" Where:\n"); | |
| printf (" SecExeFile - Name of the IA32 SEC EXE file.\n"); | |
| printf (" ResetVectorDataFile - Name of the reset vector data binary file.\n"); | |
| printf (" OutputFileName - Name of the output file.\n"); | |
| } | |
| STATUS | |
| main ( | |
| IN INTN argc, | |
| IN CHAR8 **argv | |
| ) | |
| /*++ | |
| Routine Description: | |
| Main function. | |
| Arguments: | |
| argc - Number of command line parameters. | |
| argv - Array of pointers to parameter strings. | |
| Returns: | |
| STATUS_SUCCESS - Utility exits successfully. | |
| STATUS_ERROR - Some error occurred during execution. | |
| --*/ | |
| { | |
| FILE *FpIn; | |
| FILE *FpOut; | |
| UINT32 AddressOfEntryPoint; | |
| INT32 DestRel; | |
| STATUS Status; | |
| UINT32 SecFileSize; | |
| SetUtilityName (UTILITY_NAME); | |
| if (argc == 1) { | |
| Usage(); | |
| return STATUS_ERROR; | |
| } | |
| if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) || | |
| (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) { | |
| Usage(); | |
| return STATUS_ERROR; | |
| } | |
| if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) { | |
| Version(); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Verify the correct number of arguments | |
| // | |
| if (argc != MAX_ARGS) { | |
| Error (NULL, 0, 0, "invalid number of input parameters specified", NULL); | |
| Usage (); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Open the SEC exe file | |
| // | |
| if ((FpIn = fopen (argv[1], "rb")) == NULL) { | |
| Error (NULL, 0, 0, "Unable to open file", argv[1]); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Get the entry point of the EXE file | |
| // | |
| Status = GetEntryPoint (FpIn, &AddressOfEntryPoint); | |
| if (Status != STATUS_SUCCESS) { | |
| fclose (FpIn); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Get the SEC file size | |
| // | |
| fseek (FpIn, 0, SEEK_END); | |
| SecFileSize = ftell (FpIn); | |
| // | |
| // Close the SEC file | |
| // | |
| fclose (FpIn); | |
| // | |
| // Open the reset vector data file | |
| // | |
| if ((FpIn = fopen (argv[2], "rb")) == NULL) { | |
| Error (NULL, 0, 0, "Unable to open file", argv[2]); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Open the output file | |
| // | |
| if ((FpOut = fopen (argv[3], "w+b")) == NULL) { | |
| Error (NULL, 0, 0, "Unable to open file", argv[3]); | |
| fclose (FpIn); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Copy the input file to the output file | |
| // | |
| if (CopyFile (FpIn, FpOut) != STATUS_SUCCESS) { | |
| fclose (FpIn); | |
| fclose (FpOut); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Close the reset vector data file | |
| // | |
| fclose (FpIn); | |
| // | |
| // Fix the destination relative in the jmp instruction | |
| // in the reset vector data structure | |
| // | |
| fseek (FpOut, -DEST_REL_OFFSET, SEEK_END); | |
| DestRel = AddressOfEntryPoint - (SecFileSize + sizeof (EFI_COMMON_SECTION_HEADER) + (UINT32) (ftell (FpOut)) + 2); | |
| if (DestRel <= -65536) { | |
| Error (NULL, 0, 0, "The SEC EXE file size is too big", NULL); | |
| fclose (FpOut); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (&DestRel, sizeof (UINT16), 1, FpOut) != 1) { | |
| Error (NULL, 0, 0, "Failed to write to the output file", NULL); | |
| fclose (FpOut); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Close the output file | |
| // | |
| fclose (FpOut); | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| GetEntryPoint ( | |
| IN FILE *ExeFile, | |
| OUT UINT32 *EntryPoint | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get the address of the entry point of a PE/TE file. | |
| Arguments: | |
| PeFile - File pointer to the specified PE/TE file. | |
| EntryPoint - Buffer for the address of the entry point to be returned. | |
| Returns: | |
| STATUS_SUCCESS - Function completed successfully. | |
| STATUS_ERROR - Error occured. | |
| --*/ | |
| // GC_TODO: ExeFile - add argument and description to function comment | |
| { | |
| EFI_IMAGE_DOS_HEADER DosHeader; | |
| EFI_IMAGE_NT_HEADERS32 NtHeader; | |
| EFI_TE_IMAGE_HEADER TeHeader; | |
| // | |
| // Check if it is a TE file | |
| // | |
| fseek (ExeFile, 0, SEEK_SET); | |
| // | |
| // Attempt to read the TE header | |
| // | |
| if (fread (&TeHeader, sizeof (TeHeader), 1, ExeFile) == 1) { | |
| if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { | |
| if (TeHeader.Machine != EFI_IMAGE_MACHINE_IA32) { | |
| Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL); | |
| return STATUS_ERROR; | |
| } | |
| *EntryPoint = TeHeader.AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader.StrippedSize; | |
| return STATUS_SUCCESS; | |
| } | |
| } | |
| // | |
| // Check if it is a PE file | |
| // | |
| fseek (ExeFile, 0, SEEK_SET); | |
| // | |
| // Attempt to read the DOS header | |
| // | |
| if (fread (&DosHeader, sizeof (DosHeader), 1, ExeFile) != 1) { | |
| goto InvalidFile; | |
| } | |
| // | |
| // Check the magic number | |
| // | |
| if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { | |
| goto InvalidFile; | |
| } | |
| // | |
| // Position into the file and read the NT PE header | |
| // | |
| fseek (ExeFile, (long) DosHeader.e_lfanew, SEEK_SET); | |
| if (fread (&NtHeader, sizeof (NtHeader), 1, ExeFile) != 1) { | |
| goto InvalidFile; | |
| } | |
| // | |
| // Check the PE signature in the header | |
| // | |
| if (NtHeader.Signature != EFI_IMAGE_NT_SIGNATURE) { | |
| goto InvalidFile; | |
| } | |
| // | |
| // Make sure the PE file is PE32 for IA32 | |
| // | |
| if (NtHeader.FileHeader.Machine != EFI_IMAGE_MACHINE_IA32 || | |
| NtHeader.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC | |
| ) { | |
| Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Get the entry point from the optional header | |
| // | |
| *EntryPoint = NtHeader.OptionalHeader.AddressOfEntryPoint; | |
| return STATUS_SUCCESS; | |
| InvalidFile: | |
| Error (NULL, 0, 0, "The SEC file is neither PE nor TE file", NULL); | |
| return STATUS_ERROR; | |
| } | |
| STATUS | |
| CopyFile ( | |
| FILE *FpIn, | |
| FILE *FpOut | |
| ) | |
| /*++ | |
| Routine Description: | |
| Copy file. | |
| Arguments: | |
| FpIn - File pointer to the source file. | |
| FpOut - File pointer to the destination file. | |
| Returns: | |
| STATUS_SUCCESS - Function completed successfully. | |
| STATUS_ERROR - Error occured. | |
| --*/ | |
| { | |
| INTN FileSize; | |
| INTN Offset; | |
| INTN Length; | |
| UINT8 Buffer[BUF_SIZE]; | |
| fseek (FpIn, 0, SEEK_END); | |
| FileSize = ftell (FpIn); | |
| fseek (FpIn, 0, SEEK_SET); | |
| fseek (FpOut, 0, SEEK_SET); | |
| Offset = 0; | |
| while (Offset < FileSize) { | |
| Length = sizeof (Buffer); | |
| if (FileSize - Offset < Length) { | |
| Length = FileSize - Offset; | |
| } | |
| if (fread (Buffer, Length, 1, FpIn) != 1 || fwrite (Buffer, Length, 1, FpOut) != 1) { | |
| Error (NULL, 0, 0, "Copy file error", NULL); | |
| return STATUS_ERROR; | |
| } | |
| Offset += Length; | |
| } | |
| return STATUS_SUCCESS; | |
| } |