/** @file
Copyright (c) 2024, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
EFI_RESOURCE_ATTRIBUTE_TESTED | \
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
EFI_RESOURCE_ATTRIBUTE_TESTED )
extern VOID *mHobList;
/**
Add a new HOB to the HOB List.
@param HobType Type of the new HOB.
@param HobLength Length of the new HOB to allocate.
@return NULL if there is no space to create a hob.
@return The address point to the new created hob.
**/
VOID *
EFIAPI
CreateHob (
IN UINT16 HobType,
IN UINT16 HobLength
);
/**
Build a Handoff Information Table HOB
This function initialize a HOB region from EfiMemoryBegin to
EfiMemoryTop. And EfiFreeMemoryBottom and EfiFreeMemoryTop should
be inside the HOB region.
@param[in] EfiMemoryBottom Total memory start address
@param[in] EfiMemoryTop Total memory end address.
@param[in] EfiFreeMemoryBottom Free memory start address
@param[in] EfiFreeMemoryTop Free memory end address.
@return The pointer to the handoff HOB table.
**/
EFI_HOB_HANDOFF_INFO_TABLE *
EFIAPI
HobConstructor (
IN VOID *EfiMemoryBottom,
IN VOID *EfiMemoryTop,
IN VOID *EfiFreeMemoryBottom,
IN VOID *EfiFreeMemoryTop
);
/**
Build ACPI board info HOB using infomation from ACPI table
@param AcpiTableBase ACPI table start address in memory
@retval A pointer to ACPI board HOB ACPI_BOARD_INFO. Null if build HOB failure.
**/
ACPI_BOARD_INFO *
BuildHobFromAcpi (
IN UINT64 AcpiTableBase
);
/**
*
Add HOB into HOB list
@param[in] Hob The HOB to be added into the HOB list.
**/
VOID
AddNewHob (
IN EFI_PEI_HOB_POINTERS *Hob
)
{
EFI_PEI_HOB_POINTERS NewHob;
if (Hob->Raw == NULL) {
return;
}
NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength);
if (NewHob.Header != NULL) {
CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
}
}
/**
Found the Resource Descriptor HOB that contains a range (Base, Top)
@param[in] HobList Hob start address
@param[in] Base Memory start address
@param[in] Top Memory end address.
@retval The pointer to the Resource Descriptor HOB.
**/
EFI_HOB_RESOURCE_DESCRIPTOR *
FindResourceDescriptorByRange (
IN VOID *HobList,
IN EFI_PHYSICAL_ADDRESS Base,
IN EFI_PHYSICAL_ADDRESS Top
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
//
// Skip all HOBs except Resource Descriptor HOBs
//
if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
continue;
}
//
// Skip Resource Descriptor HOBs that do not describe tested system memory
//
ResourceHob = Hob.ResourceDescriptor;
if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
continue;
}
if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
continue;
}
//
// Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
//
if (Base < ResourceHob->PhysicalStart) {
continue;
}
if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
continue;
}
return ResourceHob;
}
return NULL;
}
/**
Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
@param[in] HobList Hob start address
@param[in] MinimalNeededSize Minimal needed size.
@param[in] ExceptResourceHob Ignore this Resource Descriptor.
@retval The pointer to the Resource Descriptor HOB.
**/
EFI_HOB_RESOURCE_DESCRIPTOR *
FindAnotherHighestBelow4GResourceDescriptor (
IN VOID *HobList,
IN UINTN MinimalNeededSize,
IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;
ReturnResourceHob = NULL;
for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
//
// Skip all HOBs except Resource Descriptor HOBs
//
if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
continue;
}
//
// Skip Resource Descriptor HOBs that do not describe tested system memory
//
ResourceHob = Hob.ResourceDescriptor;
if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
continue;
}
if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
continue;
}
//
// Skip if the Resource Descriptor HOB equals to ExceptResourceHob
//
if (ResourceHob == ExceptResourceHob) {
continue;
}
//
// Skip Resource Descriptor HOBs that are beyond 4G
//
if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
continue;
}
//
// Skip Resource Descriptor HOBs that are too small
//
if (ResourceHob->ResourceLength < MinimalNeededSize) {
continue;
}
//
// Return the topest Resource Descriptor
//
if (ReturnResourceHob == NULL) {
ReturnResourceHob = ResourceHob;
} else {
if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
ReturnResourceHob = ResourceHob;
}
}
}
return ReturnResourceHob;
}
/**
Check the HOB and decide if it is need inside Payload
Payload maintainer may make decision which HOB is need or needn't
Then add the check logic in the function.
@param[in] Hob The HOB to check
@retval TRUE If HOB is need inside Payload
@retval FALSE If HOB is needn't inside Payload
**/
BOOLEAN
IsHobNeed (
EFI_PEI_HOB_POINTERS Hob
)
{
if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
return FALSE;
}
if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
return FALSE;
}
}
// Arrive here mean the HOB is need
return TRUE;
}