综述
HOB的全称是Hand-Off Block,从名字上也可以看出来,它表示的是一种用于交接的数据。按照HOB的使用情况,可以将BIOS的启动阶段分为两个部分:
- HOB生成阶段(HOB producer phase),用来创建和修改HOB;
- HOB消费阶段(HOB consumer phase),用来使用HOB,注意此阶段HOB是只读的。
而这里说的“交接”就是从HOB生成阶段像HOB消费阶段交接数据,至于交接的是什么数据,后面会一一介绍。
本文参考《PI_Spec_1_7_A_final_May1.pdf》(后面统称为PI规范),该手册为了将x86的Platform Initialization扩展到更多的平台,已经不再直接使用PEI、DXE等阶段说明HOB的使用情况,不过对于x86架构的BIOS来说,HOB生成阶段其实就是SEC和PEI阶段,而HOB消费阶段就是DXE和BDS阶段。为了方便,本文还是直接使用PEI、DXE等术语。术语的对应关系如下表所示:
Term Used in the HOB Specification | Term Used in Other PI Specifications |
---|---|
HOB producer phase | PEI phase |
HOB consumer phase | DXE phase |
executable content in the HOB producer phase | Pre-EFI Initialization Module (PEIM) |
hand-off into the HOB consumer phase | DXE Initial Program Load (IPL) PEIM or DXE IPL PEIM-to-PEIM Interface (PPI) |
platform boot-policy phase | Boot Device Selection (BDS) phase |
注意,虽然上表中只有PEI和DXE,但是从实际的情况来看,SEC和BDS也分别可以作为HOB生成阶段和HOB消费阶段。
HOB的构成
HOB在PEI阶段创建,并返回一个列表(称为HOB List,HOB列表),其中的HOB一个个堆叠放置,最终构成如下的形式:
根据HOB中包含的数据的不同可以对HOB进行分类,且HOB列表的第一个必须要是PHIT HOB。PHIT的全称是Phase Handoff Information Table,它是第一个被创建的HOB,对应的指针在PEI的核心数据中:
///
/// Union of all the possible HOB Types.
///
typedef union {
EFI_HOB_GENERIC_HEADER *Header;
EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
EFI_HOB_MEMORY_ALLOCATION *MemoryAllocation;
EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore;
EFI_HOB_MEMORY_ALLOCATION_STACK *MemoryAllocationStack;
EFI_HOB_MEMORY_ALLOCATION_MODULE *MemoryAllocationModule;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;
EFI_HOB_GUID_TYPE *Guid;
EFI_HOB_FIRMWARE_VOLUME *FirmwareVolume;
EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2;
EFI_HOB_FIRMWARE_VOLUME3 *FirmwareVolume3;
EFI_HOB_CPU *Cpu;
EFI_HOB_MEMORY_POOL *Pool;
EFI_HOB_UEFI_CAPSULE *Capsule;
UINT8 *Raw;
} EFI_PEI_HOB_POINTERS;
///
/// Forward declaration for PEI_CORE_INSTANCE
///
typedef struct _PEI_CORE_INSTANCE PEI_CORE_INSTANCE;
///
/// Pei Core private data structure instance
///
struct _PEI_CORE_INSTANCE {
UINTN Signature;
///
/// Point to ServiceTableShadow
///
EFI_PEI_SERVICES *Ps;
PEI_PPI_DATABASE PpiData;
/// 其它略。下面就是指向第一个HOB的指针,EFI_PEI_HOB_POINTERS是一个Union,包括各种指针:
EFI_PEI_HOB_POINTERS HobList;
}
后面的HOB操作接口都是以这里为基础的,比如EFI_PEI_SERVICES
中就有接口GetHobList()
,其实现:
///
/// Pei Core Instance Data Macros
///
#define PEI_CORE_INSTANCE_FROM_PS_THIS(a) \
CR(a, PEI_CORE_INSTANCE, Ps, PEI_CORE_HANDLE_SIGNATURE)
EFI_STATUS
EFIAPI
PeiGetHobList (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN OUT VOID **HobList
)
{
PEI_CORE_INSTANCE *PrivateData;
//
// Only check this parameter in debug mode
//
DEBUG_CODE_BEGIN ();
if (HobList == NULL) {
return EFI_INVALID_PARAMETER;
}
DEBUG_CODE_END ();
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
*HobList = PrivateData->HobList.Raw;
return EFI_SUCCESS;
}
创建PHIT HOB的大致流程如下(不同的平台可能会有不同):
在PeiCoreBuildHobHandoffInfoTable()
函数中有PHIT HOB的初始化:
EFI_STATUS
PeiCoreBuildHobHandoffInfoTable (
IN EFI_BOOT_MODE BootMode,
IN EFI_PHYSICAL_ADDRESS MemoryBegin,
IN UINT64 MemoryLength
)
{
EFI_HOB_HANDOFF_INFO_TABLE *Hob;
EFI_HOB_GENERIC_HEADER *HobEnd;
Hob = (VOID *)(UINTN)MemoryBegin;
HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1);
Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF;
Hob->Header.HobLength = (UINT16)sizeof (EFI_HOB_HANDOFF_INFO_TABLE);
Hob->Header.Reserved = 0;
HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST;
HobEnd->HobLength = (UINT16)sizeof (EFI_HOB_GENERIC_HEADER);
HobEnd->Reserved = 0;
Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION;
Hob->BootMode = BootMode;
Hob->EfiMemoryTop = MemoryBegin + MemoryLength;
Hob->EfiMemoryBottom = MemoryBegin;
Hob->EfiFreeMemoryTop = MemoryBegin + MemoryLength;
Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd + 1);
Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd;
return EFI_SUCCESS;
}
这里的数据可以跟前面的图对应。有了第一个HOB,之后的HOB就在此基础之上堆叠,最终完成所有需要的HOB。下面介绍目前PI规范中定义的HOB分类。
HOB分类
当前PI规范定义的HOB有如下的几种类型:
每一个HOB都包含一个通用的结构:
///
/// Describes the format and size of the data inside the HOB.
/// All HOBs must contain this generic HOB header.
///
typedef struct {
///
/// Identifies the HOB data structure type.
///
UINT16 HobType;
///
/// The length in bytes of the HOB.
///
UINT16 HobLength;
///
/// This field must always be set to zero.
///
UINT32 Reserved;
} EFI_HOB_GENERIC_HEADER;
这里就指定了HOB的类型HobType
:
//
// HobType of EFI_HOB_GENERIC_HEADER.
//
#define EFI_HOB_TYPE_HANDOFF 0x0001
#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
#define EFI_HOB_TYPE_FV 0x0005
#define EFI_HOB_TYPE_CPU 0x0006
#define EFI_HOB_TYPE_MEMORY_POOL 0x0007
#define EFI_HOB_TYPE_FV2 0x0009
#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED 0x000A
#define EFI_HOB_TYPE_UEFI_CAPSULE 0x000B
#define EFI_HOB_TYPE_FV3 0x000C
#define EFI_HOB_TYPE_UNUSED 0xFFFE
#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
然后是HOB的长度HobLength
,通过它就可以知道下一个HOB的位置。
下面介绍一些常用的HOB。
PHIT HOB
前面已经介绍了PHIT HOB,它的结构体如下:
///
/// Contains general state information used by the HOB producer phase.
/// This HOB must be the first one in the HOB list.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_HANDOFF.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// The version number pertaining to the PHIT HOB definition.
/// This value is four bytes in length to provide an 8-byte aligned entry
/// when it is combined with the 4-byte BootMode.
///
UINT32 Version;
///
/// The system boot mode as determined during the HOB producer phase.
///
EFI_BOOT_MODE BootMode;
///
/// The highest address location of memory that is allocated for use by the HOB producer
/// phase. This address must be 4-KB aligned to meet page restrictions of UEFI.
///
EFI_PHYSICAL_ADDRESS EfiMemoryTop;
///
/// The lowest address location of memory that is allocated for use by the HOB producer phase.
///
EFI_PHYSICAL_ADDRESS EfiMemoryBottom;
///
/// The highest address location of free memory that is currently available
/// for use by the HOB producer phase.
///
EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop;
///
/// The lowest address location of free memory that is available for use by the HOB producer phase.
///
EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom;
///
/// The end of the HOB list.
///
EFI_PHYSICAL_ADDRESS EfiEndOfHobList;
} EFI_HOB_HANDOFF_INFO_TABLE;
里面主要有包含两个部分,一个用来描述启动模式,另一个用来描述HOB内存的分布,这个也已经在前文的图中说明。
Memory Allocation HOB
PHIT HOB之后是Memory Allocation HOB,它对应结构体:
///
/// Describes all memory ranges used during the HOB producer
/// phase that exist outside the HOB list. This HOB type
/// describes how memory is used, not the physical attributes of memory.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
/// various attributes of the logical memory allocation.
///
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
//
// Additional data pertaining to the "Name" Guid memory
// may go here.
//
} EFI_HOB_MEMORY_ALLOCATION;
EFI_HOB_MEMORY_ALLOCATION_HEADER
结构体的构成:
///
/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the
/// various attributes of the logical memory allocation. The type field will be used for
/// subsequent inclusion in the UEFI memory map.
///
typedef struct {
///
/// A GUID that defines the memory allocation region's type and purpose, as well as
/// other fields within the memory allocation HOB. This GUID is used to define the
/// additional data within the HOB that may be present for the memory allocation HOB.
/// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0
/// specification.
///
EFI_GUID Name;
///
/// The base address of memory allocated by this HOB. Type
/// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0
/// specification.
///
EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
///
/// The length in bytes of memory allocated by this HOB.
///
UINT64 MemoryLength;
///
/// Defines the type of memory allocated by this HOB. The memory type definition
/// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined
/// in AllocatePages() in the UEFI 2.0 specification.
///
EFI_MEMORY_TYPE MemoryType;
///
/// Padding for Itanium processor family
///
UINT8 Reserved[4];
} EFI_HOB_MEMORY_ALLOCATION_HEADER;
这里也有一个MemoryType
表示类型,这里指的是UEFI下的内存使用类型,比如存放Boot Service的代码和数据的内存类型,Runtime的代码和数据的内存类型,等等。它们有如下的可选值:
///
/// Enumeration of memory types introduced in UEFI.
///
typedef enum {
///
/// Not used.
///
EfiReservedMemoryType,
///
/// The code portions of a loaded application.
/// (Note that UEFI OS loaders are UEFI applications.)
///
EfiLoaderCode,
///
/// The data portions of a loaded application and the default data allocation
/// type used by an application to allocate pool memory.
///
EfiLoaderData,
///
/// The code portions of a loaded Boot Services Driver.
///
EfiBootServicesCode,
///
/// The data portions of a loaded Boot Serves Driver, and the default data
/// allocation type used by a Boot Services Driver to allocate pool memory.
///
EfiBootServicesData,
///
/// The code portions of a loaded Runtime Services Driver.
///
EfiRuntimeServicesCode,
///
/// The data portions of a loaded Runtime Services Driver and the default
/// data allocation type used by a Runtime Services Driver to allocate pool memory.
///
EfiRuntimeServicesData,
///
/// Free (unallocated) memory.
///
EfiConventionalMemory,
///
/// Memory in which errors have been detected.
///
EfiUnusableMemory,
///
/// Memory that holds the ACPI tables.
///
EfiACPIReclaimMemory,
///
/// Address space reserved for use by the firmware.
///
EfiACPIMemoryNVS,
///
/// Used by system firmware to request that a memory-mapped IO region
/// be mapped by the OS to a virtual address so it can be accessed by EFI runtime services.
///
EfiMemoryMappedIO,
///
/// System memory-mapped IO region that is used to translate memory
/// cycles to IO cycles by the processor.
///
EfiMemoryMappedIOPortSpace,
///
/// Address space reserved by the firmware for code that is part of the processor.
///
EfiPalCode,
///
/// A memory region that operates as EfiConventionalMemory,
/// however it happens to also support byte-addressable non-volatility.
///
EfiPersistentMemory,
///
/// A memory region that describes system memory that has not been accepted
/// by a corresponding call to the underlying isolation architecture.
///
EfiUnacceptedMemoryType,
EfiMaxMemoryType
} EFI_MEMORY_TYPE;
此外,还有几个特别的EFI_HOB_MEMORY_ALLOCATION
:
EFI_HOB_MEMORY_ALLOCATION_STACK
///
/// Describes the memory stack that is produced by the HOB producer
/// phase and upon which all post-memory-installed executable
/// content in the HOB producer phase is executing.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
/// various attributes of the logical memory allocation.
///
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
} EFI_HOB_MEMORY_ALLOCATION_STACK;
从名称可以看出来它描述的是BSP执行所需的堆对应内存,通过BuildStackHob()
创建,对应的流程:
函数实现的主要代码:
CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid);
Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress;
Hob->AllocDescriptor.MemoryLength = Length;
Hob->AllocDescriptor.MemoryType = EfiBootServicesData;
DXE阶段会进一步的使用该HOB。
EFI_HOB_MEMORY_ALLOCATION_BSP_STORE
///
/// Defines the location of the boot-strap
/// processor (BSP) BSPStore ("Backing Store Pointer Store").
/// This HOB is valid for the Itanium processor family only
/// register overflow store.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
/// various attributes of the logical memory allocation.
///
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE;
该HOB主要在Itanium平台的CPU上使用,这里就不再说明。
EFI_HOB_MEMORY_ALLOCATION_MODULE
///
/// Defines the location and entry point of the HOB consumer phase.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// An instance of the EFI_HOB_MEMORY_ALLOCATION_HEADER that describes the
/// various attributes of the logical memory allocation.
///
EFI_HOB_MEMORY_ALLOCATION_HEADER MemoryAllocationHeader;
///
/// The GUID specifying the values of the firmware file system name
/// that contains the HOB consumer phase component.
///
EFI_GUID ModuleName;
///
/// The address of the memory-mapped firmware volume
/// that contains the HOB consumer phase firmware file.
///
EFI_PHYSICAL_ADDRESS EntryPoint;
} EFI_HOB_MEMORY_ALLOCATION_MODULE;
它描述的其实是DXE入口,创建的流程:
对应的代码:
//
// Load the DXE Core from a Firmware Volume.
//
Instance = 0;
do {
Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **)&LoadFile);
//
// These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
//
ASSERT_EFI_ERROR (Status);
Status = LoadFile->LoadFile (
LoadFile,
FileHandle,
&DxeCoreAddress,
&DxeCoreSize,
&DxeCoreEntryPoint,
&AuthenticationState
);
} while (EFI_ERROR (Status));
//
// Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
//
Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
ASSERT_EFI_ERROR (Status);
//
// Add HOB for the DXE Core
//
BuildModuleHob (
&DxeCoreFileInfo.FileName,
DxeCoreAddress,
ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
DxeCoreEntryPoint
);
BuildModuleHob()
的核心代码:
CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid);
Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule;
Hob->MemoryAllocationHeader.MemoryLength = ModuleLength;
Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode;
可以看到代码其实就是从FV中获取DXE核心入口,并根据它的值创建HOB,根据它可以创建DXE核心的Image Hand了,对应的操作位于函数CoreInitializeImageServices()
:
// 获取EFI_HOB_MEMORY_ALLOCATION_MODULE这个HOB
DxeCoreHob.Raw = HobStart;
while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
//
// Find Dxe Core HOB
//
break;
}
DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
}
// 获取到DxeCoreEntryPoint
DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;
gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
// 安装Image Handle
Image = &mCorePrivateImage;
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
Image->ImageBasePage = DxeCoreImageBaseAddress;
Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));
Image->Tpl = gEfiCurrentTpl;
Image->Info.SystemTable = gDxeCoreST;
Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
Image->Info.ImageSize = DxeCoreImageLength;
//
// Install the protocol interfaces for this image
//
Status = CoreInstallProtocolInterface (
&Image->Handle,
&gEfiLoadedImageProtocolGuid,
EFI_NATIVE_INTERFACE,
&Image->Info
);
ASSERT_EFI_ERROR (Status);
Resource Descriptor HOB
该HOB定义物理内存的属性,其结构:
///
/// Describes the resource properties of all fixed,
/// nonrelocatable resource ranges found on the processor
/// host bus during the HOB producer phase.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// A GUID representing the owner of the resource. This GUID is used by HOB
/// consumer phase components to correlate device ownership of a resource.
///
EFI_GUID Owner;
///
/// The resource type enumeration as defined by EFI_RESOURCE_TYPE.
///
EFI_RESOURCE_TYPE ResourceType;
///
/// Resource attributes as defined by EFI_RESOURCE_ATTRIBUTE_TYPE.
///
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
///
/// The physical start address of the resource region.
///
EFI_PHYSICAL_ADDRESS PhysicalStart;
///
/// The number of bytes of the resource region.
///
UINT64 ResourceLength;
} EFI_HOB_RESOURCE_DESCRIPTOR;
这样的HOB一般有很多个,它们通过BuildResourceDescriptorHob()
函数创建:
/**
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));
ASSERT (Hob != NULL);
Hob->ResourceType = ResourceType;
Hob->ResourceAttribute = ResourceAttribute;
Hob->PhysicalStart = PhysicalStart;
Hob->ResourceLength = NumberOfBytes;
}
该HOB包含的类型:
//
// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR.
//
#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000
#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001
#define EFI_RESOURCE_IO 0x00000002
#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003
#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004
#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005
#define EFI_RESOURCE_IO_RESERVED 0x00000006
//
// BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED is defined for unaccepted memory.
// But this defitinion has not been officially in the PI spec. Base
// on the code-first we define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED at
// MdeModulePkg/Include/Pi/PrePiHob.h and update EFI_RESOURCE_MAX_MEMORY_TYPE
// to 8. After BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED is officially published
// in PI spec, we will re-visit here.
//
// #define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007
#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000008
包含的属性:
//
// These types can be ORed together as needed.
//
// The following attributes are used to describe settings
//
#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
//
// This is typically used as memory cacheability attribute today.
// NOTE: Since PI spec 1.4, please use EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED
// as Physical write protected attribute, and EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
// means Memory cacheability attribute: The memory supports being programmed with
// a writeprotected cacheable attribute.
//
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
#define EFI_RESOURCE_ATTRIBUTE_PERSISTENT 0x00800000
//
// The rest of the attributes are used to describe capabilities
//
#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE 0x00100000
//
// This is typically used as memory cacheability attribute today.
// NOTE: Since PI spec 1.4, please use EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE
// as Memory capability attribute: The memory supports being protected from processor
// writes, and EFI_RESOURCE_ATTRIBUTE_WRITE_PROTEC TABLE means Memory cacheability attribute:
// The memory supports being programmed with a writeprotected cacheable attribute.
//
#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE 0x00200000
#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE 0x00400000
#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE 0x01000000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED 0x00040000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00080000
//
// Physical memory relative reliability attribute. This
// memory provides higher reliability relative to other
// memory in the system. If all memory has the same
// reliability, then this bit is not used.
//
#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000
在内存初始化完成之后,会调用该接口来定义内存的属性,比如:
//
// Report first 640KB of memory
//
BuildResourceDescriptorHob (
EFI_RESOURCE_SYSTEM_MEMORY,
MEM_TESTED_ATTR,
(EFI_PHYSICAL_ADDRESS) (0),
(UINT64) (0xA0000)
);
//
// Report first 0A0000h - 0FFFFFh as RESERVED memory
//
BuildResourceDescriptorHob (
EFI_RESOURCE_MEMORY_RESERVED,
MEM_TESTED_ATTR,
(EFI_PHYSICAL_ADDRESS) (0xA0000),
(UINT64) (0x60000)
);
//
// Report first 0x100000 - FSP reserved memory as system memory
//
BuildResourceDescriptorHob (
EFI_RESOURCE_SYSTEM_MEMORY,
MEM_TESTED_ATTR,
(EFI_PHYSICAL_ADDRESS) (0x100000),
(UINT64) (PeiMemBase - 0x100000)
);
在DXE阶段会收集这些HOB并初始化GDC(Global Coherency Domain)映射表。
GUID Extension HOB
该HOB术语自定义类型,如果我们需要自己创建从PEI阶段到DXE阶段传递数据的HOB,就可以使用这种类型,这也是BIOS开发时最可能用到的HOB,其结构体:
///
/// Allows writers of executable content in the HOB producer phase to
/// maintain and manage HOBs with specific GUID.
///
typedef struct {
///
/// The HOB generic header. Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION.
///
EFI_HOB_GENERIC_HEADER Header;
///
/// A GUID that defines the contents of this HOB.
///
EFI_GUID Name;
//
// Guid specific data goes here
//
} EFI_HOB_GUID_TYPE;
它是一个不定长的结构体,Name
之后还可以有自定义的数据。这个的Name
是一个唯一的GUID,后续DXE阶段通过该GUID来找到自定义的数据。
下面是一个示例,首选是HOB的创建,它位于PEI阶段,对应代码模块BeniPkg\Pei\HobProvider\HobProvider.inf:
EFI_STATUS
EFIAPI
HobProviderEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
BENI_HOB_DATA *Hob = NULL;
UINT8 Index = 0;
DEBUG ((EFI_D_ERROR, "Creating HOB ...\n"));
Hob = BuildGuidHob (&gBeniHobGuid, sizeof (BENI_HOB_DATA));
if (NULL == Hob) {
DEBUG ((EFI_D_ERROR, "[%a][%d] BuildGuidHob failed.\n", __FUNCTION__, __LINE__));
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < BENI_HOB_DATA_LEN; Index++) {
Hob->Data[Index] = Index;
}
DEBUG ((EFI_D_ERROR, "Done\n"));
return EFI_SUCCESS;
}
然后在DXE阶段就可以使用,对应模块BeniPkg\Dxe\HobConsumer\HobConsumer.inf:
EFI_STATUS
EFIAPI
HobConsumerEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_PEI_HOB_POINTERS Hob;
UINTN Index = 0;
UINT8 *Data = NULL;
Hob.Raw = GetFirstGuidHob (&gBeniHobGuid);
if (NULL == Hob.Raw) {
DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, EFI_NOT_FOUND));
return EFI_NOT_FOUND;
}
Data = (UINT8 *)(GET_GUID_HOB_DATA (Hob.Raw));
DEBUG ((EFI_D_ERROR, "BENI Hob data:\n"));
for (Index = 0; Index < BENI_HOB_DATA_LEN; Index++) {
DEBUG ((EFI_D_ERROR, "0x%02x ", *(Data + Index)));
}
DEBUG ((EFI_D_ERROR, "\n"));
return EFI_SUCCESS;
}
End of HOB List
HOB列表的最后是一个End of HOB,它有特定了类型EFI_HOB_TYPE_END_OF_HOB_LIST
,在PHIT HOB中就有一个成员EfiEndOfHobList
指向它。
其它
还有跟FV、CPU、SMRAM相关的HOB,这里就不再介绍了,有兴趣的可以直接看PI手册。