-
Pre-EFI Phase
- PEI Overview
Pre-EFI Initialization (PEI) 是Platform Initialization的第二個Phase定義在Platform Initialization Specification, Ver 1.2.1, Volume 1。
所有的machine restart event都會invoke PEI Phase。PEI執行的階段只有on-processor的資源可以使用, 例如以processor cache當作call stack然後來執行Pre-EFI Initialization(PEIM)。PEI主要可以分成6個任務如下:
- Reset
PEI consumes Reset, INIT 和 Machine Check Architecture( MCA)。以Itaium來說,reset會call Processor abstraction layer(PAL) 然後call進 firmware。
- Start-up
PEI是在rom裡面執行的,因此有非常的小的start-up code。Modular的driver都是absolutly address的。
- Support
為了要提供DXE phase以C的環境執行,PEI必須建立暫時的memory以供C使用stack。
- Modules
PEI core locate、validates和dispatch 執行PEI modules(PEIM),這些module是用來初始化platform的feature或chipset。
- Publish
PEI藉由PEIM to PEIM Interface (PPI)來 溝通。
- Goals
PEI主要的目的是Discover boot mode,Launch modules that initialize main memory Discovery & launch DXE core。
而上面提到的PEIM負責了主要四個項目:
- 初始化永久記憶體。
- 在Hand-Off Blocks中寫入memory的資訊。
- 在Hand-Off Blocks中 描述firmware volume的location。
- 將control 轉移給DXE Phase。
下圖說明了PEI Phase的操作流程,當進入PEI之後,首先會 初始化PEIM的dispatcher,接著執行各個PEIM直到最後一個PEIM存在DXE IPL將control及HOBs 轉移給DXE Phase。
HOBs是唯一pass給DXE Phase的資料結構。由於 PEI負責了recovery及S3 resume,PEI Phase必須要越小越好,複雜的運算或演算法應該放到DXE階段執行(這樣開機才會快)。
為什麼我們需要PEI呢?原因是:
- 寫不使用memory的程式是非常困難的。
- Porting的困難。以assembly來說,某部分的code vendorA使用EBP另外一個vendor 使用EBX,修改起來會比C來的費力。
- 在開發一個feature的時候,我們基本上都會希望可以使用memory以及有基本的chipset被初始化。並且,PEI也負責了S3 (resume )的部分。
下面我們將深入的介紹PEI Phase。
- PEI Foundation
- PEI Foundation Introduction
PEI Foundation 是PEI的entity負責了主要四個項目:
- Dispatch PEIMs
- 維護boot mode
- 初始化永久記憶體
- Invoke DXE loader
PEI Foundation 包含了SEC 和 Pre-EFI( PEI)被設計成一個很小的一個片段,在SEC結束後,PEI最開始的code是一段platform-specific的machine code, 這也是porting會遭遇的困難。因此,這也是為什麼要讓PEI foundation的code越小越好(事情盡量以C來做,比較好移植)。
- PEI Prerequisites
在進入PEI Phase之前要滿足兩個條件:
- Processor execution mode。
- 可以access 存在PEI Foundation的Boot Firmware Volume(BFV)。
SEC將control交出的對象就是PEI Foundation。而放置PEI Foundation的Firmware Volume(FV)就稱為Boot Firmware Volume。PEIM可能會放在一般FV或是BFV,但是有些特殊的PEIM必須要放在BFV來提供其他PEIM的location。
- PEI Foundation Entry Point
SEC call進PEI Foundation時包含了下列資訊:
- A set of PPIs
- Size and location of the the Boot Firmware Volume (BFV)
- Size and location of the temporary RAM
- Size and location of the temporary RAM available for use by the PEI Foundation
- Size and location of the stack
在SPEC裡面是強制規定SEC一定要將這些資訊放到stack中來invoke PEI Foundation。
- PEI Calling Convention Processor Binding
下面將簡述 processor-specific mechanisms 去取得指向PEI Service Table的指標。(EFI_PEI_SERVICES**)
- X86
EFI_PEI_SERVICES**
放在 4 bytes immediately preceding the Interrupt Descriptor Table,取得的方法如下。
IDTR32 STRUCT
Limit DW 1 DUP (?)
BaseAddress DD 1 DUP (?)
IDTR32 ENDS
sub esp, SIZEOF IDTR32
sidt FWORD PTR ss:[esp]
mov eax, [esp].IDTR32.BaseAddress
mov eax, DWORD PTR [eax – 4]
add esp, SIZEOF IDTR32
- X64
x64的系統則是放在8 bytes immediately preceding the Interrupt Descriptor Table,取得的方法如下。
IDTR64 STRUCT
Limit DW 1 DUP (?)
BaseAddress DQ 1 DUP (?)
IDTR64 ENDS
sub rsp, SIZEOF IDTR64
sidt [rsp]
mov rax, [rsp].IDTR64.BaseAddress
mov rax, QWORD PTR [rax – 8]
add rsp, SIZEOF IDTR64
- ARM
如果是ARM Processor Family processors的話,
EFI_PEI_SERVICES**
是放在 TPIDRURW read/write Software Thread ID register defined in the ARMv7-A Architectural Reference Manual.
CpuReadTPIDRURW:
MRC p15, 0, r0, c13, c0, 2
bx lr
EFI_PEI_SERVICES **
GetPeiServicesTablePointer (
VOID
)
{
return (EFI_PEI_SERVICES **)(UINTN)CpuReadTPIDRURW ();
}
- Memory
PEI core需要一段暫時的memory,大小會depends on CPU和chipset,以IA32為例就是8K了。IA32使用 Cache As Ram(CAR)的技術來提供暫用的memory。方法是將cache設定成no eviction mode。 下圖是PEI initial的memory map。主要分成幾個部分:
- BFV
BFV全名是Boot Firmware Volume,BFV是存放PEI core的地方,同時也是recovery block。
- FV
FV全名是Firmware Volume,定義在 Firmware Storage, vol.3。FV有可能是0到多個。
- T-RAM
T-RAM就是temporary memory。在初始化memory 之前存放stack, data的地方。
- PEI Core
PEI core 負責dispatching PEIMs 及提供基本的services 如下圖 PEI core 的主要function如下:
- *SecCoreData 存放著例如T-RAM的大小及位置、stack的地方和BFV的地方。
- *PpiList 記錄著要由PEI core initial的PPI description的list。如果這個list是空的則會存放一個結束的tag:EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
- *Data 則是指向舊的PEI core,如果是NULL則代表第一次進入。
下圖說明了在系統reset或power-on之後到準備進入DXE的流程
- PEI Service
PEI Foundation會建立一個所有PEIM都可以看到的system table叫
PEI Service Table
。 PEI Service有可能被定義成 function、command 或capability manifested。 也因為PEI階段直到最後面才會有memory可以使用,因此相對於後面phase的service,PEI service可以做的事情就相對比較少了。
在build time的時候,PEI Foundation的位置和建立的temporary ram是不可知的,因此指向PEI 的pointer會傳進每一個PEIM的entry point 及PEIM-to-PEIM Interface (PPI)。
PEI Foundation提供了下列七種service。
- PPI Service
PEIM to PEIM Interface是用來讓PEIM之間做溝通,這個interface存放在T-RAM中。PPI service提供了四種function: InstallPpi()、ReinstallPpi()、LocatePpi() 、NotifyPpi()
- Boot Mode Service
管理系統的boot mode( S3, S5, normal boot, diagnostics, etc.)。
- HOB Service
Hand-Off Blocks的簡稱,用來將資料傳到下一個phase(DXE)
- Firmware Volume Service
在Firmware File System (FFS)中找尋PEIMs及其他的firmware files。 FfsFindNextVolume() 、FfsFindNextFile()、FfsFindSectionData()
- PEI Memory Service
管理permanent memory在被discovered之前/後的memory操作。InstallPeiMemory()、AllocatePages()、AllocatePool()、CopyMem()、SetMem()
- Status Code Service
提供common progress/error code 的reporting 服務。一般來說是for debug用的。
- Reset Service
Initiate warm or cold restart of the system
- PEI Modules(PEIMs)
- PEI Modules
PEIM是一個unit 的code and/or data用來初始化平台、processor。他抽象化了domain-specific logic相似於DXE Driver。 一個platform所擁有的PEIMs可能包含了以下幾種:
- Platform-specific PEIMs
- Processor-specific PEIMs
- Chipset-specific PEIMs
- PEI CIS–prescribed architectural PEIMs
- Miscellaneous PEIMs
- PEIM Structure
每一個PEIM包存在一個檔案中,包含了:
- Standard header
- Execute-in-place code/data section
- Optional relocation information
- Authentication information, if present
PEIM binary image 可以從存放的FV執行或是在永久記憶體被初始化後shadow過去的compressed component中執行。 PEIM可執行的section可能是position-dependent 或 position-independent code. 如果是position-dependent code, relocation information must be provided in the PEIM image to allow FV store software to relocate the image to a different location than it is compiled. 下圖是PEIM的layout,有些是必要的有些則是optional的。
PEIM binary可以是XIP(execute in place)(沒有壓縮的)或是在memary初始化後copy到ram執行(壓縮的binary)。這類的position dependent code 因為base address及entry point已經改變了,因此必須作相對應的修改。
- PPI Interface
PEIM使用 PEIM to PEIM Interface(PPI)來與彼此溝通,而PEIM執行的過程中也有可能會去invoke其他的PEIM靠的就是PPI。PPI包含在
EFI_PEI_PPI_DESCRIPTOR
要使用PPI必須要透過LocatePpi()來查詢。 要提供PPI則使用InstallPpi()來讓別人使用。我們藉由PPI database來access PPI,這個database 包含了所有的PPI。如同剛剛提到的,我們可以藉由LocatePpi(), NotifyPpi(), 及ReinstallPpi()來access這個 database。
Architecture PPI
Additional PPI
。
- Architecture PPI的GUID是global的。這類的PPI提供給PEI foundation作為common interface來使用。 而這類的 PPI也會根據不同的platform來實作,例如ReportStatusCode()。
- Additional PPI相較於 Architecture PPI 只會被PEI Foundation使用而不是給其他的PEIMs使用, Additional PPI 定義了兩種PPI可以給其他PEIMs使用。
- Required PPIs
CPU I/O PPI 、PCI Configuration PPI 、 Stall PPI、 PEI Variable Services
- Optional PPIs
Security (SEC) Platform Information PPI
- PEI Dispatcher
PEIM Dispatcher是一個state machine實作在PEI Foundation裡。他的工作是將control依序地交給PEIM。PEI Dispatcher會檢查Firmware Volume中檔案型態
EFI_FV_FILETYPE_PEIM
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
依照他的相依性或參考priori file(optional的file,事先定義好PEIM的順序)來決定何時dispatch 這個PEIM。
- PEI HOBs and Memory
- HOBs
HOB是一連串的data structure在PEI階段所建立的。HOB描述platform的feature、設定或資料。在DXE phase,HOB是read only的。以下分開介紹幾個HOB的角色。
- Bridge HOB是PEI跟DXE的溝通橋樑。
- Self-Discribing HOB定義在PI的SPEC.也定義了他的attribute及length.
- Allocated HOB是alloct在block的heap, 是一塊連續的記憶體。
- Snapshot HOB裡面指向的PEIM定義的physical的值例如FVs, Physical memory properties在DXE是不可以更改的。
- Memory PEI建立HOB並存在system memory供DXE使用。
- Hand-Off Block (HOB) List
在PEI中,DXE IPL PPI會將HOB list pass給DXE Foundation。而這個list必須要至少包含以下7種HOB。
- PEI Hand-off Information Table(PHIT):指向HOB List
- 一個或多個描述physical system memory的Resource Descriptor HOB(s)
- Boot-Strap Processor (BSP)stack HOB:告訴DXE現在的stack location
- BSPStore(Backing Store Pointer Store) HOB: Itanium only
- 一個或多個描述firmware devices的Resource Descriptor HOB(s)
- 一個或多個Firmware Volume HOB(s)
- Memory Allocation Module HOB:DXE會將他放到GCD
- Pre-permanent Memory Environment
下面分幾個部分介紹PEI Pre-permanent Memory Environment:
- Purpose: 初始化 system memory
- Discovery: Discovery boot type。例如resuming from state, recovery, or normal boot
- Environment: 到這個階段還沒有system memory可以用。因此使用CPU的cache來放置data及stack,模擬出C可以執行的環境。
- Model: Run在32 bit的protected mode
- Input: aware of the location of the firmware volumes and the PEI service table
- Post-permanent Memory Environment
下面一樣分幾個部分介紹PEI Post-permanent Memory Environment:
- Purpose: Transition 到DXE, 準備HOBs
- Discovery: 擁有stack及HOB list
- Environment: 擁有system memory, XIP from firmware volume
- Model: Run在32 bit的protected mode
- Input: 建立指向第一個HOB的pointer, 也就是PHIT(PEI Hand-Off Information Table)
- PEI Memory Map Sample
下圖是PEI Memory Map的範例,也就是"可能"的長相。
首先,在PEI過程中,我們可能會populate HOBs, 同時,PHIT會指向第一個HOB。PHIT也會記錄著PeiMemoryBottom, PeiFreeMemoryBottom, PeiFreeMemoryTop, PeiMemoryTop。PeiMemoryTop跟PeiFreeMemoryTop之間是fixed memory,也就是DXE不可修改的位置。PeiFreeMemory是供DXE去使用的memory space。
- Transition To DXE
- PEI Transition To DXE
總結一下PEI從啟動到移轉給DXE的過程
- 一開始的PEI phase是沒有system memory可以使用的。
- PEI core dispatch PEIMs,在這個階段初始化CPU, Chipset等等裝置並將結果記錄在HOB List中
- 在DXE Initial Program Load(IPL) PEIM被執行的時候,HOBs List就存在了
- DXE IPL將 control傳給DXE core。當傳遞完成後,所有的PEI phase的services及PPI將無法再access。唯一傳遞給DXE的只有HOB list
- DXE Initial Program Load(IPL)
IPL有很多目的如下:
- 禁止所有的hard coded的address
- 尋找最大的physical memory HOB,一般來說置於memory的top
- 將stack allocate到memory的top
- 尋找HOB LIST的firmware volume給DXE core
- 將DXE core load到memory
- switch stack(從T-RAM轉到system memory)然後轉移到DXE
- Sample Code
- Call to DXE IPL
- PEI Transition
- Alternative Boot Path
- Alternative Boot Path
事實上,PEI並非每次開機都會跳到DXE。PEI有可能根據boot mode的不同改變boot path。PEIM可以使用SetBootMode()來改變boot mode。
- 資料來源:http://clhjoe.blogspot.tw/2012/05/uefipi-3-securitysec-and-pre-efi-phase.html
|