引導(dǎo)過程:EFI 和 iBoot
引導(dǎo)過程指的是從就計算機(jī)通電那一瞬間到CPU開始執(zhí)行操作系統(tǒng)代碼時的整個過程,這個過程往往是系統(tǒng)啟動過程中被忽視的一部分。在這個非常初期的階段中等孵,CPU 執(zhí)行標(biāo)準(zhǔn)的啟動代碼窘疮。這部分代碼需要對硬件設(shè)備進(jìn)行探測,尋找最有可能啟動的操作系統(tǒng)并且根據(jù)用戶定義的參數(shù)啟動這個操作系統(tǒng)逐抑。其他的操作系統(tǒng)用的默認(rèn)(通用)的引導(dǎo)加載器(boot loader),而OS X 和 iOS 使用的則是自己的引導(dǎo)加載器杏死,引導(dǎo)加載器工作在預(yù)期的(preboot)固件環(huán)境中泵肄。
傳統(tǒng)形式的引導(dǎo):BIOS
大部分PC采用的是BIOS,用來加載一些基本的自舉(bootstrap)代碼給CPU 執(zhí)行淑翼。BIOS 有很大的局限性腐巢,無可擴(kuò)展性可言,還和MBR 分區(qū)方案緊密耦合玄括。
EFI
正因為BIOS 的局限性冯丙,蘋果采用了一種更新的32位/64位兼容的標(biāo)準(zhǔn):可擴(kuò)展固件接口(Extensible Fireware Interface,EFI)遭京。和BIOS 相比胃惜,EFI 是一個全功能的運行時系統(tǒng),在引導(dǎo)期間提供了更為強(qiáng)大的接口哪雕,設(shè)置在之后的運行時也提供了接口船殉。
EFI 程序其實是一個二進(jìn)制程序,只不過二進(jìn)制程序采用的是 便攜式可執(zhí)行(Portable Executable斯嚎,PE)格式利虫。EFI 二進(jìn)制程序都實現(xiàn)了這樣的原型:
typedef EFI_STATUS (EFIAPI *EFI_IMAGE_ENTRY_POINT) (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE SystemTable);
這個原型是說挨厚,EFI 二進(jìn)制程序從 EFI環(huán)境接受兩個參數(shù):
- EFI句柄:引用鏡像自己,通過這個句柄可以從運行時查詢各種詳細(xì)信息
- EFI系統(tǒng)表:指向主表(master table)的指針糠惫,從這個表中可以獲得所有EFI 標(biāo)準(zhǔn)的句柄和運行時API指針
NVRAM 變量
NVRAM 是固件接口中一個非常強(qiáng)大的功能疫剃,而且這顯然是傳統(tǒng)BIOS 沒有的功能。NVRAM 變量和 shell 變量的語義是一樣的硼讽,都是環(huán)境變量的功能巢价,但是NVRAM 是在系統(tǒng)范圍內(nèi)存在的,操作系統(tǒng)和固件本身都可以訪問固阁。
一般來說壤躲,NVRAM 變量可以分為以下幾個類別:
- 引導(dǎo)相關(guān)的變量:用于指定要引導(dǎo)的內(nèi)核和根文件系統(tǒng),還負(fù)責(zé)向內(nèi)核傳遞參數(shù)
- 固件內(nèi)部變量:固件使用的變量备燃,一般被操作系統(tǒng)忽略
- 臨時變量:根據(jù)需要設(shè)置或清空柒爵,通常在重新引導(dǎo)的時候不會停留
boot.efi 的執(zhí)行流程
- 獲得EFI 服務(wù)指針,查詢CPUID
- initialConsole
- Lion 特有的初始化操作
- InitDevice Tree
- 為內(nèi)核調(diào)用門分配內(nèi)存
- 一些其他的初始化操作赚爵,如InitMemoryConfig.InitSupportedCPUTypes等函數(shù)
- 檢查休眠恢復(fù)
- 處理引導(dǎo)時的按鍵
- Lion:確認(rèn)CPU支持64位模式
- Lion:檢查Core Storage
- SetConsoleMode
- DrawBootGraphics
- LoadKernelCache
- InitBootStruct
- LoadDrivers
- LoadRamDisk
- StopAnimation
- FinalizeBootStruct
- 跳轉(zhuǎn)到內(nèi)核入口點
引導(dǎo)內(nèi)核
在加載了 kernelcahce 或內(nèi)核本身之后,boot.efi 退出引導(dǎo)服務(wù)法瑟,將控制權(quán)轉(zhuǎn)交給內(nèi)核冀膝。內(nèi)核被傳入一個參數(shù),一個包含BootStruct 的頁面霎挟,這個數(shù)據(jù)結(jié)構(gòu)在boot.efi 的最后階段完成填寫窝剖,內(nèi)核可以通過這個數(shù)據(jù)結(jié)構(gòu)提取出所需要的所有0數(shù)據(jù)。
內(nèi)核對 EFI 的回調(diào)
EFI 的職責(zé)是加載內(nèi)核酥夭。但是內(nèi)核仍然可以和 EFI 接口赐纱,從而使用 EFI 提供的運行時服務(wù)。
- efi_init( ):這個函數(shù)從內(nèi)核的引導(dǎo)參數(shù)中獲得 EFI 運行時服務(wù)熬北,這個函數(shù)會調(diào)用下一個函數(shù)
- efi_set_tables_[32|64](EFI_SYSTEM_TABLE)*:這個函數(shù)有32位和64位兩個版本疙描,接受員工指向EFI 系統(tǒng)表的指針作為參數(shù),計算器簽名和CRC讶隐,然后獲得運行時服務(wù)的指針起胰,將這個指針保存在全局變量gPEEFIRunTimesServices中
- *hibernate_newruntime_map(void map, vm_size_t map_size, unit32t system_table_offset):系統(tǒng)從休眠中喚醒的時候通過這個函數(shù)重新初始化運行時服務(wù)表
Mach 核心很少使用EFI, 而BSD 更是對 EFI 毫不知情。 而在 I/O Kit 中巫延,大量使用EFI(及設(shè)備樹)效五。
Boot Camp
蘋果的EFI 實現(xiàn)的另一個重要的特性是Boot Camp。Boot Camp 是蘋果雙重引導(dǎo)的解決方案炉峰,這個解決方案允許在Mac 上運行非蘋果的操作系統(tǒng)(主要是Windows)畏妖。由于蘋果使用私有的硬件并且使用了 EFI,而Windows仍然使用落后的BIOS疼阔,因此蘋果在Boot Camp中提供完整的驅(qū)動程序包 戒劫,并且修改了boot.efi支持多系統(tǒng)引導(dǎo)半夷。
bless( )
對于機(jī)器上的固件,OS X 提供的非常有限的訪問能力谱仪,出了nvram( ) 命令外玻熙,提供的唯一能接觸固件的工具就是bless( ),這個工具是一個控制和修改系統(tǒng)引導(dǎo)參數(shù)的工具疯攒,實際上是定義系統(tǒng)引導(dǎo)的位置和方向嗦随。這個工具支持6種模式,如下表:
模式 | 用途 |
---|---|
Folder | 將制定的目錄設(shè)置為系統(tǒng)目錄 |
Mount | 指定一個文件系統(tǒng)而不是目錄作為引導(dǎo)卷敬尺。文件系統(tǒng)參數(shù)是已掛載的文件系統(tǒng)枚尼,因此是一個名字 |
Device | 通過/dev 表示的設(shè)備指定一個卷,這時設(shè)備中的文件系統(tǒng)還沒有掛載 |
NetBoot | 設(shè)置引導(dǎo)的網(wǎng)絡(luò)服務(wù)器砂吞,使用-server bsdp://[interface@]a.b.c.d參數(shù)署恍,其中a.b.c.d 表示服務(wù)器的地址,interface 是可選項蜻直,在多 home 的系統(tǒng)中表示本地接口盯质。BSDP 是蘋果的“BootStrap Discovery Protocol” 是對 DHCPv4的一個擴(kuò)展,在蘋果之外沒有其他方法使用或?qū)崿F(xiàn)這個協(xié)議 |
Unbless | 撤銷某個文件夾概而、掛載點呼巷、設(shè)備或網(wǎng)絡(luò)引導(dǎo)的“bless” |
Indo | 僅顯示信息 |
iOS 和 iBoot
蘋果的i 系列設(shè)備都不支持 EFI, 其引導(dǎo)過程是蘋果自創(chuàng)的赎瑰。是通過iOS 特有的引導(dǎo)加載器iBoot王悍。引導(dǎo)過程分多個階段,如下圖所示: