338 lines
10 KiB
C
338 lines
10 KiB
C
/** @file
|
|
* Main file supporting the SEC Phase for Versatile Express
|
|
*
|
|
* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DebugAgentLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PeCoffExtraActionLib.h>
|
|
#include <Library/PeCoffLib.h>
|
|
|
|
#include <Pi/PiFirmwareFile.h>
|
|
#include <Pi/PiFirmwareVolume.h>
|
|
|
|
#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
|
|
(ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
|
|
|
|
|
|
// Vector Table for Sec Phase
|
|
VOID
|
|
DebugAgentVectorTable (
|
|
VOID
|
|
);
|
|
|
|
/**
|
|
Returns the highest bit set of the State field
|
|
|
|
@param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
|
|
in the Attributes field.
|
|
@param FfsHeader Pointer to FFS File Header
|
|
|
|
|
|
@retval the highest bit in the State field
|
|
|
|
**/
|
|
STATIC
|
|
EFI_FFS_FILE_STATE
|
|
GetFileState (
|
|
IN UINT8 ErasePolarity,
|
|
IN EFI_FFS_FILE_HEADER *FfsHeader
|
|
)
|
|
{
|
|
EFI_FFS_FILE_STATE FileState;
|
|
EFI_FFS_FILE_STATE HighestBit;
|
|
|
|
FileState = FfsHeader->State;
|
|
|
|
if (ErasePolarity != 0) {
|
|
FileState = (EFI_FFS_FILE_STATE)~FileState;
|
|
}
|
|
|
|
HighestBit = 0x80;
|
|
while (HighestBit != 0 && (HighestBit & FileState) == 0) {
|
|
HighestBit >>= 1;
|
|
}
|
|
|
|
return HighestBit;
|
|
}
|
|
|
|
/**
|
|
Calculates the checksum of the header of a file.
|
|
The header is a zero byte checksum, so zero means header is good
|
|
|
|
@param FfsHeader Pointer to FFS File Header
|
|
|
|
@retval Checksum of the header
|
|
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
CalculateHeaderChecksum (
|
|
IN EFI_FFS_FILE_HEADER *FileHeader
|
|
)
|
|
{
|
|
UINT8 Sum;
|
|
|
|
// Calculate the sum of the header
|
|
Sum = CalculateSum8 ((CONST VOID*)FileHeader,sizeof(EFI_FFS_FILE_HEADER));
|
|
|
|
// State field (since this indicates the different state of file).
|
|
Sum = (UINT8)(Sum - FileHeader->State);
|
|
|
|
// Checksum field of the file is not part of the header checksum.
|
|
Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);
|
|
|
|
return Sum;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetFfsFile (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
|
|
IN EFI_FV_FILETYPE FileType,
|
|
OUT EFI_FFS_FILE_HEADER **FileHeader
|
|
)
|
|
{
|
|
UINT64 FvLength;
|
|
UINTN FileOffset;
|
|
EFI_FFS_FILE_HEADER *FfsFileHeader;
|
|
UINT8 ErasePolarity;
|
|
UINT8 FileState;
|
|
UINT32 FileLength;
|
|
UINT32 FileOccupiedSize;
|
|
|
|
ASSERT (FwVolHeader->Signature == EFI_FVH_SIGNATURE);
|
|
|
|
FvLength = FwVolHeader->FvLength;
|
|
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);
|
|
FileOffset = FwVolHeader->HeaderLength;
|
|
|
|
if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
|
ErasePolarity = 1;
|
|
} else {
|
|
ErasePolarity = 0;
|
|
}
|
|
|
|
while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
|
|
// Get FileState which is the highest bit of the State
|
|
FileState = GetFileState (ErasePolarity, FfsFileHeader);
|
|
|
|
switch (FileState) {
|
|
|
|
case EFI_FILE_HEADER_INVALID:
|
|
FileOffset += sizeof(EFI_FFS_FILE_HEADER);
|
|
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));
|
|
break;
|
|
|
|
case EFI_FILE_DATA_VALID:
|
|
case EFI_FILE_MARKED_FOR_UPDATE:
|
|
if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
|
|
ASSERT (FALSE);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (FfsFileHeader->Type == FileType) {
|
|
*FileHeader = FfsFileHeader;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
|
|
FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
|
|
|
|
FileOffset += FileOccupiedSize;
|
|
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
|
|
break;
|
|
|
|
case EFI_FILE_DELETED:
|
|
FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
|
|
FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
|
|
FileOffset += FileOccupiedSize;
|
|
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
|
|
break;
|
|
|
|
default:
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetImageContext (
|
|
IN EFI_FFS_FILE_HEADER *FfsHeader,
|
|
OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN ParsedLength;
|
|
UINTN SectionSize;
|
|
UINTN SectionLength;
|
|
EFI_COMMON_SECTION_HEADER *Section;
|
|
VOID *EfiImage;
|
|
UINTN ImageAddress;
|
|
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
|
|
VOID *CodeViewEntryPointer;
|
|
|
|
Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1);
|
|
SectionSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF;
|
|
SectionSize -= sizeof (EFI_FFS_FILE_HEADER);
|
|
ParsedLength = 0;
|
|
EfiImage = NULL;
|
|
|
|
while (ParsedLength < SectionSize) {
|
|
if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) {
|
|
EfiImage = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(Section + 1);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Size is 24 bits wide so mask upper 8 bits.
|
|
// SectionLength is adjusted it is 4 byte aligned.
|
|
// Go to the next section
|
|
//
|
|
SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
|
|
SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
|
|
ASSERT (SectionLength != 0);
|
|
ParsedLength += SectionLength;
|
|
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
|
|
}
|
|
|
|
if (EfiImage == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
// Initialize the Image Context
|
|
ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
|
|
ImageContext->Handle = EfiImage;
|
|
ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
|
|
|
|
Status = PeCoffLoaderGetImageInfo (ImageContext);
|
|
if (!EFI_ERROR(Status) && ((VOID*)(UINTN)ImageContext->DebugDirectoryEntryRva != NULL)) {
|
|
ImageAddress = ImageContext->ImageAddress;
|
|
if (ImageContext->IsTeImage) {
|
|
ImageAddress += sizeof (EFI_TE_IMAGE_HEADER) - ((EFI_TE_IMAGE_HEADER*)EfiImage)->StrippedSize;
|
|
}
|
|
|
|
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(ImageAddress + ImageContext->DebugDirectoryEntryRva);
|
|
if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
|
|
CodeViewEntryPointer = (VOID *) (ImageAddress + (UINTN) DebugEntry->RVA);
|
|
switch (* (UINT32 *) CodeViewEntryPointer) {
|
|
case CODEVIEW_SIGNATURE_NB10:
|
|
ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
|
|
break;
|
|
case CODEVIEW_SIGNATURE_RSDS:
|
|
ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
|
|
break;
|
|
case CODEVIEW_SIGNATURE_MTOC:
|
|
ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Initialize debug agent.
|
|
|
|
This function is used to set up debug environment to support source level debugging.
|
|
If certain Debug Agent Library instance has to save some private data in the stack,
|
|
this function must work on the mode that doesn't return to the caller, then
|
|
the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
|
|
function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
|
|
responsible to invoke the passing-in function at the end of InitializeDebugAgent().
|
|
|
|
If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
|
|
passing in the Context to be its parameter.
|
|
|
|
If Function() is NULL, Debug Agent Library instance will return after setup debug
|
|
environment.
|
|
|
|
@param[in] InitFlag Init flag is used to decide the initialize process.
|
|
@param[in] Context Context needed according to InitFlag; it was optional.
|
|
@param[in] Function Continue function called by debug agent library; it was
|
|
optional.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InitializeDebugAgent (
|
|
IN UINT32 InitFlag,
|
|
IN VOID *Context, OPTIONAL
|
|
IN DEBUG_AGENT_CONTINUE Function OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FFS_FILE_HEADER *FfsHeader;
|
|
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
|
|
|
// We use InitFlag to know if DebugAgent has been initialized from
|
|
// Sec (DEBUG_AGENT_INIT_PREMEM_SEC) or PrePi (DEBUG_AGENT_INIT_POSTMEM_SEC)
|
|
// modules
|
|
if (InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) {
|
|
//
|
|
// Get the Sec or PrePeiCore module (defined as SEC type module)
|
|
//
|
|
Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdSecureFvBaseAddress), EFI_FV_FILETYPE_SECURITY_CORE, &FfsHeader);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = GetImageContext (FfsHeader,&ImageContext);
|
|
if (!EFI_ERROR(Status)) {
|
|
PeCoffLoaderRelocateImageExtraAction (&ImageContext);
|
|
}
|
|
}
|
|
} else if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
|
|
//
|
|
// Get the PrePi or PrePeiCore module (defined as SEC type module)
|
|
//
|
|
Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdFvBaseAddress), EFI_FV_FILETYPE_SECURITY_CORE, &FfsHeader);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = GetImageContext (FfsHeader,&ImageContext);
|
|
if (!EFI_ERROR(Status)) {
|
|
PeCoffLoaderRelocateImageExtraAction (&ImageContext);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the PeiCore module (defined as PEI_CORE type module)
|
|
//
|
|
Status = GetFfsFile ((EFI_FIRMWARE_VOLUME_HEADER*)(UINTN)PcdGet64 (PcdFvBaseAddress), EFI_FV_FILETYPE_PEI_CORE, &FfsHeader);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = GetImageContext (FfsHeader,&ImageContext);
|
|
if (!EFI_ERROR(Status)) {
|
|
PeCoffLoaderRelocateImageExtraAction (&ImageContext);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Enable/Disable the interrupt of debug timer and return the interrupt state
|
|
prior to the operation.
|
|
|
|
If EnableStatus is TRUE, enable the interrupt of debug timer.
|
|
If EnableStatus is FALSE, disable the interrupt of debug timer.
|
|
|
|
@param[in] EnableStatus Enable/Disable.
|
|
|
|
@return FALSE always.
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
SaveAndSetDebugTimerInterrupt (
|
|
IN BOOLEAN EnableStatus
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|