| /*++ | |
| i | |
| Copyright (c) 2004, 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: | |
| GenFvImageLib.c | |
| Abstract: | |
| This file contains functions required to generate a Firmware Volume. | |
| --*/ | |
| // | |
| // Include files | |
| // | |
| #ifdef __GNUC__ | |
| #include <uuid/uuid.h> | |
| #include <sys/stat.h> | |
| #endif | |
| #include <string.h> | |
| #ifndef __GNUC__ | |
| #include <io.h> | |
| #endif | |
| #include <assert.h> | |
| #include <Common/UefiBaseTypes.h> | |
| #include <Common/FirmwareVolumeImageFormat.h> | |
| #include <Common/Variable.h> | |
| #include <Common/WorkingBlockHeader.h> | |
| #include <Guid/FirmwareFileSystem.h> | |
| #include "GenFvImageLib.h" | |
| #include "GenFvImageLibInternal.h" | |
| #include "CommonLib.h" | |
| #include "Crc32.h" | |
| #include "EfiUtilityMsgs.h" | |
| #include "FvLib.h" | |
| #include "Compress.h" | |
| #include "WinNtInclude.h" | |
| // | |
| // Different file separater for Linux and Windows | |
| // | |
| #ifdef __GNUC__ | |
| #define FILE_SEP_CHAR '/' | |
| #define FILE_SEP_STRING "/" | |
| #else | |
| #define FILE_SEP_CHAR '\\' | |
| #define FILE_SEP_STRING "\\" | |
| #endif | |
| static UINT32 MaxFfsAlignment = 0; | |
| // | |
| // Local function prototypes | |
| // | |
| EFI_STATUS | |
| GetPe32Info ( | |
| IN UINT8 *Pe32, | |
| OUT UINT32 *EntryPoint, | |
| OUT UINT32 *BaseOfCode, | |
| OUT UINT16 *MachineType | |
| ); | |
| // | |
| // Local function implementations. | |
| // | |
| EFI_GUID FfsGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID; | |
| EFI_GUID DefaultFvPadFileNameGuid = { 0x78f54d4, 0xcc22, 0x4048, 0x9e, 0x94, 0x87, 0x9c, 0x21, 0x4d, 0x56, 0x2f }; | |
| // | |
| // This data array will be located at the base of the Firmware Volume Header (FVH) | |
| // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes | |
| // will be used to keep the FVH checksum consistent. | |
| // This code will be run in response to a starutp IPI for HT-enabled systems. | |
| // | |
| #define SIZEOF_STARTUP_DATA_ARRAY 0x10 | |
| UINT8 m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = { | |
| // | |
| // EA D0 FF 00 F0 ; far jmp F000:FFD0 | |
| // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes | |
| // 0, 0 ; Checksum Padding | |
| // | |
| 0xEA, | |
| 0xD0, | |
| 0xFF, | |
| 0x0, | |
| 0xF0, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00 | |
| }; | |
| UINT8 m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = { | |
| // | |
| // EB CE ; jmp short ($-0x30) | |
| // ; (from offset 0x0 to offset 0xFFD0) | |
| // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes | |
| // 0, 0 ; Checksum Padding | |
| // | |
| 0xEB, | |
| 0xCE, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00, | |
| 0x00 | |
| }; | |
| EFI_STATUS | |
| ParseFvInf ( | |
| IN MEMORY_FILE *InfFile, | |
| IN FV_INFO *FvInfo | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function parses a FV.INF file and copies info into a FV_INFO structure. | |
| Arguments: | |
| InfFile Memory file image. | |
| FvInfo Information read from INF file. | |
| Returns: | |
| EFI_SUCCESS INF file information successfully retrieved. | |
| EFI_ABORTED INF file has an invalid format. | |
| EFI_NOT_FOUND A required string was not found in the INF file. | |
| --*/ | |
| { | |
| CHAR8 Value[_MAX_PATH]; | |
| UINT64 Value64; | |
| UINTN Index; | |
| EFI_STATUS Status; | |
| // | |
| // Initialize FV info | |
| // | |
| memset (FvInfo, 0, sizeof (FV_INFO)); | |
| // | |
| // Read the FV base address | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Get the base address | |
| // | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "invalid value"); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->BaseAddress = Value64; | |
| } else { | |
| Error (NULL, 0, 0, EFI_FV_BASE_ADDRESS_STRING, "could not find value"); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Read the FV Guid | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_GUID_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Get the guid value | |
| // | |
| Status = StringToGuid (Value, &FvInfo->FvGuid); | |
| if (EFI_ERROR (Status)) { | |
| memcpy (&FvInfo->FvGuid, &FfsGuid, sizeof (EFI_GUID)); | |
| } | |
| } else { | |
| memcpy (&FvInfo->FvGuid, &FfsGuid, sizeof (EFI_GUID)); | |
| } | |
| // | |
| // Read the FV file name | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // copy the file name | |
| // | |
| strcpy (FvInfo->FvName, Value); | |
| } else { | |
| Error (NULL, 0, 0, EFI_FV_FILE_NAME_STRING, "value not specified"); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Read the Sym file name | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_SYM_FILE_NAME_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // copy the file name | |
| // | |
| strcpy (FvInfo->SymName, Value); | |
| } else { | |
| // | |
| // Symbols not required, so init to NULL. | |
| // | |
| strcpy (FvInfo->SymName, ""); | |
| } | |
| // | |
| // Read the read disabled capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_DISABLED_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the read disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_READ_DISABLED_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_READ_DISABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_READ_DISABLED_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the read enabled capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_ENABLED_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the read disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_READ_ENABLED_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_READ_ENABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_READ_ENABLED_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the read status attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_READ_STATUS_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the read disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_READ_STATUS; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_READ_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_READ_STATUS_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the write disabled capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_DISABLED_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the write disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_WRITE_DISABLED_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_DISABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_DISABLED_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the write enabled capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_ENABLED_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the write disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_WRITE_ENABLED_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_ENABLED_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_ENABLED_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the write status attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_WRITE_STATUS_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the write disabled flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_WRITE_STATUS; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_WRITE_STATUS_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the lock capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_LOCK_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the attribute flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_LOCK_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_LOCK_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_LOCK_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the lock status attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_LOCK_STATUS_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the attribute flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_LOCK_STATUS; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_LOCK_STATUS_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_LOCK_STATUS_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the sticky write attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_STICKY_WRITE_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the attribute flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_STICKY_WRITE; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_STICKY_WRITE_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_STICKY_WRITE_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the memory mapped attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_MEMORY_MAPPED_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the attribute flag | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_MEMORY_MAPPED; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_MEMORY_MAPPED_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_MEMORY_MAPPED_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the erase polarity attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ERASE_POLARITY_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the attribute flag | |
| // | |
| if (strcmp (Value, ONE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ERASE_POLARITY; | |
| } else if (strcmp (Value, ZERO_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ERASE_POLARITY_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ERASE_POLARITY_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the alignment capabilities attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_CAP_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_CAP; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_CAP_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_CAP_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the word alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_2_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_2; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the dword alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_4_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_4; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the word alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_8_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_8; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the qword alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_16_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_16; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 32 byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_32_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_32; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 64 byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_64_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_64; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 128 byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_128_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_128; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_128_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_128_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 256 byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_256_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_256; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_256_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_256_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 512 byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_512_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_512; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_512_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_512_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 1K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_1K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_1K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_1K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_1K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 2K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_2K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_2K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_2K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 4K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_4K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_4K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_4K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 8K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_8K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_8K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_8K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 16K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_16K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_16K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_16K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 32K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_32K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_32K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_32K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| // | |
| // Read the 64K byte alignment capability attribute | |
| // | |
| Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FVB_ALIGNMENT_64K_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update attribute | |
| // | |
| if (strcmp (Value, TRUE_STRING) == 0) { | |
| FvInfo->FvAttributes |= EFI_FVB_ALIGNMENT_64K; | |
| } else if (strcmp (Value, FALSE_STRING) != 0) { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64K_STRING, "expected %s | %s", TRUE_STRING, FALSE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } else { | |
| Error (NULL, 0, 0, EFI_FVB_ALIGNMENT_64K_STRING, "value not specified"); | |
| return Status; | |
| } | |
| if (!(FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_CAP) && | |
| ( | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_2) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_4) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_8) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_16) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_32) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_64) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_128) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_256) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_512) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_1K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_2K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_4K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_8K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_16K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_32K) || | |
| (FvInfo->FvAttributes & EFI_FVB_ALIGNMENT_64K) | |
| ) | |
| ) { | |
| Error ( | |
| NULL, | |
| 0, | |
| 0, | |
| "illegal combination of alignment attributes", | |
| "if %s is not %s, no individual alignments can be %s", | |
| EFI_FVB_ALIGNMENT_CAP_STRING, | |
| TRUE_STRING, | |
| TRUE_STRING | |
| ); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Read block maps | |
| // | |
| for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) { | |
| // | |
| // Read the number of blocks | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the number of blocks | |
| // | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, Value, "invalid value for %s", EFI_NUM_BLOCKS_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64; | |
| } else { | |
| // | |
| // If there is no number of blocks, but there is a size, then we have a mismatched pair | |
| // and should return an error. | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value); | |
| if (!EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING); | |
| return EFI_ABORTED; | |
| } else { | |
| // | |
| // We are done | |
| // | |
| break; | |
| } | |
| } | |
| // | |
| // Read the size of blocks | |
| // | |
| Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Update the number of blocks | |
| // | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, Value, "invalid value specified for %s", EFI_BLOCK_SIZE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvBlocks[Index].BlockLength = (UINT32) Value64; | |
| } else { | |
| // | |
| // There is a number of blocks, but there is no size, so we have a mismatched pair | |
| // and should return an error. | |
| // | |
| Error (NULL, 0, 0, "must specify both", "%s and %s", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| } | |
| // | |
| // Read files | |
| // | |
| for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) { | |
| // | |
| // Read the number of blocks | |
| // | |
| Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Add the file | |
| // | |
| strcpy (FvInfo->FvFiles[Index], Value); | |
| } else { | |
| break; | |
| } | |
| } | |
| if (FindSection (InfFile, COMPONENT_SECTION_STRING)) { | |
| Index = 0; | |
| // | |
| // Read component FV_VARIABLE | |
| // | |
| Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_VARIABLE_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Add the component | |
| // | |
| strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_VARIABLE_STRING); | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: %s is not a valid integer.\n", EFI_NV_VARIABLE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvComponents[Index].Size = (UINTN) Value64; | |
| } else { | |
| printf ("WARNING: Could not read %s.\n", EFI_NV_VARIABLE_STRING); | |
| } | |
| Index++; | |
| // | |
| // Read component FV_EVENT_LOG | |
| // | |
| Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_EVENT_LOG_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Add the component | |
| // | |
| strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_EVENT_LOG_STRING); | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: %s is not a valid integer.\n", EFI_NV_EVENT_LOG_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvComponents[Index].Size = (UINTN) Value64; | |
| } else { | |
| printf ("WARNING: Could not read %s.\n", EFI_NV_EVENT_LOG_STRING); | |
| } | |
| Index++; | |
| // | |
| // Read component FV_FTW_WORKING | |
| // | |
| Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_FTW_WORKING_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Add the component | |
| // | |
| strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_WORKING_STRING); | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: %s is not a valid integer.\n", EFI_NV_FTW_WORKING_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvComponents[Index].Size = (UINTN) Value64; | |
| } else { | |
| printf ("WARNING: Could not read %s.\n", EFI_NV_FTW_WORKING_STRING); | |
| } | |
| Index++; | |
| // | |
| // Read component FV_FTW_SPARE | |
| // | |
| Status = FindToken (InfFile, COMPONENT_SECTION_STRING, EFI_NV_FTW_SPARE_STRING, 0, Value); | |
| if (Status == EFI_SUCCESS) { | |
| // | |
| // Add the component | |
| // | |
| strcpy (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_SPARE_STRING); | |
| Status = AsciiStringToUint64 (Value, FALSE, &Value64); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: %s is not a valid integer.\n", EFI_NV_FTW_SPARE_STRING); | |
| return EFI_ABORTED; | |
| } | |
| FvInfo->FvComponents[Index].Size = (UINTN) Value64; | |
| } else { | |
| printf ("WARNING: Could not read %s.\n", EFI_NV_FTW_SPARE_STRING); | |
| } | |
| } | |
| // | |
| // Compute size for easy access later | |
| // | |
| FvInfo->Size = 0; | |
| for (Index = 0; FvInfo->FvBlocks[Index].NumBlocks; Index++) { | |
| FvInfo->Size += FvInfo->FvBlocks[Index].NumBlocks * FvInfo->FvBlocks[Index].BlockLength; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| UpdateFfsFileState ( | |
| IN EFI_FFS_FILE_HEADER *FfsFile, | |
| IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function changes the FFS file attributes based on the erase polarity | |
| of the FV. | |
| Arguments: | |
| FfsFile File header. | |
| FvHeader FV header. | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| if (FvHeader->Attributes & EFI_FVB_ERASE_POLARITY) { | |
| FfsFile->State = (UINT8)~(FfsFile->State); | |
| } | |
| } | |
| EFI_STATUS | |
| ReadFfsAlignment ( | |
| IN EFI_FFS_FILE_HEADER *FfsFile, | |
| IN OUT UINT32 *Alignment | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function determines the alignment of the FFS input file from the file | |
| attributes. | |
| Arguments: | |
| FfsFile FFS file to parse | |
| Alignment The minimum required alignment of the FFS file, in bytes | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was invalid. | |
| EFI_ABORTED An error occurred. | |
| --*/ | |
| { | |
| // | |
| // Verify input parameters. | |
| // | |
| if (FfsFile == NULL || Alignment == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| switch ((FfsFile->Attributes >> 3) & 0x07) { | |
| case 0: | |
| // | |
| // 8 byte alignment, mini alignment requirement for FFS file. | |
| // | |
| *Alignment = (1 << 3); | |
| break; | |
| case 1: | |
| // | |
| // 16 byte alignment | |
| // | |
| *Alignment = (1 << 4); | |
| break; | |
| case 2: | |
| // | |
| // 128 byte alignment | |
| // | |
| *Alignment = (1 << 7); | |
| break; | |
| case 3: | |
| // | |
| // 512 byte alignment | |
| // | |
| *Alignment = (1 << 9); | |
| break; | |
| case 4: | |
| // | |
| // 1K byte alignment | |
| // | |
| *Alignment = (1 << 10); | |
| break; | |
| case 5: | |
| // | |
| // 4K byte alignment | |
| // | |
| *Alignment = (1 << 12); | |
| break; | |
| case 6: | |
| // | |
| // 32K byte alignment | |
| // | |
| *Alignment = (1 << 15); | |
| break; | |
| case 7: | |
| // | |
| // 64K byte alignment | |
| // | |
| *Alignment = (1 << 16); | |
| break; | |
| default: | |
| Error (NULL, 0, 0, "nvalid file attribute calculated, this is most likely a utility error", NULL); | |
| return EFI_ABORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddPadFile ( | |
| IN OUT MEMORY_FILE *FvImage, | |
| IN UINT32 DataAlignment | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function adds a pad file to the FV image if it required to align the | |
| data of the next file. | |
| Arguments: | |
| FvImage The memory image of the FV to add it to. The current offset | |
| must be valid. | |
| DataAlignment The data alignment of the next FFS file. | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was invalid. | |
| EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete | |
| the pad file add. | |
| --*/ | |
| { | |
| EFI_FFS_FILE_HEADER *PadFile; | |
| EFI_GUID PadFileGuid; | |
| UINTN PadFileSize; | |
| // | |
| // Verify input parameters. | |
| // | |
| if (FvImage == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Basic assumption is we start from an 8 byte aligned address | |
| // and our file header is a multiple of 8 bytes | |
| // | |
| assert ((UINTN) FvImage->CurrentFilePointer % 8 == 0); | |
| assert (sizeof (EFI_FFS_FILE_HEADER) % 8 == 0); | |
| // | |
| // Check if a pad file is necessary | |
| // | |
| if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Write pad file header | |
| // | |
| PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer; | |
| // | |
| // Verify that we have enough space for the file header | |
| // | |
| if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| #ifdef __GNUC__ | |
| { | |
| uuid_t tmp_id; | |
| uuid_generate (tmp_id); | |
| memcpy (&PadFileGuid, tmp_id, sizeof (EFI_GUID)); | |
| } | |
| #else | |
| UuidCreate (&PadFileGuid); | |
| #endif | |
| memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER)); | |
| memcpy (&PadFile->Name, &PadFileGuid, sizeof (EFI_GUID)); | |
| PadFile->Type = EFI_FV_FILETYPE_FFS_PAD; | |
| PadFile->Attributes = 0; | |
| // | |
| // Calculate the pad file size | |
| // | |
| // | |
| // This is the earliest possible valid offset (current plus pad file header | |
| // plus the next file header) | |
| // | |
| PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2); | |
| // | |
| // Add whatever it takes to get to the next aligned address | |
| // | |
| while ((PadFileSize % DataAlignment) != 0) { | |
| PadFileSize++; | |
| } | |
| // | |
| // Subtract the next file header size | |
| // | |
| PadFileSize -= sizeof (EFI_FFS_FILE_HEADER); | |
| // | |
| // Subtract the starting offset to get size | |
| // | |
| PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage; | |
| // | |
| // Write pad file size (calculated size minus next file header size) | |
| // | |
| PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF); | |
| PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF); | |
| PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF); | |
| // | |
| // Fill in checksums and state, they must be 0 for checksumming. | |
| // | |
| PadFile->IntegrityCheck.Checksum.Header = 0; | |
| PadFile->IntegrityCheck.Checksum.File = 0; | |
| PadFile->State = 0; | |
| PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER)); | |
| if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) { | |
| PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, PadFileSize); | |
| } else { | |
| PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; | |
| } | |
| PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; | |
| UpdateFfsFileState ( | |
| (EFI_FFS_FILE_HEADER *) PadFile, | |
| (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage | |
| ); | |
| // | |
| // Verify that we have enough space (including the padding | |
| // | |
| if ((UINTN) (PadFile + sizeof (EFI_FFS_FILE_HEADER)) >= (UINTN) FvImage->Eof) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Update the current FV pointer | |
| // | |
| FvImage->CurrentFilePointer += PadFileSize; | |
| return EFI_SUCCESS; | |
| } | |
| BOOLEAN | |
| IsVtfFile ( | |
| IN EFI_FFS_FILE_HEADER *FileBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function checks the header to validate if it is a VTF file | |
| Arguments: | |
| FileBuffer Buffer in which content of a file has been read. | |
| Returns: | |
| TRUE If this is a VTF file | |
| FALSE If this is not a VTF file | |
| --*/ | |
| { | |
| EFI_GUID VtfGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; | |
| if (!memcmp (&FileBuffer->Name, &VtfGuid, sizeof (EFI_GUID))) { | |
| return TRUE; | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| EFI_STATUS | |
| FfsRebaseImageRead ( | |
| IN VOID *FileHandle, | |
| IN UINTN FileOffset, | |
| IN OUT UINT32 *ReadSize, | |
| OUT VOID *Buffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file | |
| Arguments: | |
| FileHandle - The handle to the PE/COFF file | |
| FileOffset - The offset, in bytes, into the file to read | |
| ReadSize - The number of bytes to read from the file starting at FileOffset | |
| Buffer - A pointer to the buffer to read the data into. | |
| Returns: | |
| EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset | |
| --*/ | |
| { | |
| CHAR8 *Destination8; | |
| CHAR8 *Source8; | |
| UINT32 Length; | |
| Destination8 = Buffer; | |
| Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); | |
| Length = *ReadSize; | |
| while (Length--) { | |
| *(Destination8++) = *(Source8++); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddSymFile ( | |
| IN UINT64 BaseAddress, | |
| IN EFI_FFS_FILE_HEADER *FfsFile, | |
| IN OUT MEMORY_FILE *SymImage, | |
| IN CHAR8 *SourceFileName | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function adds the SYM tokens in the source file to the destination file. | |
| The SYM tokens are updated to reflect the base address. | |
| Arguments: | |
| BaseAddress The base address for the new SYM tokens. | |
| FfsFile Pointer to the beginning of the FFS file in question. | |
| SymImage The memory file to update with symbol information. | |
| SourceFileName The source file. | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was invalid. | |
| EFI_ABORTED An error occurred. | |
| --*/ | |
| { | |
| FILE *SourceFile; | |
| CHAR8 Buffer[_MAX_PATH]; | |
| CHAR8 Type[_MAX_PATH]; | |
| CHAR8 Address[_MAX_PATH]; | |
| CHAR8 Section[_MAX_PATH]; | |
| CHAR8 Token[_MAX_PATH]; | |
| CHAR8 SymFileName[_MAX_PATH]; | |
| CHAR8 CodeModuleName[_MAX_PATH]; | |
| CHAR8 *Ptr; | |
| UINT64 TokenAddress; | |
| EFI_STATUS Status; | |
| EFI_FILE_SECTION_POINTER Pe32Section; | |
| UINT32 EntryPoint; | |
| UINT32 BaseOfCode; | |
| UINT16 MachineType; | |
| // | |
| // Verify input parameters. | |
| // | |
| if (BaseAddress == 0 || FfsFile == NULL || SymImage == NULL || SourceFileName == NULL) { | |
| Error (NULL, 0, 0, "invalid parameter passed to AddSymFile()", NULL); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Check if we want to add this file | |
| // | |
| // | |
| // Get the file name | |
| // | |
| strcpy (Buffer, SourceFileName); | |
| // | |
| // Copy the file name for the path of the sym file and truncate the name portion. | |
| // | |
| strcpy (SymFileName, Buffer); | |
| Ptr = strrchr (SymFileName, FILE_SEP_CHAR); | |
| assert (Ptr); | |
| Ptr[0] = 0; | |
| // | |
| // Find the file extension and make it lower case | |
| // | |
| Ptr = strrchr (SymFileName, '.'); | |
| if (Ptr != NULL) { | |
| strlwr (Ptr); | |
| } | |
| // | |
| // Check if it is PEI file | |
| // | |
| if (strstr (Buffer, ".pei") != NULL) { | |
| // | |
| // Find the human readable portion | |
| // | |
| if (!strtok (Buffer, "-") || | |
| !strtok (NULL, "-") || | |
| !strtok (NULL, "-") || | |
| !strtok (NULL, "-") || | |
| !strtok (NULL, "-") || | |
| !strcpy (Buffer, strtok (NULL, ".")) | |
| ) { | |
| Error (NULL, 0, 0, "failed to find human readable portion of the file name in AddSymFile()", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Save code module name | |
| // | |
| strcpy (CodeModuleName, Buffer); | |
| // | |
| // Add the symbol file name and extension to the file path. | |
| // | |
| strcat (Buffer, ".sym"); | |
| strcat (SymFileName, FILE_SEP_CHAR); | |
| strcat (SymFileName, Buffer); | |
| } else { | |
| // | |
| // Only handle PEIM files. | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Find PE32 section | |
| // | |
| Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, 1, &Pe32Section); | |
| // | |
| // BUGBUG: Assume if no PE32 section it is PIC and hardcode base address | |
| // | |
| if (Status == EFI_NOT_FOUND) { | |
| Status = GetSectionByType (FfsFile, EFI_SECTION_TE, 1, &Pe32Section); | |
| } | |
| if (Status == EFI_SUCCESS) { | |
| Status = GetPe32Info ( | |
| (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), | |
| &EntryPoint, | |
| &BaseOfCode, | |
| &MachineType | |
| ); | |
| } else if (Status == EFI_NOT_FOUND) { | |
| // | |
| // For PIC, hardcode. | |
| // | |
| BaseOfCode = 0x60; | |
| Status = EFI_SUCCESS; | |
| } else { | |
| Error (NULL, 0, 0, "could not parse a PE32 section from the PEI file", NULL); | |
| return Status; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "GetPe32Info() could not get PE32 entry point for PEI file", NULL); | |
| return Status; | |
| } | |
| // | |
| // Open the source file | |
| // | |
| SourceFile = fopen (SymFileName, "r"); | |
| if (SourceFile == NULL) { | |
| // | |
| // SYM files are not required. | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Read the first line | |
| // | |
| if (fgets (Buffer, _MAX_PATH, SourceFile) == NULL) { | |
| Buffer[0] = 0; | |
| } | |
| // | |
| // Make sure it matches the expected sym format | |
| // | |
| if (strcmp (Buffer, "TEXTSYM format | V1.0\n")) { | |
| fclose (SourceFile); | |
| Error (NULL, 0, 0, "AddSymFile() found unexpected sym format in input file", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Read in the file | |
| // | |
| while (feof (SourceFile) == 0) { | |
| // | |
| // Read a line | |
| // | |
| if (fscanf ( | |
| SourceFile, | |
| "%s | %s | %s | %s\n", | |
| Type, | |
| Address, | |
| Section, | |
| Token | |
| ) == 4) { | |
| // | |
| // If the token starts with "??" ignore it | |
| // | |
| if (Token[0] == '?' && Token[1] == '?') { | |
| continue; | |
| } | |
| // | |
| // Get the token address | |
| // | |
| AsciiStringToUint64 (Address, TRUE, &TokenAddress); | |
| // | |
| // Add the base address | |
| // | |
| TokenAddress += BaseAddress; | |
| // | |
| // If PE32 or TE section then find the start of code. For PIC it is hardcoded. | |
| // | |
| if (Pe32Section.Pe32Section) { | |
| // | |
| // Add the offset of the PE32 section | |
| // | |
| TokenAddress += (UINTN) Pe32Section.Pe32Section - (UINTN) FfsFile; | |
| // | |
| // Add the size of the PE32 section header | |
| // | |
| TokenAddress += sizeof (EFI_PE32_SECTION); | |
| } else { | |
| // | |
| // For PIC hardcoded. | |
| // | |
| TokenAddress += 0x28; | |
| } | |
| // | |
| // Add the beginning of the code | |
| // | |
| TokenAddress += BaseOfCode; | |
| sprintf ( | |
| Buffer, | |
| "%s | %016I64X | %s | _%s%s\n", | |
| Type, | |
| TokenAddress, | |
| Section, | |
| CodeModuleName, | |
| Token | |
| ); | |
| memcpy (SymImage->CurrentFilePointer, Buffer, strlen (Buffer) + 1); | |
| SymImage->CurrentFilePointer = (UINT8 *) (((UINTN) SymImage->CurrentFilePointer) + strlen (Buffer) + 1); | |
| } | |
| } | |
| fclose (SourceFile); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddFile ( | |
| IN OUT MEMORY_FILE *FvImage, | |
| IN FV_INFO *FvInfo, | |
| IN UINTN Index, | |
| IN OUT EFI_FFS_FILE_HEADER **VtfFileImage, | |
| IN OUT MEMORY_FILE *SymImage | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function adds a file to the FV image. The file will pad to the | |
| appropriate alignment if required. | |
| Arguments: | |
| FvImage The memory image of the FV to add it to. The current offset | |
| must be valid. | |
| FvInfo Pointer to information about the FV. | |
| Index The file in the FvInfo file list to add. | |
| VtfFileImage A pointer to the VTF file within the FvImage. If this is equal | |
| to the end of the FvImage then no VTF previously found. | |
| SymImage The memory image of the Sym file to update if symbols are present. | |
| The current offset must be valid. | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was invalid. | |
| EFI_ABORTED An error occurred. | |
| EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add. | |
| --*/ | |
| { | |
| FILE *NewFile; | |
| UINTN FileSize; | |
| UINT8 *FileBuffer; | |
| UINTN NumBytesRead; | |
| UINT32 CurrentFileAlignment; | |
| EFI_STATUS Status; | |
| EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress; | |
| UINT8 VtfHeaderChecksum; | |
| UINT8 VtfFileChecksum; | |
| UINT8 FileState; | |
| EFI_FFS_FILE_TAIL TailValue; | |
| UINT32 TailSize; | |
| // | |
| // Verify input parameters. | |
| // | |
| if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL || SymImage == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Read the file to add | |
| // | |
| NewFile = fopen (FvInfo->FvFiles[Index], "rb"); | |
| if (NewFile == NULL) { | |
| Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to open file for reading"); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Get the file size | |
| // | |
| FileSize = _filelength (fileno (NewFile)); | |
| // | |
| // Read the file into a buffer | |
| // | |
| FileBuffer = malloc (FileSize); | |
| if (FileBuffer == NULL) { | |
| Error (NULL, 0, 0, "memory allocation failure", NULL); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile); | |
| // | |
| // Done with the file, from this point on we will just use the buffer read. | |
| // | |
| fclose (NewFile); | |
| // | |
| // Verify read successful | |
| // | |
| if (NumBytesRead != sizeof (UINT8) * FileSize) { | |
| free (FileBuffer); | |
| Error (NULL, 0, 0, FvInfo->FvFiles[Index], "failed to read input file contents"); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Verify space exists to add the file | |
| // | |
| if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) { | |
| Error (NULL, 0, 0, FvInfo->FvFiles[Index], "insufficient space remains to add the file"); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Update the file state based on polarity of the FV. | |
| // | |
| UpdateFfsFileState ( | |
| (EFI_FFS_FILE_HEADER *) FileBuffer, | |
| (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage | |
| ); | |
| // | |
| // If we have a VTF file, add it at the top. | |
| // | |
| if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) { | |
| if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) { | |
| // | |
| // No previous VTF, add this one. | |
| // | |
| *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize); | |
| // | |
| // Sanity check. The file MUST align appropriately | |
| // | |
| if ((((UINTN) *VtfFileImage) & 0x07) != 0) { | |
| Error (NULL, 0, 0, "VTF file does not align on 8-byte boundary", NULL); | |
| } | |
| // | |
| // copy VTF File Header | |
| // | |
| memcpy (*VtfFileImage, FileBuffer, sizeof (EFI_FFS_FILE_HEADER)); | |
| // | |
| // Copy VTF body | |
| // | |
| memcpy ( | |
| (UINT8 *) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER), | |
| FileBuffer + sizeof (EFI_FFS_FILE_HEADER), | |
| FileSize - sizeof (EFI_FFS_FILE_HEADER) | |
| ); | |
| // | |
| // re-calculate the VTF File Header | |
| // | |
| FileState = (*VtfFileImage)->State; | |
| (*VtfFileImage)->State = 0; | |
| *(UINT32 *) ((*VtfFileImage)->Size) = FileSize; | |
| (*VtfFileImage)->IntegrityCheck.Checksum.Header = 0; | |
| (*VtfFileImage)->IntegrityCheck.Checksum.File = 0; | |
| VtfHeaderChecksum = CalculateChecksum8 ((UINT8 *) *VtfFileImage, sizeof (EFI_FFS_FILE_HEADER)); | |
| (*VtfFileImage)->IntegrityCheck.Checksum.Header = VtfHeaderChecksum; | |
| // | |
| // Determine if it has a tail | |
| // | |
| if ((*VtfFileImage)->Attributes & FFS_ATTRIB_TAIL_PRESENT) { | |
| TailSize = sizeof (EFI_FFS_FILE_TAIL); | |
| } else { | |
| TailSize = 0; | |
| } | |
| if ((*VtfFileImage)->Attributes & FFS_ATTRIB_CHECKSUM) { | |
| VtfFileChecksum = CalculateChecksum8 ((UINT8 *) *VtfFileImage, FileSize - TailSize); | |
| (*VtfFileImage)->IntegrityCheck.Checksum.File = VtfFileChecksum; | |
| } else { | |
| (*VtfFileImage)->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; | |
| } | |
| // | |
| // If it has a file tail, update it | |
| // | |
| if ((*VtfFileImage)->Attributes & FFS_ATTRIB_TAIL_PRESENT) { | |
| TailValue = (EFI_FFS_FILE_TAIL) (~((*VtfFileImage)->IntegrityCheck.TailReference)); | |
| *(EFI_FFS_FILE_TAIL *) (((UINTN) (*VtfFileImage) + GetLength ((*VtfFileImage)->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue; | |
| } | |
| (*VtfFileImage)->State = FileState; | |
| free (FileBuffer); | |
| return EFI_SUCCESS; | |
| } else { | |
| // | |
| // Already found a VTF file. | |
| // | |
| Error (NULL, 0, 0, "multiple VTF files are illegal in a single FV", NULL); | |
| free (FileBuffer); | |
| return EFI_ABORTED; | |
| } | |
| } | |
| // | |
| // Check if alignment is required | |
| // | |
| Status = ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not determine alignment of file %s.\n", FvInfo->FvFiles[Index]); | |
| free (FileBuffer); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Find the largest alignment of all the FFS files in the FV | |
| // | |
| if (CurrentFileAlignment > MaxFfsAlignment) { | |
| MaxFfsAlignment = CurrentFileAlignment; | |
| } | |
| // | |
| // Add pad file if necessary | |
| // | |
| Status = AddPadFile (FvImage, CurrentFileAlignment); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not align the file data properly.\n"); | |
| free (FileBuffer); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Add file | |
| // | |
| if ((FvImage->CurrentFilePointer + FileSize) < FvImage->Eof) { | |
| // | |
| // Copy the file | |
| // | |
| memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize); | |
| // | |
| // If the file is XIP, rebase | |
| // | |
| CurrentFileBaseAddress = FvInfo->BaseAddress + ((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage); | |
| // | |
| // Status = RebaseFfsFile ((EFI_FFS_FILE_HEADER*) FvImage->CurrentFilePointer, CurrentFileBaseAddress); | |
| // if (EFI_ERROR(Status)) { | |
| // printf ("ERROR: Could not rebase the file %s.\n", FvInfo->FvFiles[Index]); | |
| // return EFI_ABORTED; | |
| // } | |
| // | |
| // Update Symbol file | |
| // | |
| Status = AddSymFile ( | |
| CurrentFileBaseAddress, | |
| (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer, | |
| SymImage, | |
| FvInfo->FvFiles[Index] | |
| ); | |
| assert (!EFI_ERROR (Status)); | |
| // | |
| // Update the current pointer in the FV image | |
| // | |
| FvImage->CurrentFilePointer += FileSize; | |
| } else { | |
| printf ("ERROR: The firmware volume is out of space, could not add file %s.\n", FvInfo->FvFiles[Index]); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Make next file start at QWord Boundry | |
| // | |
| while (((UINTN) FvImage->CurrentFilePointer & 0x07) != 0) { | |
| FvImage->CurrentFilePointer++; | |
| } | |
| // | |
| // Free allocated memory. | |
| // | |
| free (FileBuffer); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddVariableBlock ( | |
| IN UINT8 *FvImage, | |
| IN UINTN Size, | |
| IN FV_INFO *FvInfo | |
| ) | |
| { | |
| EFI_FIRMWARE_VOLUME_HEADER *FvHeader; | |
| VARIABLE_STORE_HEADER *VarStoreHeader; | |
| // | |
| // Variable block should exclude FvHeader. Since the length of | |
| // FvHeader depends on the block map, which is variable length, | |
| // we could only decide the actual variable block length here. | |
| // | |
| FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage; | |
| FvImage = FvImage + FvHeader->HeaderLength; | |
| VarStoreHeader = (VARIABLE_STORE_HEADER *) FvImage; | |
| VarStoreHeader->Signature = VARIABLE_STORE_SIGNATURE; | |
| VarStoreHeader->Size = Size - FvHeader->HeaderLength; | |
| VarStoreHeader->Format = VARIABLE_STORE_FORMATTED; | |
| VarStoreHeader->State = VARIABLE_STORE_HEALTHY; | |
| VarStoreHeader->Reserved = 0; | |
| VarStoreHeader->Reserved1 = 0; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddEventLogBlock ( | |
| IN UINT8 *FvImage, | |
| IN UINTN Size, | |
| IN FV_INFO *FvInfo | |
| ) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddFTWWorkingBlock ( | |
| IN UINT8 *FvImage, | |
| IN UINTN Size, | |
| IN FV_INFO *FvInfo | |
| ) | |
| { | |
| EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FTWHeader; | |
| UINT32 Crc32; | |
| Crc32 = 0; | |
| FTWHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FvImage; | |
| memcpy (&FTWHeader->Signature, &(FvInfo->FvGuid), sizeof (EFI_GUID)); | |
| FTWHeader->WriteQueueSize = Size - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER); | |
| CalculateCrc32 (FvImage, sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), &Crc32); | |
| FTWHeader->Crc = Crc32; | |
| if (FvInfo->FvAttributes & EFI_FVB_ERASE_POLARITY) { | |
| FTWHeader->WorkingBlockValid = 0; | |
| FTWHeader->WorkingBlockInvalid = 1; | |
| } else { | |
| FTWHeader->WorkingBlockValid = 1; | |
| FTWHeader->WorkingBlockInvalid = 0; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AddFTWSpareBlock ( | |
| IN UINT8 *FvImage, | |
| IN UINTN Size, | |
| IN FV_INFO *FvInfo | |
| ) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GenNonFFSFv ( | |
| IN UINT8 *FvImage, | |
| IN FV_INFO *FvInfo | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function generate the non FFS FV image, such as the working block | |
| and spare block. How each component of the FV is built is component | |
| specific. | |
| Arguments: | |
| FvImage The memory image of the FV to add it to. The current offset | |
| must be valid. | |
| FvInfo Pointer to information about the FV. | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was invalid. | |
| EFI_ABORTED An error occurred. | |
| EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add. | |
| --*/ | |
| { | |
| UINTN Index; | |
| EFI_FIRMWARE_VOLUME_HEADER *FvHeader; | |
| UINT64 TotalSize; | |
| FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage; | |
| TotalSize = 0; | |
| for (Index = 0; FvInfo->FvComponents[Index].Size != 0; Index++) { | |
| if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_VARIABLE_STRING) == 0) { | |
| AddVariableBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo); | |
| } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_EVENT_LOG_STRING) == 0) { | |
| AddEventLogBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo); | |
| } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_WORKING_STRING) == 0) { | |
| AddFTWWorkingBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo); | |
| } else if (stricmp (FvInfo->FvComponents[Index].ComponentName, EFI_NV_FTW_SPARE_STRING) == 0) { | |
| AddFTWSpareBlock (FvImage, FvInfo->FvComponents[Index].Size, FvInfo); | |
| } else { | |
| printf ("Error. Unknown Non-FFS block %s \n", FvInfo->FvComponents[Index].ComponentName); | |
| return EFI_ABORTED; | |
| } | |
| FvImage = FvImage + FvInfo->FvComponents[Index].Size; | |
| TotalSize = TotalSize + FvInfo->FvComponents[Index].Size; | |
| } | |
| // | |
| // Index and TotalSize is zero mean there's no component, so this is an empty fv | |
| // | |
| if ((Index != 0 || TotalSize != 0) && TotalSize != FvInfo->Size) { | |
| printf ("Error. Component size does not sum up to FV size.\n"); | |
| return EFI_ABORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PadFvImage ( | |
| IN MEMORY_FILE *FvImage, | |
| IN EFI_FFS_FILE_HEADER *VtfFileImage | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function places a pad file between the last file in the FV and the VTF | |
| file if the VTF file exists. | |
| Arguments: | |
| FvImage Memory file for the FV memory image | |
| VtfFileImage The address of the VTF file. If this is the end of the FV | |
| image, no VTF exists and no pad file is needed. | |
| Returns: | |
| EFI_SUCCESS Completed successfully. | |
| EFI_INVALID_PARAMETER One of the input parameters was NULL. | |
| --*/ | |
| { | |
| EFI_FFS_FILE_HEADER *PadFile; | |
| UINTN FileSize; | |
| // | |
| // If there is no VTF or the VTF naturally follows the previous file without a | |
| // pad file, then there's nothing to do | |
| // | |
| if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || (void *) FvImage->CurrentFilePointer == (void *) VtfFileImage) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Pad file starts at beginning of free space | |
| // | |
| PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer; | |
| // | |
| // write header | |
| // | |
| memset (PadFile, 0, sizeof (EFI_FFS_FILE_HEADER)); | |
| memcpy (&PadFile->Name, &DefaultFvPadFileNameGuid, sizeof (EFI_GUID)); | |
| PadFile->Type = EFI_FV_FILETYPE_FFS_PAD; | |
| PadFile->Attributes = 0; | |
| // | |
| // FileSize includes the EFI_FFS_FILE_HEADER | |
| // | |
| FileSize = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer; | |
| PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF); | |
| PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8); | |
| PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16); | |
| // | |
| // Fill in checksums and state, must be zero during checksum calculation. | |
| // | |
| PadFile->IntegrityCheck.Checksum.Header = 0; | |
| PadFile->IntegrityCheck.Checksum.File = 0; | |
| PadFile->State = 0; | |
| PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER)); | |
| if (PadFile->Attributes & FFS_ATTRIB_CHECKSUM) { | |
| PadFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) PadFile, FileSize); | |
| } else { | |
| PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; | |
| } | |
| PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; | |
| UpdateFfsFileState ( | |
| (EFI_FFS_FILE_HEADER *) PadFile, | |
| (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage | |
| ); | |
| // | |
| // Update the current FV pointer | |
| // | |
| FvImage->CurrentFilePointer = FvImage->Eof; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| UpdateResetVector ( | |
| IN MEMORY_FILE *FvImage, | |
| IN FV_INFO *FvInfo, | |
| IN EFI_FFS_FILE_HEADER *VtfFile | |
| ) | |
| /*++ | |
| Routine Description: | |
| This parses the FV looking for the PEI core and then plugs the address into | |
| the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to | |
| complete an IA32 Bootstrap FV. | |
| Arguments: | |
| FvImage Memory file for the FV memory image | |
| FvInfo Information read from INF file. | |
| VtfFile Pointer to the VTF file in the FV image. | |
| Returns: | |
| EFI_SUCCESS Function Completed successfully. | |
| EFI_ABORTED Error encountered. | |
| EFI_INVALID_PARAMETER A required parameter was NULL. | |
| EFI_NOT_FOUND PEI Core file not found. | |
| --*/ | |
| { | |
| EFI_FFS_FILE_HEADER *PeiCoreFile; | |
| EFI_FFS_FILE_HEADER *SecCoreFile; | |
| EFI_STATUS Status; | |
| EFI_FILE_SECTION_POINTER Pe32Section; | |
| UINT32 EntryPoint; | |
| UINT32 BaseOfCode; | |
| UINT16 MachineType; | |
| EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress; | |
| EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress; | |
| EFI_PHYSICAL_ADDRESS *SecCoreEntryAddressPtr; | |
| UINT32 *Ia32ResetAddressPtr; | |
| UINT8 *BytePointer; | |
| UINT8 *BytePointer2; | |
| UINT16 *WordPointer; | |
| UINT16 CheckSum; | |
| UINTN Index; | |
| EFI_FFS_FILE_STATE SavedState; | |
| EFI_FFS_FILE_TAIL TailValue; | |
| UINT32 TailSize; | |
| UINT64 FitAddress; | |
| FIT_TABLE *FitTablePtr; | |
| // | |
| // Verify input parameters | |
| // | |
| if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Initialize FV library | |
| // | |
| InitializeFvLib (FvImage->FileImage, (UINTN) FvImage->Eof - (UINTN) FvImage->FileImage); | |
| // | |
| // Verify VTF file | |
| // | |
| Status = VerifyFfsFile (VtfFile); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Find the PEI Core | |
| // | |
| Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile); | |
| if (EFI_ERROR (Status) || PeiCoreFile == NULL) { | |
| Error (NULL, 0, 0, "could not find the PEI core in the FV", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // PEI Core found, now find PE32 or TE section | |
| // | |
| Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section); | |
| if (Status == EFI_NOT_FOUND) { | |
| Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "could not find PE32 or TE section in PEI core file", NULL); | |
| return EFI_ABORTED; | |
| } | |
| Status = GetPe32Info ( | |
| (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), | |
| &EntryPoint, | |
| &BaseOfCode, | |
| &MachineType | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "could not get PE32 entry point for PEI core", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Physical address is FV base + offset of PE32 + offset of the entry point | |
| // | |
| PeiCorePhysicalAddress = FvInfo->BaseAddress; | |
| PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; | |
| PeiCorePhysicalAddress += EntryPoint; | |
| if (MachineType == EFI_IMAGE_MACHINE_IA64) { | |
| // | |
| // Update PEI_CORE address | |
| // | |
| // | |
| // Set the uncached attribute bit in the physical address | |
| // | |
| PeiCorePhysicalAddress |= 0x8000000000000000ULL; | |
| // | |
| // Check if address is aligned on a 16 byte boundary | |
| // | |
| if (PeiCorePhysicalAddress & 0xF) { | |
| printf ( | |
| "ERROR: PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %Xh.\n", | |
| PeiCorePhysicalAddress | |
| ); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // First Get the FIT table address | |
| // | |
| FitAddress = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF; | |
| FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress)); | |
| Status = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress); | |
| if (!EFI_ERROR (Status)) { | |
| UpdateFitCheckSum (FitTablePtr); | |
| } | |
| // | |
| // Find the Sec Core | |
| // | |
| Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile); | |
| if (EFI_ERROR (Status) || SecCoreFile == NULL) { | |
| Error (NULL, 0, 0, "could not find the Sec core in the FV", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Sec Core found, now find PE32 section | |
| // | |
| Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "could not find PE32 section in SEC core file", NULL); | |
| return EFI_ABORTED; | |
| } | |
| Status = GetPe32Info ( | |
| (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), | |
| &EntryPoint, | |
| &BaseOfCode, | |
| &MachineType | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| Error (NULL, 0, 0, "could not get PE32 entry point for SEC core", NULL); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Physical address is FV base + offset of PE32 + offset of the entry point | |
| // | |
| SecCorePhysicalAddress = FvInfo->BaseAddress; | |
| SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; | |
| SecCorePhysicalAddress += EntryPoint; | |
| // | |
| // Update SEC_CORE address | |
| // | |
| // | |
| // Set the uncached attribute bit in the physical address | |
| // | |
| SecCorePhysicalAddress |= 0x8000000000000000ULL; | |
| // | |
| // Update the address | |
| // | |
| SecCoreEntryAddressPtr = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET); | |
| *SecCoreEntryAddressPtr = SecCorePhysicalAddress; | |
| // | |
| // Check if address is aligned on a 16 byte boundary | |
| // | |
| if (SecCorePhysicalAddress & 0xF) { | |
| printf ( | |
| "ERROR: SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %Xh.\n", | |
| SecCorePhysicalAddress | |
| ); | |
| return EFI_ABORTED; | |
| } | |
| } else if (MachineType == EFI_IMAGE_MACHINE_IA32) { | |
| // | |
| // Get the location to update | |
| // | |
| Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET); | |
| // | |
| // Write lower 32 bits of physical address | |
| // | |
| *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress; | |
| // | |
| // Update the BFV base address | |
| // | |
| Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - 4); | |
| *Ia32ResetAddressPtr = (UINT32) (FvInfo->BaseAddress); | |
| CheckSum = 0x0000; | |
| // | |
| // Update the Startup AP in the FVH header block ZeroVector region. | |
| // | |
| BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage); | |
| BytePointer2 = (FvInfo->Size == 0x10000) ? m64kRecoveryStartupApDataArray : m128kRecoveryStartupApDataArray; | |
| for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) { | |
| *BytePointer++ = *BytePointer2++; | |
| } | |
| // | |
| // Calculate the checksum | |
| // | |
| WordPointer = (UINT16 *) ((UINTN) FvImage->FileImage); | |
| for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) { | |
| CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer)); | |
| WordPointer++; | |
| } | |
| // | |
| // Update the checksum field | |
| // | |
| BytePointer = (UINT8 *) ((UINTN) FvImage->FileImage); | |
| BytePointer += (SIZEOF_STARTUP_DATA_ARRAY - 2); | |
| WordPointer = (UINT16 *) BytePointer; | |
| *WordPointer = (UINT16) (0x10000 - (UINT32) CheckSum); | |
| } else { | |
| Error (NULL, 0, 0, "invalid machine type in PEI core", "machine type=0x%X", (UINT32) MachineType); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Determine if it has an FFS file tail. | |
| // | |
| if (VtfFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { | |
| TailSize = sizeof (EFI_FFS_FILE_TAIL); | |
| } else { | |
| TailSize = 0; | |
| } | |
| // | |
| // Now update file checksum | |
| // | |
| SavedState = VtfFile->State; | |
| VtfFile->IntegrityCheck.Checksum.File = 0; | |
| VtfFile->State = 0; | |
| if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) { | |
| VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( | |
| (UINT8 *) VtfFile, | |
| GetLength (VtfFile->Size) - TailSize | |
| ); | |
| } else { | |
| VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; | |
| } | |
| VtfFile->State = SavedState; | |
| // | |
| // Update tail if present | |
| // | |
| if (VtfFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { | |
| TailValue = (EFI_FFS_FILE_TAIL) (~(VtfFile->IntegrityCheck.TailReference)); | |
| *(EFI_FFS_FILE_TAIL *) (((UINTN) (VtfFile) + GetLength (VtfFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GetPe32Info ( | |
| IN UINT8 *Pe32, | |
| OUT UINT32 *EntryPoint, | |
| OUT UINT32 *BaseOfCode, | |
| OUT UINT16 *MachineType | |
| ) | |
| /*++ | |
| Routine Description: | |
| Retrieves the PE32 entry point offset and machine type from PE image or TeImage. | |
| See EfiImage.h for machine types. The entry point offset is from the beginning | |
| of the PE32 buffer passed in. | |
| Arguments: | |
| Pe32 Beginning of the PE32. | |
| EntryPoint Offset from the beginning of the PE32 to the image entry point. | |
| BaseOfCode Base address of code. | |
| MachineType Magic number for the machine type. | |
| Returns: | |
| EFI_SUCCESS Function completed successfully. | |
| EFI_ABORTED Error encountered. | |
| EFI_INVALID_PARAMETER A required parameter was NULL. | |
| EFI_UNSUPPORTED The operation is unsupported. | |
| --*/ | |
| { | |
| EFI_IMAGE_DOS_HEADER *DosHeader; | |
| EFI_IMAGE_NT_HEADERS *NtHeader; | |
| EFI_TE_IMAGE_HEADER *TeHeader; | |
| // | |
| // Verify input parameters | |
| // | |
| if (Pe32 == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // First check whether it is one TE Image. | |
| // | |
| TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32; | |
| if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { | |
| // | |
| // By TeImage Header to get output | |
| // | |
| *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize; | |
| *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize; | |
| *MachineType = TeHeader->Machine; | |
| } else { | |
| // | |
| // Then check whether | |
| // First is the DOS header | |
| // | |
| DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32; | |
| // | |
| // Verify DOS header is expected | |
| // | |
| if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { | |
| printf ("ERROR: Unknown magic number in the DOS header, 0x%04X.\n", DosHeader->e_magic); | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Immediately following is the NT header. | |
| // | |
| NtHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32 + DosHeader->e_lfanew); | |
| // | |
| // Verify NT header is expected | |
| // | |
| if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) { | |
| printf ("ERROR: Unrecognized image signature 0x%08X.\n", NtHeader->Signature); | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Get output | |
| // | |
| *EntryPoint = NtHeader->OptionalHeader.AddressOfEntryPoint; | |
| *BaseOfCode = NtHeader->OptionalHeader.BaseOfCode; | |
| *MachineType = NtHeader->FileHeader.Machine; | |
| } | |
| // | |
| // Verify machine type is supported | |
| // | |
| if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC) { | |
| printf ("ERROR: Unrecognized machine type in the PE32 file.\n"); | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Exposed function implementations (prototypes are defined in GenFvImageLib.h) | |
| // | |
| EFI_STATUS | |
| GenerateFvImage ( | |
| IN CHAR8 *InfFileImage, | |
| IN UINTN InfFileSize, | |
| OUT UINT8 **FvImage, | |
| OUT UINTN *FvImageSize, | |
| OUT CHAR8 **FvFileName, | |
| OUT UINT8 **SymImage, | |
| OUT UINTN *SymImageSize, | |
| OUT CHAR8 **SymFileName | |
| ) | |
| /*++ | |
| Routine Description: | |
| This is the main function which will be called from application. | |
| Arguments: | |
| InfFileImage Buffer containing the INF file contents. | |
| InfFileSize Size of the contents of the InfFileImage buffer. | |
| FvImage Pointer to the FV image created. | |
| FvImageSize Size of the FV image created and pointed to by FvImage. | |
| FvFileName Requested name for the FV file. | |
| SymImage Pointer to the Sym image created. | |
| SymImageSize Size of the Sym image created and pointed to by SymImage. | |
| SymFileName Requested name for the Sym file. | |
| Returns: | |
| EFI_SUCCESS Function completed successfully. | |
| EFI_OUT_OF_RESOURCES Could not allocate required resources. | |
| EFI_ABORTED Error encountered. | |
| EFI_INVALID_PARAMETER A required parameter was NULL. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| MEMORY_FILE InfMemoryFile; | |
| MEMORY_FILE FvImageMemoryFile; | |
| MEMORY_FILE SymImageMemoryFile; | |
| FV_INFO FvInfo; | |
| UINTN Index; | |
| EFI_FIRMWARE_VOLUME_HEADER *FvHeader; | |
| EFI_FFS_FILE_HEADER *VtfFileImage; | |
| // | |
| // Check for invalid parameter | |
| // | |
| if (InfFileImage == NULL || FvImage == NULL || FvImageSize == NULL || FvFileName == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Initialize file structures | |
| // | |
| InfMemoryFile.FileImage = InfFileImage; | |
| InfMemoryFile.CurrentFilePointer = InfFileImage; | |
| InfMemoryFile.Eof = InfFileImage + InfFileSize; | |
| // | |
| // Parse the FV inf file for header information | |
| // | |
| Status = ParseFvInf (&InfMemoryFile, &FvInfo); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not parse the input INF file.\n"); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Update the file name return values | |
| // | |
| strcpy (*FvFileName, FvInfo.FvName); | |
| strcpy (*SymFileName, FvInfo.SymName); | |
| // | |
| // Calculate the FV size | |
| // | |
| *FvImageSize = FvInfo.Size; | |
| // | |
| // Allocate the FV | |
| // | |
| *FvImage = malloc (*FvImageSize); | |
| if (*FvImage == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Allocate space for symbol file storage | |
| // | |
| *SymImage = malloc (SYMBOL_FILE_SIZE); | |
| if (*SymImage == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Initialize the FV to the erase polarity | |
| // | |
| if (FvInfo.FvAttributes & EFI_FVB_ERASE_POLARITY) { | |
| memset (*FvImage, -1, *FvImageSize); | |
| } else { | |
| memset (*FvImage, 0, *FvImageSize); | |
| } | |
| // | |
| // Initialize FV header | |
| // | |
| FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) *FvImage; | |
| // | |
| // Initialize the zero vector to all zeros. | |
| // | |
| memset (FvHeader->ZeroVector, 0, 16); | |
| // | |
| // Copy the FFS GUID | |
| // | |
| memcpy (&FvHeader->FileSystemGuid, &FvInfo.FvGuid, sizeof (EFI_GUID)); | |
| FvHeader->FvLength = *FvImageSize; | |
| FvHeader->Signature = EFI_FVH_SIGNATURE; | |
| FvHeader->Attributes = FvInfo.FvAttributes; | |
| FvHeader->Revision = EFI_FVH_REVISION; | |
| FvHeader->Reserved[0] = 0; | |
| FvHeader->Reserved[1] = 0; | |
| FvHeader->Reserved[2] = 0; | |
| // | |
| // Copy firmware block map | |
| // | |
| for (Index = 0; FvInfo.FvBlocks[Index].NumBlocks != 0; Index++) { | |
| FvHeader->FvBlockMap[Index].NumBlocks = FvInfo.FvBlocks[Index].NumBlocks; | |
| FvHeader->FvBlockMap[Index].BlockLength = FvInfo.FvBlocks[Index].BlockLength; | |
| } | |
| // | |
| // Add block map terminator | |
| // | |
| FvHeader->FvBlockMap[Index].NumBlocks = 0; | |
| FvHeader->FvBlockMap[Index].BlockLength = 0; | |
| // | |
| // Complete the header | |
| // | |
| FvHeader->HeaderLength = (UINT16) (((UINTN) &(FvHeader->FvBlockMap[Index + 1])) - (UINTN) *FvImage); | |
| FvHeader->Checksum = 0; | |
| FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); | |
| // | |
| // If there is no FFS file, find and generate each components of the FV | |
| // | |
| if (FvInfo.FvFiles[0][0] == 0) { | |
| Status = GenNonFFSFv (*FvImage, &FvInfo); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not generate NonFFS FV.\n"); | |
| free (*FvImage); | |
| return EFI_ABORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Initialize our "file" view of the buffer | |
| // | |
| FvImageMemoryFile.FileImage = *FvImage; | |
| FvImageMemoryFile.CurrentFilePointer = *FvImage + FvHeader->HeaderLength; | |
| FvImageMemoryFile.Eof = *FvImage +*FvImageSize; | |
| // | |
| // Initialize our "file" view of the symbol file. | |
| // | |
| SymImageMemoryFile.FileImage = *SymImage; | |
| SymImageMemoryFile.CurrentFilePointer = *SymImage; | |
| SymImageMemoryFile.Eof = *FvImage + SYMBOL_FILE_SIZE; | |
| // | |
| // Initialize the FV library. | |
| // | |
| InitializeFvLib (FvImageMemoryFile.FileImage, FvInfo.Size); | |
| // | |
| // Files start on 8 byte alignments, so move to the next 8 byte aligned | |
| // address. For now, just assert if it isn't. Currently FV header is | |
| // always a multiple of 8 bytes. | |
| // BUGBUG: Handle this better | |
| // | |
| assert ((((UINTN) FvImageMemoryFile.CurrentFilePointer) % 8) == 0); | |
| // | |
| // Initialize the VTF file address. | |
| // | |
| VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof; | |
| // | |
| // Add files to FV | |
| // | |
| for (Index = 0; FvInfo.FvFiles[Index][0] != 0; Index++) { | |
| // | |
| // Add the file | |
| // | |
| Status = AddFile (&FvImageMemoryFile, &FvInfo, Index, &VtfFileImage, &SymImageMemoryFile); | |
| // | |
| // Exit if error detected while adding the file | |
| // | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not add file %s.\n", FvInfo.FvFiles[Index]); | |
| free (*FvImage); | |
| return EFI_ABORTED; | |
| } | |
| } | |
| // | |
| // If there is a VTF file, some special actions need to occur. | |
| // | |
| if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) { | |
| // | |
| // Pad from the end of the last file to the beginning of the VTF file. | |
| // | |
| Status = PadFvImage (&FvImageMemoryFile, VtfFileImage); | |
| if (EFI_ERROR (Status)) { | |
| printf ("ERROR: Could not create the pad file between the last file and the VTF file.\n"); | |
| free (*FvImage); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Update reset vector (SALE_ENTRY for IPF) | |
| // Now for IA32 and IA64 platform, the fv which has bsf file must have the | |
| // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the | |
| // reset vector. If the PEI Core is found, the VTF file will probably get | |
| // corrupted by updating the entry point. | |
| // | |
| if ((FvInfo.BaseAddress + FvInfo.Size) == FV_IMAGES_TOP_ADDRESS) { | |
| Status = UpdateResetVector (&FvImageMemoryFile, &FvInfo, VtfFileImage); | |
| if (EFI_ERROR(Status)) { | |
| printf ("ERROR: Could not update the reset vector.\n"); | |
| free (*FvImage); | |
| return EFI_ABORTED; | |
| } | |
| } | |
| } | |
| // | |
| // Determine final Sym file size | |
| // | |
| *SymImageSize = SymImageMemoryFile.CurrentFilePointer - SymImageMemoryFile.FileImage; | |
| // | |
| // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV | |
| // | |
| if (FvHeader->Attributes | EFI_FVB_ALIGNMENT_CAP) { | |
| for (Index = 1; Index <= 16; Index ++) { | |
| if ((1 << Index) < MaxFfsAlignment) { | |
| // | |
| // Unset the unsupported alignment attribute. | |
| // | |
| FvHeader->Attributes = FvHeader->Attributes & ~((1 << Index) * EFI_FVB_ALIGNMENT_CAP); | |
| } else { | |
| // | |
| // Set the supported alignment attribute. | |
| // | |
| FvHeader->Attributes = FvHeader->Attributes | ((1 << Index) * EFI_FVB_ALIGNMENT_CAP); | |
| } | |
| } | |
| // | |
| // Update Checksum for FvHeader | |
| // | |
| FvHeader->Checksum = 0; | |
| FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| UpdatePeiCoreEntryInFit ( | |
| IN FIT_TABLE *FitTablePtr, | |
| IN UINT64 PeiCorePhysicalAddress | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from | |
| Sec to Pei Core | |
| Arguments: | |
| FitTablePtr - The pointer of FIT_TABLE. | |
| PeiCorePhysicalAddress - The address of Pei Core entry. | |
| Returns: | |
| EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully. | |
| EFI_NOT_FOUND - Not found the PEI_CORE FIT entry. | |
| --*/ | |
| { | |
| FIT_TABLE *TmpFitPtr; | |
| UINTN Index; | |
| UINTN NumFitComponents; | |
| TmpFitPtr = FitTablePtr; | |
| NumFitComponents = TmpFitPtr->CompSize; | |
| for (Index = 0; Index < NumFitComponents; Index++) { | |
| if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) { | |
| TmpFitPtr->CompAddress = PeiCorePhysicalAddress; | |
| return EFI_SUCCESS; | |
| } | |
| TmpFitPtr++; | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| VOID | |
| UpdateFitCheckSum ( | |
| IN FIT_TABLE *FitTablePtr | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function is used to update the checksum for FIT. | |
| Arguments: | |
| FitTablePtr - The pointer of FIT_TABLE. | |
| Returns: | |
| None. | |
| --*/ | |
| { | |
| if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) { | |
| FitTablePtr->CheckSum = 0; | |
| FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16); | |
| } | |
| } |