Linux內(nèi)核映像的組成

1. Setup.bin
在內(nèi)核初始化時(shí),需要一些信息,如顯示信息、內(nèi)存信息。這些信息由工作在實(shí)模式下的setup.bin通過(guò)bios獲取,保存在內(nèi)核中的變量boot_params,該變量是boot_pramas下的一個(gè)實(shí)例。
?
實(shí)模式:虛地址到實(shí)地址轉(zhuǎn)換:DS段寄存器左移4位與偏移地址相加,得到物理地址,最大尋址位是2的20次方,即1Mbyte??蓪ぶ菲渲械娜我獾刂?,所有指令都相當(dāng)于工作在特權(quán)級(jí),直接操作CPU的各種功能,沒(méi)有安全級(jí)別,沒(méi)有分頁(yè)功能,沒(méi)有虛擬地址的概念,只有物理地址。各種寄存器的位寬基本上是16位的(段寄存器為20位)。
保護(hù)模式:虛地址到實(shí)地址轉(zhuǎn)換經(jīng)過(guò)MMU(內(nèi)存管理單元),內(nèi)存管理采用段式+頁(yè)式的方式,最大尋址位2的32次方,即4G。操作系統(tǒng)工作在最高優(yōu)先級(jí)0上,應(yīng)用程序則運(yùn)行在較低優(yōu)先級(jí)。各種寄存器的位寬基本上都是32位的,但是可以兼容同名的16位寄存器,兼容實(shí)地址模式,即實(shí)地址模式的程序無(wú)需再編譯即可跑在保護(hù)模式下。
?
linux-4.4.153\arch\x86\include\uapi\asm\bootparam.h
linux-4.4.153\arch\x86\boot\video.c
store_video_mode調(diào)用函數(shù)intcall獲取顯示方面信息,保存在screen_info
intcall是調(diào)用bios中斷的封裝
0x10是bios提供的顯示服務(wù)的中斷號(hào)
查看/linux-4.4.153/arch/x86/boot/bioscall.s
al是低8位寄存器
比較寄存器%al的值和標(biāo)號(hào)3處所占用的1字節(jié)
相等則跳轉(zhuǎn)到標(biāo)號(hào)1
否則將寄存器%al的值復(fù)制到標(biāo)號(hào)3處的1個(gè)字節(jié)的空間
再跳轉(zhuǎn)到標(biāo)號(hào)1
????????隨著新的bios的標(biāo)準(zhǔn)出現(xiàn),尤其是efi的出現(xiàn),為了支持新標(biāo)準(zhǔn),出現(xiàn)新的32位啟動(dòng)協(xié)議。在新協(xié)議下,由bootloader實(shí)現(xiàn)收集這些信息,內(nèi)核啟動(dòng)不用運(yùn)行setup.bin,直接跳轉(zhuǎn)到內(nèi)核的保護(hù)模式。
????????setup.bin另一個(gè)重要的功能就是負(fù)責(zé)在內(nèi)核和bootloader之間傳遞信息。在加載內(nèi)核的時(shí)候,bootloader需要從setup.bin中獲取內(nèi)核是否可重定位、內(nèi)核對(duì)齊的要求、內(nèi)核建議的加載地址。所以在構(gòu)建映像的時(shí)候,內(nèi)核需要用到這些信息,setup.bin還不能被放棄。
2. 內(nèi)核非壓縮部分
????????內(nèi)核保護(hù)模式部分是經(jīng)過(guò)壓縮的,運(yùn)行前需要解壓縮。
????????內(nèi)核在構(gòu)建的時(shí)候壓縮了自己,解壓縮的時(shí)候也要由內(nèi)核自己完成
????????內(nèi)核在壓縮鏡像外圍添加一些非壓縮代碼,bootloader在加載內(nèi)核映像的時(shí)候跳轉(zhuǎn)至非壓縮部分。這些指令直接送給cpu,負(fù)責(zé)解壓內(nèi)核的壓縮部分。
????????非壓縮部分還負(fù)責(zé)內(nèi)核重定位。
????????內(nèi)核非壓縮部分工作在保護(hù)模式下,占用內(nèi)存在完成使命后被釋放。
3. Vmlinux
????????在編譯的時(shí)候,kbuild分別構(gòu)建內(nèi)核各個(gè)子目錄中的目標(biāo)文件,將他們鏈接為vmlinux。為了縮小內(nèi)核體積,kbuild刪除了vmlinux中的一些不必要的信息,將其命名為vmlinux.bin,最后將vmlinux.bin壓縮為vmlinux.bin.gz。默認(rèn)情況下內(nèi)核使用gzip壓縮。
4. 映像的格式
????????bin是binary的縮寫,表示文件格式是裸二進(jìn)制。
????????Linux在host environment模式二進(jìn)制文件是ELF格式,操作系統(tǒng)也提供ELF文件的加載器。但是,操作系統(tǒng)本身工作在freestanding environment下。
????????內(nèi)核版本從2.6開(kāi)始內(nèi)核的壓縮部分,即vmlinux采用了ELF格式。
????????在內(nèi)核解壓鏡像后,會(huì)跳轉(zhuǎn)到解壓映像的開(kāi)頭執(zhí)行。ELF文件開(kāi)頭是ELF文件頭。因此需要一個(gè)ELF加載器來(lái)加載ELF頭部。
????????內(nèi)核非壓縮部分調(diào)用函數(shù)decompress解壓內(nèi)核后,調(diào)用parse_elf處理ELF格式的內(nèi)核映像。
linux-4.4.153\arch\x86\boot\compressed\misc.c
????????在ELF中存放代碼和數(shù)據(jù)段的類型是PT_LOAD
????????在函數(shù)prase_elf中,對(duì)于類型是PT_LOAD的段,按照program headers中的信息,將他們移動(dòng)到鏈接時(shí)指定的物理地址處,即p_paddr,若內(nèi)核是可重定位的,還要考慮內(nèi)核實(shí)際加載地址和編譯時(shí)指定的加載地址的差值。
????????若bootloader不是”the Xen domain builder”,可以不要保留內(nèi)核的壓縮部分為ELF格式,并且略去啟動(dòng)時(shí)進(jìn)行的prase_elf操作。
1.?將壓縮部分鏈接為裸二進(jìn)制格式
將傳遞給命令objdump的參數(shù)追加-O binary
linux-4.4.153/arch/x86/boot/compressed/Makefile
1.?注釋掉prase_elf
linux-4.4.153\arch\x86\boot\compressed\misc.c