SeaBIOS程式的各種入口點都在src/romlayout.S這個檔案中定義了,啟動包括了vCPU上電後開始執行的起點src/romlayout.S:reset_vector,該位置會被QEMU加載到vCPU實體空間的0xFFFFFFF0位置。該處的指令是一個跳轉指令,該指令會跳轉到src/romlayout.S:entry_post位置,然後判斷是否是系統resume,如果不是則跳轉到post.c:handle_post()函數處,開始POST(Power On Self Test)階段。
post.c:handle_post()主要執行如下操作:
- 初始化debug序列槽
- 将SeaBIOS程式拷貝到0xC0000 ~ 0x100000記憶體區域,并且将這段記憶體區域的屬性設定為可寫的。
- 檢測目前平台資訊,如使用的晶片組類型,記憶體大小等,建立相應的E820表表項,設定記憶體配置設定函數配置設定記憶體時從哪些記憶體區域擷取記憶體。
- 跳轉到maininit()函數
maininit()函數會對各種系統資源進行初始化,然後尋找可啟動的裝置,詳細步驟如下:
- 對系統的各種接口進行初始化,主要是軟體上的接口,沒怎麼動到其他硬體
- 對fw_cfg裝置進行初始化,該裝置是QEMU傳遞Firmware資訊給SeaBIOS的一個模拟裝置,SeaBIOS通過fw_cfg裝置可以擷取到SMBIOS、ACPI、E820表等資訊。
- 初始化中斷向量表
- 初始化BDA(BIOS Data Area)、EBDA(Extended BIOS Data Area)資料區,這兩個區域是BIOS标準中定義的,用于存放一些BIOS相關的資訊,并且有一些指定的用途。
- 配置平台硬體
- 配置平台DMA控制器
- 配置中斷控制器
- 配置PCI裝置,搜尋系統中的PCI裝置,并為各個PCI裝置配置設定I/O和Memory位址空間,讓系統能夠正确地通路PCI裝置,并配置相應的中斷。
- 配置好SMRAM的記憶體入口點,并将其隐藏起來
- 配置好MTRR(Memory Type Range Register)寄存器,即配置不同記憶體區間的記憶體屬性(從CPU的角度看)
- 給其他非BSP(Bootstrap Processor)CPU,即AP(Application Processor)發送IPI中斷,讓AP對其自身進行初始化。并等待其他AP執行完畢。
- 建立MP表,SMBIOS表和ACPI表
- 配置時鐘和定時器
- 選取系統的顯示卡,并執行其PCI Option ROM對顯示卡進行初始化,這步完成後,顯示器就被點亮了,并且可以開始顯示啟動過程
- 對各種外設進行初始化,如USB控制器,磁盤控制器,鍵鼠控制器等等,由于外設比較多,并且速度慢,是以在對這些裝置進行初始化的時候,SeaBIOS引入了Thread的概念(其實更應該叫做協程),讓多個裝置的初始化同時執行,并不是嚴格的并行執行,此時隻有一個CPU在執行,它在多個裝置的初始化程式中來回切換,確定不會在一個裝置的初始化中卡住很長時間
- 執行其他PCI裝置的Option ROM,初始化相應的PCI裝置
- 收集可啟動選項,并且調用0x19中斷,開始OS的啟動。
至此,SeaBIOS的執行過程已經大緻理清,其中還包含了很多細節沒有提到,想要了解其中的細節還需要看具體的代碼。
同時也歡迎關注同名微信公衆号“河馬虛拟化”第一時間擷取最新文章。