mirror of https://github.com/acidanthera/audk.git
2728 lines
79 KiB
C
2728 lines
79 KiB
C
/*++
|
|
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"
|
|
|
|
|
|
//
|
|
// 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:
|
|
//
|
|
// 1 byte alignment
|
|
//
|
|
*Alignment = (1 << 0);
|
|
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, '\\');
|
|
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, "\\");
|
|
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
|
|
//
|
|
#ifdef __GNUC__
|
|
{
|
|
struct stat stat_buf;
|
|
fstat(fileno(NewFile), &stat_buf);
|
|
FileSize = stat_buf.st_size;
|
|
}
|
|
#else
|
|
FileSize = _filelength (fileno (NewFile));
|
|
#endif
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
//
|
|
// 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;
|
|
|
|
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);
|
|
}
|
|
}
|