/** @file | |
* Main file supporting the SEC Phase for Versatile Express | |
* | |
* Copyright (c) 2011-2014, ARM Limited. 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. | |
* | |
**/ | |
#include <Uefi.h> | |
#include <Library/ArmLib.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 Libary 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; | |
// Now we've got UART, check the Debug Agent Vector Table | |
// Note: The AArch64 Vector table must be 2k-byte aligned - if this assertion fails ensure | |
// 'Align=4K' is defined into your FDF for this module. | |
ASSERT (((UINTN)DebugAgentVectorTable & ARM_VECTOR_TABLE_ALIGNMENT) == 0); | |
ArmWriteVBar ((UINTN)DebugAgentVectorTable); | |
// We use InitFlag to know if DebugAgent has been intialized 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; | |
} | |