audk/Tools/CCode/Source/GenFvImage/GenFvImageLib.c

2763 lines
80 KiB
C
Raw Normal View History

/*++
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 "EfiCompress.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);
}
}