Adding support for BeagleBoard.

ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers.
EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell.
BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine).


git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
AJFISH
2009-12-06 01:57:05 +00:00
parent f7753a96ba
commit 2ef2b01e07
294 changed files with 47954 additions and 0 deletions

View File

@@ -0,0 +1,841 @@
/** @file
Implementation of the 6 PEI Ffs (FV) APIs in library form.
This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
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 <PrePi.h>
#include <Library/ExtractGuidedSectionLib.h>
#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
(ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
/**
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 *Ptr;
UINTN Index;
UINT8 Sum;
Sum = 0;
Ptr = (UINT8 *)FileHeader;
for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) {
Sum = (UINT8)(Sum + Ptr[Index]);
Sum = (UINT8)(Sum + Ptr[Index+1]);
Sum = (UINT8)(Sum + Ptr[Index+2]);
Sum = (UINT8)(Sum + Ptr[Index+3]);
}
for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) {
Sum = (UINT8)(Sum + Ptr[Index]);
}
//
// 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;
}
/**
Given a FileHandle return the VolumeHandle
@param FileHandle File handle to look up
@param VolumeHandle Match for FileHandle
@retval TRUE VolumeHandle is valid
**/
STATIC
BOOLEAN
EFIAPI
FileHandleToVolume (
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT EFI_PEI_FV_HANDLE *VolumeHandle
)
{
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_PEI_HOB_POINTERS Hob;
Hob.Raw = GetHobList ();
if (Hob.Raw == NULL) {
return FALSE;
}
do {
Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
if (Hob.Raw != NULL) {
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress);
if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
*VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;
return TRUE;
}
Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
}
} while (Hob.Raw != NULL);
return FALSE;
}
/**
Given the input file pointer, search for the next matching file in the
FFS volume as defined by SearchType. The search starts from FileHeader inside
the Firmware Volume defined by FwVolHeader.
@param FileHandle File handle to look up
@param VolumeHandle Match for FileHandle
**/
EFI_STATUS
FindFileEx (
IN CONST EFI_PEI_FV_HANDLE FvHandle,
IN CONST EFI_GUID *FileName, OPTIONAL
IN EFI_FV_FILETYPE SearchType,
IN OUT EFI_PEI_FILE_HANDLE *FileHandle
)
{
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_FFS_FILE_HEADER **FileHeader;
EFI_FFS_FILE_HEADER *FfsFileHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
UINT32 FileLength;
UINT32 FileOccupiedSize;
UINT32 FileOffset;
UINT64 FvLength;
UINT8 ErasePolarity;
UINT8 FileState;
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;
FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
FvLength = FwVolHeader->FvLength;
if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
ErasePolarity = 1;
} else {
ErasePolarity = 0;
}
//
// If FileHeader is not specified (NULL) or FileName is not NULL,
// start with the first file in the firmware volume. Otherwise,
// start from the FileHeader.
//
if ((*FileHeader == NULL) || (FileName != NULL)) {
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);
if (FwVolHeader->ExtHeaderOffset != 0) {
FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset);
FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize);
}
} else {
//
// Length is 24 bits wide so mask upper 8 bits
// FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
//
FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;
FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
}
FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
ASSERT (FileOffset <= 0xFFFFFFFF);
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);
*FileHeader = NULL;
return EFI_NOT_FOUND;
}
FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
if (FileName != NULL) {
if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
*FileHeader = FfsFileHeader;
return EFI_SUCCESS;
}
} else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
(FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
*FileHeader = FfsFileHeader;
return EFI_SUCCESS;
}
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:
*FileHeader = NULL;
return EFI_NOT_FOUND;
}
}
*FileHeader = NULL;
return EFI_NOT_FOUND;
}
/**
Go through the file to search SectionType section,
when meeting an encapsuled section.
@param SectionType - Filter to find only section of this type.
@param Section - From where to search.
@param SectionSize - The file size to search.
@param OutputBuffer - Pointer to the section to search.
@retval EFI_SUCCESS
**/
EFI_STATUS
FfsProcessSection (
IN EFI_SECTION_TYPE SectionType,
IN EFI_COMMON_SECTION_HEADER *Section,
IN UINTN SectionSize,
OUT VOID **OutputBuffer
)
{
EFI_STATUS Status;
UINT32 SectionLength;
UINT32 ParsedLength;
EFI_COMPRESSION_SECTION *CompressionSection;
UINTN DstBufferSize;
VOID *ScratchBuffer;
UINT32 ScratchBufferSize;
VOID *DstBuffer;
UINT16 SectionAttribute;
UINT32 AuthenticationStatus;
*OutputBuffer = NULL;
ParsedLength = 0;
Status = EFI_NOT_FOUND;
while (ParsedLength < SectionSize) {
if (Section->Type == SectionType) {
*OutputBuffer = (VOID *)(Section + 1);
return EFI_SUCCESS;
} else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {
if (Section->Type == EFI_SECTION_COMPRESSION) {
CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {
return EFI_UNSUPPORTED;
}
Status = UefiDecompressGetInfo (
(UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
(UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
(UINT32 *) &DstBufferSize,
&ScratchBufferSize
);
} else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
Status = ExtractGuidedSectionGetInfo (
Section,
(UINT32 *) &DstBufferSize,
&ScratchBufferSize,
&SectionAttribute
);
}
if (EFI_ERROR (Status)) {
//
// GetInfo failed
//
DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
return EFI_NOT_FOUND;
}
//
// Allocate scratch buffer
//
ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
if (ScratchBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Allocate destination buffer, extra one page for adjustment
//
DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
if (DstBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
// to make section data at page alignment.
//
DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
//
// Call decompress function
//
if (Section->Type == EFI_SECTION_COMPRESSION) {
Status = UefiDecompress (
(CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
DstBuffer,
ScratchBuffer
);
} else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
Status = ExtractGuidedSectionDecode (
Section,
&DstBuffer,
ScratchBuffer,
&AuthenticationStatus
);
}
if (EFI_ERROR (Status)) {
//
// Decompress failed
//
DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
return EFI_NOT_FOUND;
} else {
return FfsProcessSection (
SectionType,
DstBuffer,
DstBufferSize,
OutputBuffer
);
}
}
//
// 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);
}
return EFI_NOT_FOUND;
}
/**
This service enables discovery sections of a given type within a valid FFS file.
@param SearchType The value of the section type to find.
@param FfsFileHeader A pointer to the file header that contains the set of sections to
be searched.
@param SectionData A pointer to the discovered section, if successful.
@retval EFI_SUCCESS The section was found.
@retval EFI_NOT_FOUND The section was not found.
**/
EFI_STATUS
EFIAPI
FfsFindSectionData (
IN EFI_SECTION_TYPE SectionType,
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT VOID **SectionData
)
{
EFI_FFS_FILE_HEADER *FfsFileHeader;
UINT32 FileSize;
EFI_COMMON_SECTION_HEADER *Section;
FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
//
// Size is 24 bits wide so mask upper 8 bits.
// Does not include FfsFileHeader header size
// FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
//
Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
FileSize -= sizeof (EFI_FFS_FILE_HEADER);
return FfsProcessSection (
SectionType,
Section,
FileSize,
SectionData
);
}
/**
This service enables discovery of additional firmware files.
@param SearchType A filter to find files only of this type.
@param FwVolHeader Pointer to the firmware volume header of the volume to search.
This parameter must point to a valid FFS volume.
@param FileHeader Pointer to the current file from which to begin searching.
@retval EFI_SUCCESS The file was found.
@retval EFI_NOT_FOUND The file was not found.
@retval EFI_NOT_FOUND The header checksum was not zero.
**/
EFI_STATUS
EFIAPI
FfsFindNextFile (
IN UINT8 SearchType,
IN EFI_PEI_FV_HANDLE VolumeHandle,
IN OUT EFI_PEI_FILE_HANDLE *FileHandle
)
{
return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);
}
/**
This service enables discovery of additional firmware volumes.
@param Instance This instance of the firmware volume to find. The value 0 is the
Boot Firmware Volume (BFV).
@param FwVolHeader Pointer to the firmware volume header of the volume to return.
@retval EFI_SUCCESS The volume was found.
@retval EFI_NOT_FOUND The volume was not found.
**/
EFI_STATUS
EFIAPI
FfsFindNextVolume (
IN UINTN Instance,
IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
)
{
EFI_PEI_HOB_POINTERS Hob;
Hob.Raw = GetHobList ();
if (Hob.Raw == NULL) {
return EFI_NOT_FOUND;
}
do {
Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
if (Hob.Raw != NULL) {
if (Instance-- == 0) {
*VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);
return EFI_SUCCESS;
}
Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
}
} while (Hob.Raw != NULL);
return EFI_NOT_FOUND;
}
/**
Find a file in the volume by name
@param FileName A pointer to the name of the file to
find within the firmware volume.
@param VolumeHandle The firmware volume to search FileHandle
Upon exit, points to the found file's
handle or NULL if it could not be found.
@retval EFI_SUCCESS File was found.
@retval EFI_NOT_FOUND File was not found.
@retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or
FileName was NULL.
**/
EFI_STATUS
EFIAPI
FfsFindFileByName (
IN CONST EFI_GUID *FileName,
IN EFI_PEI_FV_HANDLE VolumeHandle,
OUT EFI_PEI_FILE_HANDLE *FileHandle
)
{
EFI_STATUS Status;
if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);
if (Status == EFI_NOT_FOUND) {
*FileHandle = NULL;
}
return Status;
}
/**
Get information about the file by name.
@param FileHandle Handle of the file.
@param FileInfo Upon exit, points to the file's
information.
@retval EFI_SUCCESS File information returned.
@retval EFI_INVALID_PARAMETER If FileHandle does not
represent a valid file.
@retval EFI_INVALID_PARAMETER If FileInfo is NULL.
**/
EFI_STATUS
EFIAPI
FfsGetFileInfo (
IN EFI_PEI_FILE_HANDLE FileHandle,
OUT EFI_FV_FILE_INFO *FileInfo
)
{
UINT8 FileState;
UINT8 ErasePolarity;
EFI_FFS_FILE_HEADER *FileHeader;
EFI_PEI_FV_HANDLE VolumeHandle;
if ((FileHandle == NULL) || (FileInfo == NULL)) {
return EFI_INVALID_PARAMETER;
}
VolumeHandle = 0;
//
// Retrieve the FirmwareVolume which the file resides in.
//
if (!FileHandleToVolume(FileHandle, &VolumeHandle)) {
return EFI_INVALID_PARAMETER;
}
if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
ErasePolarity = 1;
} else {
ErasePolarity = 0;
}
//
// Get FileState which is the highest bit of the State
//
FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
switch (FileState) {
case EFI_FILE_DATA_VALID:
case EFI_FILE_MARKED_FOR_UPDATE:
break;
default:
return EFI_INVALID_PARAMETER;
}
FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
FileInfo->FileType = FileHeader->Type;
FileInfo->FileAttributes = FileHeader->Attributes;
FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
FileInfo->Buffer = (FileHeader + 1);
return EFI_SUCCESS;
}
/**
Get Information about the volume by name
@param VolumeHandle Handle of the volume.
@param VolumeInfo Upon exit, points to the volume's
information.
@retval EFI_SUCCESS File information returned.
@retval EFI_INVALID_PARAMETER If FileHandle does not
represent a valid file.
@retval EFI_INVALID_PARAMETER If FileInfo is NULL.
**/
EFI_STATUS
EFIAPI
FfsGetVolumeInfo (
IN EFI_PEI_FV_HANDLE VolumeHandle,
OUT EFI_FV_INFO *VolumeInfo
)
{
EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
if (VolumeInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// VolumeHandle may not align at 8 byte,
// but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
// So, Copy FvHeader into the local FvHeader structure.
//
CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
//
// Check Fv Image Signature
//
if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
VolumeInfo->FvAttributes = FwVolHeader.Attributes;
VolumeInfo->FvStart = (VOID *) VolumeHandle;
VolumeInfo->FvSize = FwVolHeader.FvLength;
CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
if (FwVolHeader.ExtHeaderOffset != 0) {
FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
}
return EFI_SUCCESS;
}
/**
Search through every FV until you find a file of type FileType
@param FileType File handle of a Fv type file.
@param Volumehandle On succes Volume Handle of the match
@param FileHandle On success File Handle of the match
@retval EFI_NOT_FOUND FV image can't be found.
@retval EFI_SUCCESS Successfully found FileType
**/
EFI_STATUS
EFIAPI
FfsAnyFvFindFirstFile (
IN EFI_FV_FILETYPE FileType,
OUT EFI_PEI_FV_HANDLE *VolumeHandle,
OUT EFI_PEI_FILE_HANDLE *FileHandle
)
{
EFI_STATUS Status;
UINTN Instance;
//
// Search every FV for the DXE Core
//
Instance = 0;
*FileHandle = NULL;
while (1)
{
Status = FfsFindNextVolume (Instance++, VolumeHandle);
if (EFI_ERROR (Status))
{
break;
}
Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);
if (!EFI_ERROR (Status))
{
break;
}
}
return Status;
}
/**
Get Fv image from the FV type file, then add FV & FV2 Hob.
@param FileHandle File handle of a Fv type file.
@retval EFI_NOT_FOUND FV image can't be found.
@retval EFI_SUCCESS Successfully to process it.
**/
EFI_STATUS
EFIAPI
FfsProcessFvFile (
IN EFI_PEI_FILE_HANDLE FvFileHandle
)
{
EFI_STATUS Status;
EFI_PEI_FV_HANDLE FvImageHandle;
EFI_FV_INFO FvImageInfo;
UINT32 FvAlignment;
VOID *FvBuffer;
EFI_PEI_HOB_POINTERS HobFv2;
FvBuffer = NULL;
//
// Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
// been extracted.
//
HobFv2.Raw = GetHobList ();
while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {
//
// this FILE has been dispatched, it will not be dispatched again.
//
return EFI_SUCCESS;
}
HobFv2.Raw = GET_NEXT_HOB (HobFv2);
}
//
// Find FvImage in FvFile
//
Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Collect FvImage Info.
//
Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
ASSERT_EFI_ERROR (Status);
//
// FvAlignment must be more than 8 bytes required by FvHeader structure.
//
FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
if (FvAlignment < 8) {
FvAlignment = 8;
}
//
// Check FvImage
//
if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
if (FvBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
//
// Update FvImageInfo after reload FvImage to new aligned memory
//
FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
}
//
// Inform HOB consumer phase, i.e. DXE core, the existance of this FV
//
BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize);
//
// Makes the encapsulated volume show up in DXE phase to skip processing of
// encapsulated file again.
//
BuildFv2Hob (
(EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
FvImageInfo.FvSize,
&FvImageInfo.FvName,
&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
);
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,808 @@
/** @file
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
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 <PrePi.h>
#include <Guid/MemoryTypeInformation.h>
//
// Have to use build system to set the original value in case we are running
// from FLASH and globals don't work. So if you do a GetHobList() and gHobList
// and gHobList is NULL the PCD default values are used.
//
VOID *gHobList = NULL;
// May want to put this into a library so you only need the PCD setings if you are using the feature?
VOID
BuildMemoryTypeInformationHob (
VOID
)
{
EFI_MEMORY_TYPE_INFORMATION Info[10];
Info[0].Type = EfiACPIReclaimMemory;
Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory);
Info[1].Type = EfiACPIMemoryNVS;
Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS);
Info[2].Type = EfiReservedMemoryType;
Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType);
Info[3].Type = EfiRuntimeServicesData;
Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData);
Info[4].Type = EfiRuntimeServicesCode;
Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode);
Info[5].Type = EfiBootServicesCode;
Info[5].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesCode);
Info[6].Type = EfiBootServicesData;
Info[6].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesData);
Info[7].Type = EfiLoaderCode;
Info[7].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderCode);
Info[8].Type = EfiLoaderData;
Info[8].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderData);
// Terminator for the list
Info[9].Type = EfiMaxMemoryType;
Info[9].NumberOfPages = 0;
BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info));
}
/**
**/
VOID
CreateHobList (
IN VOID *MemoryBegin,
IN UINTN MemoryLength,
IN VOID *HobBase,
IN VOID *StackBase
)
{
EFI_HOB_HANDOFF_INFO_TABLE *Hob;
EFI_HOB_GENERIC_HEADER *HobEnd;
EFI_RESOURCE_ATTRIBUTE_TYPE Attributes;
Hob = HobBase;
HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
Hob->Header.HobLength = sizeof(EFI_HOB_HANDOFF_INFO_TABLE);
Hob->Header.Reserved = 0;
HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER);
HobEnd->Reserved = 0;
Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION;
Hob->EfiMemoryTop = (UINTN)MemoryBegin + MemoryLength;
Hob->EfiMemoryBottom = (UINTN)MemoryBegin;
Hob->EfiFreeMemoryTop = (UINTN)StackBase;
Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1);
Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
SetHobList (Hob);
BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize));
Attributes =(
EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_TESTED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
);
BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, Attributes, (UINTN)MemoryBegin, MemoryLength);
BuildStackHob ((UINTN)StackBase, Hob->EfiMemoryTop - (UINTN)StackBase);
if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) {
// Optional feature that helps prevent EFI memory map fragmentation.
BuildMemoryTypeInformationHob ();
}
}
VOID
EFIAPI
BuildFvHobs (
IN EFI_PHYSICAL_ADDRESS PhysicalStart,
IN UINT64 NumberOfBytes,
IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute
)
{
EFI_RESOURCE_ATTRIBUTE_TYPE Resource;
BuildFvHob (PhysicalStart, NumberOfBytes);
if (ResourceAttribute == NULL) {
Resource = (EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_TESTED |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE);
} else {
Resource = *ResourceAttribute;
}
BuildResourceDescriptorHob (EFI_RESOURCE_FIRMWARE_DEVICE, Resource, PhysicalStart, NumberOfBytes);
}
/**
Returns the pointer to the HOB list.
This function returns the pointer to first HOB in the list.
@return The pointer to the HOB list.
**/
VOID *
EFIAPI
GetHobList (
VOID
)
{
if (gHobList == NULL) {
return (VOID *)(UINTN)PcdGet32 (PcdPrePiHobBase);
} else {
return gHobList;
}
}
/**
Updates the pointer to the HOB list.
@param HobList Hob list pointer to store
**/
EFI_STATUS
EFIAPI
SetHobList (
IN VOID *HobList
)
{
gHobList = HobList;
//
// If this code is running from ROM this could fail
//
return (gHobList == HobList) ? EFI_SUCCESS: EFI_UNSUPPORTED;
}
VOID *
CreateHob (
IN UINT16 HobType,
IN UINT16 HobLength
)
{
EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob;
EFI_HOB_GENERIC_HEADER *HobEnd;
EFI_PHYSICAL_ADDRESS FreeMemory;
VOID *Hob;
HandOffHob = GetHobList ();
HobLength = (UINT16)((HobLength + 0x7) & (~0x7));
FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom;
if (FreeMemory < HobLength) {
return NULL;
}
Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList;
((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType;
((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength;
((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0;
HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength);
HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER);
HobEnd->Reserved = 0;
HobEnd++;
HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd;
return Hob;
}
/**
Returns the next instance of a HOB type from the starting HOB.
This function searches the first instance of a HOB type from the starting HOB pointer.
If there does not exist such HOB type from the starting HOB pointer, it will return NULL.
In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
unconditionally: it returns HobStart back if HobStart itself meets the requirement;
caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
If HobStart is NULL, then ASSERT().
@param Type The HOB type to return.
@param HobStart The starting HOB pointer to search from.
@return The next instance of a HOB type from the starting HOB.
**/
VOID *
EFIAPI
GetNextHob (
IN UINT16 Type,
IN CONST VOID *HobStart
)
{
EFI_PEI_HOB_POINTERS Hob;
ASSERT (HobStart != NULL);
Hob.Raw = (UINT8 *) HobStart;
//
// Parse the HOB list until end of list or matching type is found.
//
while (!END_OF_HOB_LIST (Hob)) {
if (Hob.Header->HobType == Type) {
return Hob.Raw;
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
return NULL;
}
/**
Returns the first instance of a HOB type among the whole HOB list.
This function searches the first instance of a HOB type among the whole HOB list.
If there does not exist such HOB type in the HOB list, it will return NULL.
@param Type The HOB type to return.
@return The next instance of a HOB type from the starting HOB.
**/
VOID *
EFIAPI
GetFirstHob (
IN UINT16 Type
)
{
VOID *HobList;
HobList = GetHobList ();
return GetNextHob (Type, HobList);
}
/**
This function searches the first instance of a HOB from the starting HOB pointer.
Such HOB should satisfy two conditions:
its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
If there does not exist such HOB from the starting HOB pointer, it will return NULL.
Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
to extract the data section and its size info respectively.
In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer
unconditionally: it returns HobStart back if HobStart itself meets the requirement;
caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart.
If Guid is NULL, then ASSERT().
If HobStart is NULL, then ASSERT().
@param Guid The GUID to match with in the HOB list.
@param HobStart A pointer to a Guid.
@return The next instance of the matched GUID HOB from the starting HOB.
**/
VOID *
EFIAPI
GetNextGuidHob (
IN CONST EFI_GUID *Guid,
IN CONST VOID *HobStart
){
EFI_PEI_HOB_POINTERS GuidHob;
GuidHob.Raw = (UINT8 *) HobStart;
while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) {
if (CompareGuid (Guid, &GuidHob.Guid->Name)) {
break;
}
GuidHob.Raw = GET_NEXT_HOB (GuidHob);
}
return GuidHob.Raw;
}
/**
This function searches the first instance of a HOB among the whole HOB list.
Such HOB should satisfy two conditions:
its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid.
If there does not exist such HOB from the starting HOB pointer, it will return NULL.
Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE ()
to extract the data section and its size info respectively.
If Guid is NULL, then ASSERT().
@param Guid The GUID to match with in the HOB list.
@return The first instance of the matched GUID HOB among the whole HOB list.
**/
VOID *
EFIAPI
GetFirstGuidHob (
IN CONST EFI_GUID *Guid
)
{
VOID *HobList;
HobList = GetHobList ();
return GetNextGuidHob (Guid, HobList);
}
/**
Get the Boot Mode from the HOB list.
This function returns the system boot mode information from the
PHIT HOB in HOB list.
@param VOID
@return The Boot Mode.
**/
EFI_BOOT_MODE
EFIAPI
GetBootMode (
VOID
)
{
EFI_PEI_HOB_POINTERS Hob;
Hob.Raw = GetHobList ();
return Hob.HandoffInformationTable->BootMode;
}
/**
Get the Boot Mode from the HOB list.
This function returns the system boot mode information from the
PHIT HOB in HOB list.
@param VOID
@return The Boot Mode.
**/
EFI_STATUS
EFIAPI
SetBootMode (
IN EFI_BOOT_MODE BootMode
)
{
EFI_PEI_HOB_POINTERS Hob;
Hob.Raw = GetHobList ();
Hob.HandoffInformationTable->BootMode = BootMode;
return BootMode;
}
/**
Builds a HOB for a loaded PE32 module.
This function builds a HOB for a loaded PE32 module.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If ModuleName is NULL, then ASSERT().
If there is no additional space for HOB creation, then ASSERT().
@param ModuleName The GUID File Name of the module.
@param MemoryAllocationModule The 64 bit physical address of the module.
@param ModuleLength The length of the module in bytes.
@param EntryPoint The 64 bit physical address of the module entry point.
**/
VOID
EFIAPI
BuildModuleHob (
IN CONST EFI_GUID *ModuleName,
IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule,
IN UINT64 ModuleLength,
IN EFI_PHYSICAL_ADDRESS EntryPoint
)
{
EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob;
ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) &&
((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0));
Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE));
CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
Hob->MemoryAllocationHeader.MemoryLength = ModuleLength;
Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode;
//
// Zero the reserved space to match HOB spec
//
ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved));
CopyGuid (&Hob->ModuleName, ModuleName);
Hob->EntryPoint = EntryPoint;
}
/**
Builds a HOB that describes a chunk of system memory.
This function builds a HOB that describes a chunk of system memory.
If there is no additional space for HOB creation, then ASSERT().
@param ResourceType The type of resource described by this HOB.
@param ResourceAttribute The resource attributes of the memory described by this HOB.
@param PhysicalStart The 64 bit physical address of memory described by this HOB.
@param NumberOfBytes The length of the memory described by this HOB in bytes.
**/
VOID
EFIAPI
BuildResourceDescriptorHob (
IN EFI_RESOURCE_TYPE ResourceType,
IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute,
IN EFI_PHYSICAL_ADDRESS PhysicalStart,
IN UINT64 NumberOfBytes
)
{
EFI_HOB_RESOURCE_DESCRIPTOR *Hob;
Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR));
Hob->ResourceType = ResourceType;
Hob->ResourceAttribute = ResourceAttribute;
Hob->PhysicalStart = PhysicalStart;
Hob->ResourceLength = NumberOfBytes;
}
/**
Builds a GUID HOB with a certain data length.
This function builds a customized HOB tagged with a GUID for identification
and returns the start address of GUID HOB data so that caller can fill the customized data.
The HOB Header and Name field is already stripped.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If Guid is NULL, then ASSERT().
If there is no additional space for HOB creation, then ASSERT().
If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
@param Guid The GUID to tag the customized HOB.
@param DataLength The size of the data payload for the GUID HOB.
@return The start address of GUID HOB data.
**/
VOID *
EFIAPI
BuildGuidHob (
IN CONST EFI_GUID *Guid,
IN UINTN DataLength
)
{
EFI_HOB_GUID_TYPE *Hob;
//
// Make sure that data length is not too long.
//
ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE)));
Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength));
CopyGuid (&Hob->Name, Guid);
return Hob + 1;
}
/**
Copies a data buffer to a newly-built HOB.
This function builds a customized HOB tagged with a GUID for identification,
copies the input data to the HOB data field and returns the start address of the GUID HOB data.
The HOB Header and Name field is already stripped.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If Guid is NULL, then ASSERT().
If Data is NULL and DataLength > 0, then ASSERT().
If there is no additional space for HOB creation, then ASSERT().
If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT().
@param Guid The GUID to tag the customized HOB.
@param Data The data to be copied into the data field of the GUID HOB.
@param DataLength The size of the data payload for the GUID HOB.
@return The start address of GUID HOB data.
**/
VOID *
EFIAPI
BuildGuidDataHob (
IN CONST EFI_GUID *Guid,
IN VOID *Data,
IN UINTN DataLength
)
{
VOID *HobData;
ASSERT (Data != NULL || DataLength == 0);
HobData = BuildGuidHob (Guid, DataLength);
return CopyMem (HobData, Data, DataLength);
}
/**
Builds a Firmware Volume HOB.
This function builds a Firmware Volume HOB.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param BaseAddress The base address of the Firmware Volume.
@param Length The size of the Firmware Volume in bytes.
**/
VOID
EFIAPI
BuildFvHob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_HOB_FIRMWARE_VOLUME *Hob;
Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME));
Hob->BaseAddress = BaseAddress;
Hob->Length = Length;
}
/**
Builds a EFI_HOB_TYPE_FV2 HOB.
This function builds a EFI_HOB_TYPE_FV2 HOB.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param BaseAddress The base address of the Firmware Volume.
@param Length The size of the Firmware Volume in bytes.
@param FvName The name of the Firmware Volume.
@param FileName The name of the file.
**/
VOID
EFIAPI
BuildFv2Hob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN CONST EFI_GUID *FvName,
IN CONST EFI_GUID *FileName
)
{
EFI_HOB_FIRMWARE_VOLUME2 *Hob;
Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2));
Hob->BaseAddress = BaseAddress;
Hob->Length = Length;
CopyGuid (&Hob->FvName, FvName);
CopyGuid (&Hob->FileName, FileName);
}
/**
Builds a Capsule Volume HOB.
This function builds a Capsule Volume HOB.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param BaseAddress The base address of the Capsule Volume.
@param Length The size of the Capsule Volume in bytes.
**/
VOID
EFIAPI
BuildCvHob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
ASSERT (FALSE);
}
/**
Builds a HOB for the CPU.
This function builds a HOB for the CPU.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param SizeOfMemorySpace The maximum physical memory addressability of the processor.
@param SizeOfIoSpace The maximum physical I/O addressability of the processor.
**/
VOID
EFIAPI
BuildCpuHob (
IN UINT8 SizeOfMemorySpace,
IN UINT8 SizeOfIoSpace
)
{
EFI_HOB_CPU *Hob;
Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU));
Hob->SizeOfMemorySpace = SizeOfMemorySpace;
Hob->SizeOfIoSpace = SizeOfIoSpace;
//
// Zero the reserved space to match HOB spec
//
ZeroMem (Hob->Reserved, sizeof (Hob->Reserved));
}
/**
Builds a HOB for the Stack.
This function builds a HOB for the stack.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param BaseAddress The 64 bit physical address of the Stack.
@param Length The length of the stack in bytes.
**/
VOID
EFIAPI
BuildStackHob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_HOB_MEMORY_ALLOCATION_STACK *Hob;
ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
((Length & (EFI_PAGE_SIZE - 1)) == 0));
Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK));
CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid);
Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
Hob->AllocDescriptor.MemoryLength = Length;
Hob->AllocDescriptor.MemoryType = EfiBootServicesData;
//
// Zero the reserved space to match HOB spec
//
ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
}
/**
Update the Stack Hob if the stack has been moved
@param BaseAddress The 64 bit physical address of the Stack.
@param Length The length of the stack in bytes.
**/
VOID
UpdateStackHob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_PEI_HOB_POINTERS Hob;
Hob.Raw = GetHobList ();
while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
//
// Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
// to be reclaimed by DXE core.
//
BuildMemoryAllocationHob (
Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
EfiConventionalMemory
);
//
// Update the BSP Stack Hob to reflect the new stack info.
//
Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
break;
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
}
/**
Builds a HOB for the memory allocation.
This function builds a HOB for the memory allocation.
It can only be invoked during PEI phase;
for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase.
If there is no additional space for HOB creation, then ASSERT().
@param BaseAddress The 64 bit physical address of the memory.
@param Length The length of the memory allocation in bytes.
@param MemoryType Type of memory allocated by this HOB.
**/
VOID
EFIAPI
BuildMemoryAllocationHob (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN EFI_MEMORY_TYPE MemoryType
)
{
EFI_HOB_MEMORY_ALLOCATION *Hob;
ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) &&
((Length & (EFI_PAGE_SIZE - 1)) == 0));
Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION));
ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID));
Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
Hob->AllocDescriptor.MemoryLength = Length;
Hob->AllocDescriptor.MemoryType = MemoryType;
//
// Zero the reserved space to match HOB spec
//
ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved));
}

View File

@@ -0,0 +1,160 @@
/** @file
Implementation of the 6 PEI Ffs (FV) APIs in library form.
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
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 <PrePi.h>
/**
Allocates one or more 4KB pages of type EfiBootServicesData.
Allocates the number of 4KB pages of MemoryType and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
returned.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePages (
IN UINTN Pages
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_PHYSICAL_ADDRESS Offset;
Hob.Raw = GetHobList ();
// Check to see if on 4k boundary
Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF;
if (Offset != 0) {
// If not aligned, make the allocation aligned.
Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset;
}
//
// Verify that there is sufficient memory to satisfy the allocation
//
if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < Hob.HandoffInformationTable->EfiFreeMemoryBottom) {
return 0;
} else {
//
// Update the PHIT to reflect the memory usage
//
Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;
// This routine used to create a memory allocation HOB a la PEI, but that's not
// necessary for us.
return (VOID *)(UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop;
}
}
/**
Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
returned. If there is not enough memory at the specified alignment remaining to satisfy the
request, then NULL is returned.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
@param Pages The number of 4 KB pages to allocate.
@param Alignment The requested alignment of the allocation. Must be a power of two.
If Alignment is zero, then byte alignment is used.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment
)
{
VOID *Memory;
UINTN AlignmentMask;
//
// Alignment must be a power of two or zero.
//
ASSERT ((Alignment & (Alignment - 1)) == 0);
if (Pages == 0) {
return NULL;
}
//
// Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
//
ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment)));
//
// We would rather waste some memory to save PEI code size.
//
Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment));
if (Alignment == 0) {
AlignmentMask = Alignment;
} else {
AlignmentMask = Alignment - 1;
}
return (VOID *) (UINTN) (((UINTN) Memory + AlignmentMask) & ~AlignmentMask);
}
/**
Allocates a buffer of type EfiBootServicesData.
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
@param AllocationSize The number of bytes to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePool (
IN UINTN AllocationSize
)
{
EFI_HOB_MEMORY_POOL *Hob;
Hob = GetHobList ();
//
// Verify that there is sufficient memory to satisfy the allocation
//
if (AllocationSize > 0x10000) {
// Please call AllcoatePages for big allocations
return 0;
} else {
Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_TYPE_MEMORY_POOL) + AllocationSize));
return (VOID *)(Hob + 1);
}
}

View File

@@ -0,0 +1,44 @@
/** @file
Library that helps implement monolithic PEI (i.e. PEI part of SEC)
Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
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.
**/
#ifndef _PI_PEI_H_
#define _PI_PEI_H_
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/PrePiLib.h>
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiDecompressLib.h>
#include <Library/PeCoffLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Guid/MemoryAllocationHob.h>
#define GET_HOB_TYPE(Hob) ((Hob).Header->HobType)
#define GET_HOB_LENGTH(Hob) ((Hob).Header->HobLength)
#define GET_NEXT_HOB(Hob) ((Hob).Raw + GET_HOB_LENGTH (Hob))
#define END_OF_HOB_LIST(Hob) (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_END_OF_HOB_LIST)
//
// Get the data and data size field of GUID
//
#define GET_GUID_HOB_DATA(GuidHob) ((VOID *) (((UINT8 *) &((GuidHob)->Name)) + sizeof (EFI_GUID)))
#define GET_GUID_HOB_DATA_SIZE(GuidHob) (((GuidHob)->Header).HobLength - sizeof (EFI_HOB_GUID_TYPE))
#endif

View File

@@ -0,0 +1,231 @@
/** @file
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
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 <PrePi.h>
//
// Hack to work in NT32
//
EFI_STATUS
EFIAPI
SecWinNtPeiLoadFile (
IN VOID *Pe32Data,
IN EFI_PHYSICAL_ADDRESS *ImageAddress,
IN UINT64 *ImageSize,
IN EFI_PHYSICAL_ADDRESS *EntryPoint
);
EFI_STATUS
EFIAPI
LoadPeCoffImage (
IN VOID *PeCoffImage,
OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
OUT UINT64 *ImageSize,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint
)
{
RETURN_STATUS Status;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
VOID *Buffer;
ZeroMem (&ImageContext, sizeof (ImageContext));
ImageContext.Handle = PeCoffImage;
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
Status = PeCoffLoaderGetImageInfo (&ImageContext);
ASSERT_EFI_ERROR (Status);
//
// Allocate Memory for the image
//
Buffer = AllocatePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize));
ASSERT (Buffer != 0);
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
//
// Load the image to our new buffer
//
Status = PeCoffLoaderLoadImage (&ImageContext);
ASSERT_EFI_ERROR (Status);
//
// Relocate the image in our new buffer
//
Status = PeCoffLoaderRelocateImage (&ImageContext);
ASSERT_EFI_ERROR (Status);
*ImageAddress = ImageContext.ImageAddress;
*ImageSize = ImageContext.ImageSize;
*EntryPoint = ImageContext.EntryPoint;
//
// Flush not needed for all architectures. We could have a processor specific
// function in this library that does the no-op if needed.
//
InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize);
return Status;
}
typedef
VOID
(EFIAPI *DXE_CORE_ENTRY_POINT) (
IN VOID *HobStart
);
EFI_STATUS
EFIAPI
LoadDxeCoreFromFfsFile (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN UINTN StackSize
)
{
EFI_STATUS Status;
VOID *PeCoffImage;
EFI_PHYSICAL_ADDRESS ImageAddress;
UINT64 ImageSize;
EFI_PHYSICAL_ADDRESS EntryPoint;
VOID *BaseOfStack;
VOID *TopOfStack;
VOID *Hob;
EFI_FV_FILE_INFO FvFileInfo;
Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage);
if (EFI_ERROR (Status)) {
return Status;
}
Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint);
// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint);
ASSERT_EFI_ERROR (Status);
//
// Extract the DxeCore GUID file name.
//
Status = FfsGetFileInfo (FileHandle, &FvFileInfo);
ASSERT_EFI_ERROR (Status);
BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint);
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint));
Hob = GetHobList ();
if (StackSize == 0) {
// User the current stack
((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob);
} else {
//
// Allocate 128KB for the Stack
//
BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize));
ASSERT (BaseOfStack != NULL);
//
// Compute the top of the stack we were allocated. Pre-allocate a UINTN
// for safety.
//
TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
//
// Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
//
UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize);
SwitchStack (
(SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint,
Hob,
NULL,
TopOfStack
);
}
// Should never get here as DXE Core does not return
DEBUG ((EFI_D_ERROR, "DxeCore returned\n"));
ASSERT (FALSE);
return EFI_DEVICE_ERROR;
}
EFI_STATUS
EFIAPI
LoadDxeCoreFromFv (
IN UINTN *FvInstance, OPTIONAL
IN UINTN StackSize
)
{
EFI_STATUS Status;
EFI_PEI_FV_HANDLE VolumeHandle;
EFI_PEI_FILE_HANDLE FileHandle = NULL;
if (FvInstance != NULL) {
//
// Caller passed in a specific FV to try, so only try that one
//
Status = FfsFindNextVolume (*FvInstance, &VolumeHandle);
if (!EFI_ERROR (Status)) {
Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
}
} else {
Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle);
}
if (!EFI_ERROR (Status)) {
return LoadDxeCoreFromFfsFile (FileHandle, StackSize);
}
return Status;
}
EFI_STATUS
EFIAPI
DecompressFirstFv (
VOID
)
{
EFI_STATUS Status;
EFI_PEI_FV_HANDLE VolumeHandle;
EFI_PEI_FILE_HANDLE FileHandle;
Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle);
if (!EFI_ERROR (Status)) {
Status = FfsProcessFvFile (FileHandle);
}
return Status;
}

View File

@@ -0,0 +1,90 @@
#%HEADER%
#/** @file
# Component description file for Apple Pre PI Library
#
# LIbrary helps you build a platform that skips PEI and loads DXE Core
# directly. Helps building HOBs, reading data from the FV, and doing
# decompression.
#
# Copyright (c) 2008, Apple, Inc.
#
# 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.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PrePiLib
FILE_GUID = 1F3A3278-82EB-4C0D-86F1-5BCDA5846CB2
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = PrePiLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources.common]
FwVol.c
Hob.c
Memory.c
PrePiLib.c
ReportStatusCode.c
[Packages]
MdePkg/MdePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec # needed to support StatusCodes
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec # needed to support StatusCodes
[LibraryClasses]
BaseLib
DebugLib
BaseMemoryLib
UefiDecompressLib
PeCoffLib
CacheMaintenanceLib
PrintLib
SerialPortLib
ExtractGuidedSectionLib
[Guids]
gEfiHobMemoryAllocModuleGuid
gEfiHobMemoryAllocStackGuid
gEfiStatusCodeSpecificDataGuid
gEfiMemoryTypeInformationGuid
gEfiStatusCodeDataTypeDebugGuid
[Protocols]
gEfiStatusCodeRuntimeProtocolGuid
[FixedPcd.common]
gEmbeddedTokenSpaceGuid.PcdPrePiHobBase
gEmbeddedTokenSpaceGuid.PcdPrePiTempMemorySize
gEmbeddedTokenSpaceGuid.PcdPrePiBfvBaseAddress
gEmbeddedTokenSpaceGuid.PcdPrePiBfvSize
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode
gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData
[FeaturePcd]
gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob

View File

@@ -0,0 +1,327 @@
/** @file
Library that helps implement monolithic PEI
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
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 <PrePi.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/SerialPortLib.h>
#include <Library/PrintLib.h>
#include <Protocol/StatusCode.h>
#include <Guid/StatusCodeDataTypeId.h>
#include <Guid/StatusCodeDataTypeDebug.h>
#include <FrameworkPei.h>
#define EFI_STATUS_CODE_DATA_MAX_SIZE 200
EFI_STATUS
EFIAPI
SerialReportStatusCode (
IN EFI_STATUS_CODE_TYPE CodeType,
IN EFI_STATUS_CODE_VALUE Value,
IN UINT32 Instance,
IN CONST EFI_GUID *CallerId,
IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
);
EFI_STATUS_CODE_PROTOCOL gStatusCode = {
(EFI_REPORT_STATUS_CODE)SerialReportStatusCode
};
/**
Extracts ASSERT() information from a status code structure.
Converts the status code specified by CodeType, Value, and Data to the ASSERT()
arguments specified by Filename, Description, and LineNumber. If CodeType is
an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
Filename, Description, and LineNumber from the optional data area of the
status code buffer specified by Data. The optional data area of Data contains
a Null-terminated ASCII string for the FileName, followed by a Null-terminated
ASCII string for the Description, followed by a 32-bit LineNumber. If the
ASSERT() information could be extracted from Data, then return TRUE.
Otherwise, FALSE is returned.
If Data is NULL, then ASSERT().
If Filename is NULL, then ASSERT().
If Description is NULL, then ASSERT().
If LineNumber is NULL, then ASSERT().
@param CodeType The type of status code being converted.
@param Value The status code value being converted.
@param Data Pointer to status code data buffer.
@param Filename Pointer to the source file name that generated the ASSERT().
@param Description Pointer to the description of the ASSERT().
@param LineNumber Pointer to source line number that generated the ASSERT().
@retval TRUE The status code specified by CodeType, Value, and Data was
converted ASSERT() arguments specified by Filename, Description,
and LineNumber.
@retval FALSE The status code specified by CodeType, Value, and Data could
not be converted to ASSERT() arguments.
**/
BOOLEAN
EFIAPI
ReportStatusCodeExtractAssertInfo (
IN EFI_STATUS_CODE_TYPE CodeType,
IN EFI_STATUS_CODE_VALUE Value,
IN CONST EFI_STATUS_CODE_DATA *Data,
OUT CHAR8 **Filename,
OUT CHAR8 **Description,
OUT UINT32 *LineNumber
)
{
EFI_DEBUG_ASSERT_DATA *AssertData;
ASSERT (Data != NULL);
ASSERT (Filename != NULL);
ASSERT (Description != NULL);
ASSERT (LineNumber != NULL);
if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
*Filename = (CHAR8 *)(AssertData + 1);
*Description = *Filename + AsciiStrLen (*Filename) + 1;
*LineNumber = AssertData->LineNumber;
return TRUE;
}
return FALSE;
}
/**
Extracts DEBUG() information from a status code structure.
Converts the status code specified by Data to the DEBUG() arguments specified
by ErrorLevel, Marker, and Format. If type GUID in Data is
EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
Format from the optional data area of the status code buffer specified by Data.
The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
the Format. If the DEBUG() information could be extracted from Data, then
return TRUE. Otherwise, FALSE is returned.
If Data is NULL, then ASSERT().
If ErrorLevel is NULL, then ASSERT().
If Marker is NULL, then ASSERT().
If Format is NULL, then ASSERT().
@param Data Pointer to status code data buffer.
@param ErrorLevel Pointer to error level mask for a debug message.
@param Marker Pointer to the variable argument list associated with Format.
@param Format Pointer to a Null-terminated ASCII format string of a
debug message.
@retval TRUE The status code specified by Data was converted DEBUG() arguments
specified by ErrorLevel, Marker, and Format.
@retval FALSE The status code specified by Data could not be converted to
DEBUG() arguments.
**/
BOOLEAN
EFIAPI
ReportStatusCodeExtractDebugInfo (
IN CONST EFI_STATUS_CODE_DATA *Data,
OUT UINT32 *ErrorLevel,
OUT BASE_LIST *Marker,
OUT CHAR8 **Format
)
{
EFI_DEBUG_INFO *DebugInfo;
ASSERT (Data != NULL);
ASSERT (ErrorLevel != NULL);
ASSERT (Marker != NULL);
ASSERT (Format != NULL);
//
// If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
//
if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
return FALSE;
}
//
// Retrieve the debug information from the status code record
//
DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
*ErrorLevel = DebugInfo->ErrorLevel;
//
// The first 12 * UINTN bytes of the string are really an
// argument stack to support varargs on the Format string.
//
*Marker = (BASE_LIST) (DebugInfo + 1);
*Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
return TRUE;
}
EFI_STATUS
EFIAPI
SerialReportStatusCode (
IN EFI_STATUS_CODE_TYPE CodeType,
IN EFI_STATUS_CODE_VALUE Value,
IN UINT32 Instance,
IN CONST EFI_GUID *CallerId,
IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
)
{
CHAR8 *Filename;
CHAR8 *Description;
CHAR8 *Format;
CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
UINT32 ErrorLevel;
UINT32 LineNumber;
UINTN CharCount;
BASE_LIST Marker;
EFI_DEBUG_INFO *DebugInfo;
Buffer[0] = '\0';
if (Data != NULL &&
ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
//
// Print ASSERT() information into output buffer.
//
CharCount = AsciiSPrint (
Buffer,
EFI_STATUS_CODE_DATA_MAX_SIZE,
"\n\rASSERT!: %a (%d): %a\n\r",
Filename,
LineNumber,
Description
);
//
// Callout to standard output.
//
SerialPortWrite ((UINT8 *)Buffer, CharCount);
return EFI_SUCCESS;
} else if (Data != NULL &&
ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
//
// Print DEBUG() information into output buffer.
//
CharCount = AsciiBSPrint (
Buffer,
EFI_STATUS_CODE_DATA_MAX_SIZE,
Format,
Marker
);
} else if (Data != NULL &&
CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) &&
(CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
//
// Print specific data into output buffer.
//
DebugInfo = (EFI_DEBUG_INFO *) (Data + 1);
Marker = (BASE_LIST) (DebugInfo + 1);
Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12);
CharCount = AsciiBSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker);
} else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
//
// Print ERROR information into output buffer.
//
CharCount = AsciiSPrint (
Buffer,
EFI_STATUS_CODE_DATA_MAX_SIZE,
"ERROR: C%x:V%x I%x",
CodeType,
Value,
Instance
);
//
// Make sure we don't try to print values that weren't intended to be printed, especially NULL GUID pointers.
//
if (CallerId != NULL) {
CharCount += AsciiSPrint (
&Buffer[CharCount - 1],
(EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
" %g",
CallerId
);
}
if (Data != NULL) {
CharCount += AsciiSPrint (
&Buffer[CharCount - 1],
(EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
" %x",
Data
);
}
CharCount += AsciiSPrint (
&Buffer[CharCount - 1],
(EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)),
"\n\r"
);
} else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
CharCount = AsciiSPrint (
Buffer,
EFI_STATUS_CODE_DATA_MAX_SIZE,
"PROGRESS CODE: V%x I%x\n\r",
Value,
Instance
);
} else {
CharCount = AsciiSPrint (
Buffer,
EFI_STATUS_CODE_DATA_MAX_SIZE,
"Undefined: C%x:V%x I%x\n\r",
CodeType,
Value,
Instance
);
}
SerialPortWrite ((UINT8 *)Buffer, CharCount);
return EFI_SUCCESS;
}
VOID
EFIAPI
AddDxeCoreReportStatusCodeCallback (
VOID
)
{
BuildGuidDataHob (&gEfiStatusCodeRuntimeProtocolGuid, &gStatusCode, sizeof(VOID *));
}