1 基本概念及用法
HOB是Hand-offblock的缩写。是PEI阶段向DXE传递系统信息的手段。PEI阶段构建一些HOB结构,然后将其作为参数传给DXE阶段函数,DXE Core会根据其使用平台相关资源。
HOB是系列的连续的内存结构体,可以认为其由三部分构成:第一部分,是PHIT头,它描述了HOB的起始地址以及总的内存使用;第二部分是各个Hob列表,DXE阶段会根据这一部分获取上关资源;第三部分是结束部分。
1.1 PHIT头:
typedef struct {
EFI_HOB_GENERIC_HEADER Header;
UINT32 Version;
EFI_BOOT_MODE BootMode;
EFI_PHYSICAL_ADDRESS EfiMemoryTop;
EFI_PHYSICAL_ADDRESS EfiMemoryBottom;
EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop;
EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom;
EFI_PHYSICAL_ADDRESS EfiEndOfHobList;
} EFI_HOB_HANDOFF_INFO_TABLE;
1.2 HOB列表中的一个
typedef struct {
EFI_HOB_GENERIC_HEADER Header;
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
} EFI_HOB_MEMORY_ALLOCATION;
1.3 EFI_HOB_GENERIC_HEADER
typedef struct {
UINT16 HobType;
UINT16 HobLength;
UINT32 Reserved;
} EFI_HOB_GENERIC_HEADER;
每一个HOB,都有一个HEADER,来指示该HOB的类型。包括PHIT头,也会有HEADER。下面来看一下HOB定义的类型有哪些:
#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_UNUSED 0xFFFE
#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
我是从UDK2014上拷贝出来的,不知道最新的PI SPEC有没有增加。当然如果规范没定义,也可以根据需要自己定义,因为自已是生产者自己也是消费者。
2. HOB相关函数
2.1创建HOB
EFI_STATUS
EFIAPI
PeiCreateHob (
IN CONSTEFI_PEI_SERVICES **PeiServices,
IN UINT16 Type,
IN UINT16 Length,
IN OUT VOID **Hob
)
{
Step1. 获取HOB列表的首地址,即PHIT头。
Step2. 确定是否有足够的空间建立该HOB。
Step3. 找到结束标志的HOB,将其改写成该HOB类型。并将结束标志的HOB移至该HOB下方。
Step4. 更新PHITHOB。
}
在创建该HOB后,我们就可以将该HOB的实际数据填至相应区域内。
2.2 获取HobList首地址
EFI_STATUS
EFIAPI
PeiGetHobList (
IN CONSTEFI_PEI_SERVICES **PeiServices,
IN OUT VOID **HobList
)
{
Step1. 如果用来接收HOB的HobList为空,返回非法。
Step2. 由参数PeiSerivces得到PEI Core实例,进而获得HobList首地址。
}
2.3 DXE阶段使用HOB
HOB的真正使用是在DXE阶段,当然PEI阶段也可以使用,但代码中并没有那么用。DXE阶段使用HOB时,必须先解析其结构。具体如下:
2.3.1 获取HOBList首地址
VOID *
EFIAPI
GetHobList (
VOID
)
{
ASSERT (mHobList!= NULL);
return mHobList;
}
2.3.2 获取给定类型的HOB
VOID *
EFIAPI
GetFirstHob (
IN UINT16 Type
)
{
VOID *HobList;
HobList =GetHobList ();
return GetNextHob(Type, HobList);
}
其中GetNextHob()会根据HOB类型,返回其第一个匹配的HOB。
2.3.3 GetNextHob()获取类型匹配的HOB
VOID *
EFIAPI
GetNextHob (
IN UINT16 Type,
IN CONSTVOID *HobStart
)
{
Step1. HobStart不准为空。
Step2. 将HobStart作为地址,赋值给Hob。
Step3. 判断其是否是HOB的结尾,如果是,则没找到。否则进入Step4。
Step4. 比较该HOB类型是不是和找的类型一致,如果一致,则将其返回。否则进入Step5。Step5. 找到紧邻该HOB的下一个HOB,继续Step3。
}
2.3.4 GET_NEXT_HOB的用法
在2.3.3中,想找到某HOB的下一个HOB,则需要计算当前HOB大小,并且跳过该HOB。这就需要用到GET_NEXT_HOB宏定义。
#define GET_NEXT_HOB(HobStart) \
(VOID *)(*(UINT8**)&(HobStart) + GET_HOB_LENGTH (HobStart))
而GET_HOB_LENTGH的原型为
#define GET_HOB_LENGTH(HobStart) \
((*(EFI_HOB_GENERIC_HEADER **)&(HobStart))->HobLength)
所以检索HOB最重要的一个字段是Header的HobLength字段。有了它,我们就可以正确地检索每一个HOB了。