typedef EFI_STATUS (EFIAPI *EFI_PEIM_ENTRY_POINT)( IN EFI_FFS_FILE_HEADER * FfsHeader, IN EFI_PEI_SERVICES **PeiServices );
比較常用到的幾個函數:
(**PeiServices).LocatePpi這個函數要注意的就是 PEI Phase 下 PPI 的存放和 DXE 下存放 PROTOCOL 略有不同,因為 PEI FOUNDATION 會用來存放 PPI DB,所以很有可能一個 DB 裡 N 個 INSTANCE,第三個參數就是讓你選第幾個 INSTANCE 用的,第一個為 0,以此類推。
Status = (**PeiServices).CreateHob ( PeiServices, EFI_HOB_TYPE_XXX, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + PrivateDataSize), (VOID**) &HobBuffer );
這個函數要注意的地方就是 CreateHOB 他只幫你弄個 HEADER 出來,要塞 HOB 資料,要自己拉空間出來,算好 OFFSET 是要件。
函數成功的話,HobBuffer 就會指一塊空間出來給你。
(**PeiServices).CopyMem ( (VOID*)(((UINT8*) HobBuffer) + sizeof (EFI_HOB_GUID_TYPE)), (VOID*) PrivateData, (UINTN) PrivateDataSize );
再來也是算 OFFSET 把資料 COPY 進去,就行了。
DXE Phase 下:
EFI_HOB_HANDOFF_INFORMATION_TABLE *HobList; LibGetSystemConfigurationTable (&gEfiHobListGuid, (VOID**) &HobList);
藉此取得 HOBLIST,然後再用想對應的函數把你要的 HOB 拉出來就行了,如果我上面 HOB 的 TYPE 是 EFI_HOB_TYPE_GUID_EXTENSION,同時這個 HOB.Name 有加以指定一個 GUID,那我在 DXE Phase 下就能使用下列函數把 HOB 倒出來:
GetNextGuidHob ((VOID**) &HobList, &HobNameGuid, (VOID**) &HobContent, &BufferSize);
關於為什麼 PEI Service Table 要做成雙指標,在 BIOSREN 論壇 srcore 兄做了很漂亮的解釋,這邊借轉載並改成台灣用語:
『這個問題細究起來有點意思。這裡頭有歷史原因,其實依現在看來,定義成直接指標就可以了。』
『PEI 階段中,在 Main Memory 可用之前,PEI Core 和 PEIM 都必須在 flash 上 XIP。XIP 就意味著全域變數只能讀,不能寫。所以PEI Core在 memory 可用並且把自己 Shadow 到 memory 之前,是不可以用全域變數保存自己在 Stack 中分配的 PrivateData 的位址的。』
『這就是說我們必須有一種方法能讓 PEI CORE 在 PEIM 調用 PEI Service 的時候,能從傳進來的指向 PEI Serivces Table 的間接指標得到 PEI CORE 自己私有資料的位址。』
『當初,規範定義 EFI_PEI_SERVICES ** 是期望如下的 PEI CORE 的實現:舉例說明』
typedef struct { ... EFI_PEI_SERVICES *PS, ... } PEI_CORE_DATA;
『PEI_CORE_DATA 在 Stack 上分配,PS 域被初始化為 PEI Core 資料段中 PEI Service Table 的指標。』
『&PEI_CORE_DATA.PS 不就是EFI_PEI_SERVICES ** 嗎?通過 CR 就可能得到 Stack 上 PEI_CORE_DATA 的地址。』
『注意,這裡有個前提,就是 PEI Service Table 中所有域的值都是固定的,作為一個 PEI Core 的全域變數存放在資料段中。』
『對,這就是定義 EFI_PEI_SERVICES ** 的由來。』
『有人會問,如果PEI CORE按照如下實現:』
typedef struct { ... EFI_PEI_SERVICES PSTable, ... } PEI_CORE_DATA;
『就是說在 PEI Core 的 PrivateData 中定義一份 PEI Service Table 而不是指向它的指標,PEI Core 在初始化的時候將自己資料段中 PEI Service Table 作為範本拷到 PEI_CORE_DATA.PSTable 中。』
『這樣,就只用定義 EFI_PEI_SERVICES * (即 &PEI_CORE_DATA.PSTable)就可以了。確實如此,但規範仍然定義 EFI_PEI_SERVICES **,是考慮到 PEI Service Table 是固定的,可以直接放在 flash 上 PEI Core image 的資料段裡,PEI CORE 私有資料裡有一個指標指向它就可以了,這樣可以省掉一些對 temporary memory 的佔用,畢竟 temporary memory 的資源還是比較寶貴的。』
『瞭解了它的最初的設計意圖,那為什麼說回過頭來看,其實定義成直接指標就可以了?』
『因為 PEI CIS 規範的修訂使得 PEI Service Table 裡面的值不再是 build time 決定之後就不變的了。PEI CIS 0.91 在 PEI Service Table 加入了 CPU IO PPI 和 PCI CFG PPI 的指標。這兩個指標必須在執行時填入,所以 PEI Service Table 不能再放在 flash 上了,它必須被放到 memory 裡,這樣它才能被修改。』
『所以現在PEI CORE的實現一般是這樣:』
typedef struct { ... EFI_PEI_SERVICES *PS, ... ... EFI_PEI_SERVICES PSTable, ... } PEI_CORE_DATA;
『PEI Core 在初始化的時候將自己資料段中 PEI Service Table 作為模組拷到 PEI_CORE_DATA.PSTable 中,然後 PEI_CORE_DATA.PS = &PEI_CORE_DATA.PSTable。』
媽呀~!真是看的一頭霧水!
回覆刪除才剛踏進這行不久,沒有一個很好的學習方向!
只有看了硬體相關架構,自己看Spec又無法很好的理解彼此的關係!想和Code一起看又更慘= ="...
整個都已經不知道該怎辦了..囧!
多問,多筆記。到了一個階段,你會完全沒辦法問人,那時候早期的知識就很重要。
回覆刪除這一行考驗的就是探索的能力
BIOS真是門學問。。。
回覆刪除