2011年10月21日 星期五

Boot Manager

Boot Manager會按照定義在Global NVRAM Variable的順序去Load UEFI Driver以及UEFI Application (包括UEFI OS Boot Loader). BIOS必須要使用Global NVRAM Variable裡面的Boot Order去boot. BIOS可以在Boot Order List裡面加入Boot Option或是移除Boot Option. 如果在Boot的過程中有發現一些條件成立的話, BIOS可以在Boot Manager裡面實作Add的功能.
UEFI的Boot順序如下:
1. Boot Order List可以從Global NVRAM Variable讀出. 如果修改此Variable的話, 那麼只能Reset之後才會有作用. Boot Order List會定義一串NVRAM Variable, 每個NVRAM Variable包含了Load的資訊. 每個NVRAM Variable定義了Boot Option的名稱, 可以顯示給User.
2. NVRAM Variable也包含了指標指到Hardware Device以及Hardware Device的File, 此File包含了UEFI image可以被Load.
3. NVRAM Variable可能還包含OS分割區以及目錄.
NVRAM Variable也可以包含Load Option, 直接載入UEFI Image. BIOS並不會知道Load Option會包甚麼東西. 高階的軟體可以寫到Global NVRAM Variable去設定BIOS boot的行為.

3.1 Firmware Boot Manager
Boot Manager會負責決定甚麼東西該載入, 並且和User互動來決定該做甚麼事.

3.1.1 Boot Manager Programming
透過SetVariable()可以修改Load Option Variable. 每個Load Option Entry會存在在Boot#### Variable或Driver#### Variable. ####是唯一的Option Number, 以十六進制表示(0000~FFFF). Load Option會依照Option Number的順序排列. DriverOrder放Driver####, BootOrder放Boot####. 例如, 若要加入一個新的Boot Option, 那麼新的Boot####就會被加入. 接著新的Boot####的Option Number也會加到BootOrder Variable裡面, 此時BootOrder會被重寫.

3.1.2 Load Option Processing
Boot Manager必須要呼叫LoadImage(), 需支援最新的EFI_SIMPLE_FILE_SYSTEM_PROTOCOL以及EFI_LOAD_FILE_PROTOCOL來處理Load Option. 如果LoadImage()成功的話, Boot Manager需要再呼叫StartImage()之前, 透過SetWatchdogTimer()把WatchDog Timer叫起來. 如果Boot Image無法透過LoadImage()載入的話, 那麼Boot Manager就需要去檢查Default Application去Boot. 搜尋Default Application去Boot會發生在Removable以及Fixed Media之間.

3.1.3 Load Options
每個Load Option Variable包含了一個EFI_LOAD_OPTION. 可以透過SetVariable()去建立一個Load Option. 當建立了一個新的Load Option, 所有未定義的參數都需要設為0. 如果Load Option是LOAD_OPTION_ACTIVE的話, Boot Manager會利用Load Option的Device Path去嘗試Boot.

3.4.1.2 Non-removable Media Boot Behavior
在Non-emovable Media的裝置上, 通常會使用"目錄"以及"檔案"來表示FilePath, 讓Platform可以根據此FilePath去達到Boot的動作. 然而BootOrder Variable裡面只有Boot####可以參考, 而且Boot####並無法表示Boot Device的Time Out, 或是指定的檔案是否存在, 或是Boot Variable是否有效, 我們需要有一個預設的行為來處理這些情況的發生.
這個預設的行為包含了讓Boot Manager搜尋Non-removable Media是否有支援EFI_SIMPLE_FILE_SYSTEM_PROTOCOL或是EFI_BLOCK_IO_PROTOCOL. 一般而言Boot Manager會去搜尋所有的媒體裝置, 然而Platform的策略應該會去限制, 只搜尋連接在系統的裝置. 可以選擇這樣的限制來實作.
如果Device的EFI系統分區上有支援EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的話, 那麼BIOS就會去試著從這個EFI系統分區上去Boot, Boot的方式是去執行\EFI\BOOT\BOOTxxx.EFI.
如果Device不支援EFI_SIMPLE_FILE_SYSTEM_PROTOCOL但是有支援EFI_BLOCK_IO_PROTOCOL的話, 那麼就必須要呼叫EFI Boot Service ConnectController去Connect這個Device, 其中DriverImageHandle需要設為NULL, RemainingDevicePath的Recursive flag設為TRUE. BIOS就會試著去Boot此Device的Child.

2011年9月23日 星期五

Boot Menu

1. 在Driver.c中的DxeMain(), 首先會去Locate三個Protocol, 分別是EFI_HII_CONFIG_ROUTING_PROTOCOL, EFI_HII_DATABASE_PROTOCOL以及EFI_FORM_BROWSER2_PROTOCOL.

2. 找到gST->ConsoleInHandle的EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.

3. 檢查BootMenu的Protocol是否已安裝, 如果還未安裝, 表示正在Post階段, Setup還沒初始化, 這時候需要先註冊Event, 等EFI_HII_PLATFORM_SETUP_FORMSET安裝後, 再呼叫BmInitSetupMenu(), 註冊完之後順便安裝BootMenu的Protocol.

4.1. (XP版)在SetupBootMenu.c中, BmInitSetupMenu()首先會透過BmLoadBootOptions()去載入所有Boot Option. 接著呼叫BmInitSetupMenuStrings()以及BmInitSetupMenuForm(). 最後透過HiiLibCreatePackageListDriverHandle()建立HII Driver Handle, 透過HiiLibCreatePackageListFromPackages()建立HII Package List.

4.2. (MB3版)在BootIii.c中, BmInitSetupMenu()首先會透過CreateHiiDriverHandle()建立HII Driver Handle. 接著呼叫PreparePackageList()以及NewPackageList()去安裝VFR Form. 接著Locate SCT_BDS_SERVICES_PROTOCOL. 透過Protocol呼叫GetBootList().
4.2.1. BootManager會先InitializeLoadOptions(), Load Option又可分成兩種, 一種是Boot, 另一種是Driver.

5. 如果Setup Menu的Boot Page沒有被執行, 那麼BootManager就會來執行BmInitMenu().

6. 在Menu.c中, BmInitMenu()首先會執行BootMenu.c的BmInitBootMenu()去初始化Boot Menu畫面的設定值. BmInitMenu()也會執行AppMenu.c的BmInitAppMenu()去初始化App Menu畫面的設定值. 接著透過BootOption.c的BmLoadBootOptions()去Load所有Boot Option. 接著執行BmInitAppMenu()和BmLoadAppOptions(). 最後透過HiiLibCreatePackageListDriverHandle()建立HII Driver Handle, 透過HiiLibCreatePackageListFromPackages()建立HII Package List (這段Code類似SetupBootMenu的部分, 但在這裡只有安裝String而已, 沒有安裝Form.

6.1 當BootOption.c執行BmLoadBootOption()時, 會透過BDS_SERVICES_PROTOCOL->GetBootList()去取得Boot List的起點.

7. 最後透過BmDrawMenu()去畫BootMenu. 用BmInteractMenu()去接受Keyboard按下的鍵來做反應.