EFI基本概念之HOB
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
#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了。