我正在使用 GNU GRUB 版本2.04的引導加載程式和 Linux 內核5.19-rc2
我正在除錯 Linux 內核初始化,并期望在內核啟動時 CPU 應該處于實模式。實際上如中所述Intel System Programming Manual, Chapter 2:
所有 Intel 64 和 IA-32 處理器在上電或復位后進入實地址模式(參見第 9 章,“處理器管理和初始化”)。然后軟體啟動從實地址模式到保護模式的切換。
所以我在第一個 Linux 內核函式 GRUB 呼叫(我相信它是secondary_startup_64在 x86-64 上)在 GDB 中設定斷點以在 QEMU 中除錯 Ubuntu 20.04。我希望PE和PG標志CR0被禁用,因為在實地址模式下沒有分頁和保護模式。但這是我得到的gdb:
Thread 2 hit Breakpoint 1, secondary_startup_64 () at arch/x86/kernel/head_64.S:147
147 call verify_cpu
(gdb) p $cr0
$1 = [ PG AM WP NE ET MP PE ]
可以看出PG,PE設定了標志,原因尚不清楚。我看到了兩種可能性:
- GRUB 本身將 CPU 轉移到保護模式并啟用分頁
secondary_startup_64不是 GRUB 呼叫的 Linux Kernel 的第一個函式,并且之前執行過 Kernel 代碼。如果是這樣,從 GRUB 到 Linux 內核的真正入口點是什么?
uj5u.com熱心網友回復:
“所有 Intel 64 和 IA-32 處理器在上電或復位后進入實地址模式”,然后韌體啟動(使用一個 CPU),然后它啟動所有其他 CPU,所有 CPU 都切換到受保護模式或長模式(連同初始化很多東西——記憶體、MTRR、ACPI 表……);并且除一個之外的所有 CPU 都重新進入睡眠狀態。
最終; 如果韌體是 BIOS,它會將 CPU 切換回實模式并啟動引導加載程式;如果韌體是 UEFI,它將使 CPU 處于長模式并啟動引導加載程式。無論哪種方式,GRUB 都會啟動。
如果韌體是 BIOS,則 GRUB 將 CPU 切換到保護模式(然后在每次想要使用 BIOS 功能時將其從保護模式切換到實模式并回傳到保護模式);做很多事情;發現它正在加載 64 位 Linux 內核并切換到長模式。如果韌體是 UEFI,它只會一直處于長模式。請注意,GRUB 的代碼大多是 32 位代碼;保護模式和長模式都允許你運行 32 位代碼;所以大部分 GRUB 的代碼都適用于保護模式和長模式。
甚至更晚;在韌體和 GRUB 完成大量作業之后,并且可能在 CPU 的模式更改了幾千次之后;GRUB 將控制權交給 Linux。
現在... Linux 有幾個不同的入口點,引導加載程式使用最適合它的入口點。這種情況偶爾會發生變化——例如,非常舊版本的 Linux 內置了一個軟盤引導加載程式(他們稍后就擺脫了),而現代版本的 Linux 可以內置一個 UEFI 引導加載程式。還有一個實模式入口點和一個保護模式入口點(較舊)和一個 64 位入口點(較新)。如果韌體是 BIOS,這些 GRUB 可能只使用 32 位入口點,如果韌體是 UEFI,則使用 64 位入口點。
大多數這些入口點(不包括 UEFI 引導加載程式入口點)作為一個鏈作業 - 例如,如果使用實模式入口點,它會切換到保護模式并跳轉到 32 位入口點;如果使用 32 位入口點,它會設定分頁和長模式并跳轉到 64 位入口點。
您的斷點位于/接近 64 位入口點;因此,無論引導加載程式使用哪個入口點(32 位或 64 位),您都會開始查看 64 位代碼。64位代碼需要長模式,長模式需要分頁;所以必須設定PG和PE。
當然(對于 64 位入口點)可能會配置分頁,以便所有物理地址都映射到相同的虛擬地址,因此即使啟用了分頁,它實際上也不會做任何事情。內核的 64 位啟動代碼會改變分頁的配置方式(將內核映射到內核空間等)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/495916.html
