2018-2019-1 20189210 《LInux内核原理与分析》第四周作业
第三章
這一章接觸內(nèi)核源代碼,對(duì)內(nèi)核源碼進(jìn)行編譯和調(diào)試跟蹤
一、預(yù)備知識(shí):
內(nèi)核:整個(gè)操作系統(tǒng)的最底層,它負(fù)責(zé)了整個(gè)硬件的驅(qū)動(dòng)以及提供各種系統(tǒng)所需的內(nèi)核功能。內(nèi)核實(shí)質(zhì)上是系統(tǒng)上面的一個(gè)文件而已,這個(gè)文件包含了驅(qū)動(dòng)主機(jī)各項(xiàng)硬件的檢測(cè)程序與驅(qū)動(dòng)模塊。當(dāng)系統(tǒng)讀完BIOS并加載MBR內(nèi)的引導(dǎo)裝載程序后,就能夠加載內(nèi)核到內(nèi)存當(dāng)中。然后內(nèi)核開始檢測(cè)硬件,掛載根目錄并取得內(nèi)核模塊來(lái)驅(qū)動(dòng)所有的硬件,之后調(diào)用/sbin/init就能依序啟動(dòng)多有系統(tǒng)所需要的服務(wù)了。
Qemu :以GPL許可證分發(fā)源碼的模擬處理器,能啟動(dòng)那些為不同中央處理器編譯的Linux程序。
二、構(gòu)造一個(gè)簡(jiǎn)單的Linux內(nèi)核
構(gòu)造的MenuOS系統(tǒng)是由Linux內(nèi)核鏡像和根文件系統(tǒng)集成起來(lái)的。
Linux內(nèi)核在PC上以文件的形式存在(保存成磁盤文件形式),就是所謂的“映像文件”。內(nèi)核編譯(make)之后會(huì)生成兩個(gè)文件,一個(gè)Image,一個(gè)zImage,其中Image為內(nèi)核映像文件,而zImage為內(nèi)核的一種映像壓縮文件,Image大約為4M,而zImage不到2M。為了能使用zImage這個(gè)壓縮版本,必須在它的開頭加上解壓縮的代碼,將zImage 解壓縮之后才能執(zhí)行,因此它的執(zhí)行速度比Image要慢。但考慮到嵌入式系統(tǒng)的存儲(chǔ)空容量一般都比較小,內(nèi)核要常駐內(nèi)存,采用zImage可以占用較少的存儲(chǔ)空間,因此犧牲一點(diǎn)性能上的代價(jià)也是值得的,所以一般嵌入式系統(tǒng)均采用壓縮的內(nèi)核映像文件,即zImage。
根文件系統(tǒng)首先是一種文件系統(tǒng),該文件系統(tǒng)不僅具有普通文件系統(tǒng)的存儲(chǔ)數(shù)據(jù)文件的功能,但是相對(duì)于普通的文件系統(tǒng),它的特殊之處在于,它是內(nèi)核啟動(dòng)時(shí)所掛載(mount)的第一個(gè)文件系統(tǒng),內(nèi)核代碼的映像文件保存在根文件系統(tǒng)中,系統(tǒng)引導(dǎo)啟動(dòng)程序會(huì)在根文件系統(tǒng)掛載之后從中把一些初始化腳本(如rcS,inittab)和服務(wù)加載到內(nèi)存中去運(yùn)行。先將/dev/ram0掛載,而后執(zhí)行/linuxrc.等其執(zhí)行完后。切換根目錄,再掛載具體的根文件系統(tǒng).根文件系統(tǒng)執(zhí)行完之后,也就是到了Start_kernel()函數(shù)的最后,執(zhí)行init的進(jìn)程,也就第一個(gè)用戶進(jìn)程。對(duì)系統(tǒng)進(jìn)行各種初始化的操作。
在實(shí)驗(yàn)樓中的虛擬機(jī)里,直接進(jìn)入LinuxKernel目錄使用如下命令就可以運(yùn)行Linux內(nèi)核源碼和跟文件系統(tǒng)
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rotes.img
其中bzImage是vmlinux經(jīng)過(guò)gzip壓縮后的文件,適用于大內(nèi)核;vmLinux是編譯出來(lái)的最原始的內(nèi)核ELF文件;initrd是內(nèi)存根文件系統(tǒng),只創(chuàng)建了一個(gè)rootfs.img,其中只有一個(gè)init的功能,用menu程序替代init, 內(nèi)核啟動(dòng)完成后進(jìn)入menu程序。
三、跟蹤調(diào)試Linux內(nèi)核的啟動(dòng)過(guò)程
Qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rotes.img -s -S
-S CPU初始化之前將其凍結(jié)起來(lái)
-s 是默認(rèn)在tcp::1234端口上創(chuàng)建了一個(gè)gdb-server
再打開一個(gè)窗口,啟動(dòng)gdb,把內(nèi)核加載進(jìn)來(lái),建立連接
file linux-3.18.6/vmlinux #把帶有符號(hào)表的內(nèi)核鏡像加載進(jìn)來(lái)
target remote:1234 #用tcp:1234端口來(lái)鏈接gdb server
然后在start_kernel函數(shù)和rest_init處設(shè)置端點(diǎn),調(diào)試運(yùn)行
四、對(duì)于start_kernel( )和rest_init( )的分析
start_kernel( )相當(dāng)于main.c中的main函數(shù),是首先運(yùn)行的,在此函數(shù)調(diào)用之前,內(nèi)核代碼主要是匯編語(yǔ)言編寫的,用于完成硬件系統(tǒng)的初始化工作,為C代碼的運(yùn)行設(shè)置環(huán)境。這個(gè)函數(shù)主要進(jìn)行各個(gè)模塊初始化工作,trap_init()(中斷向量的初始化)、mm_init()(內(nèi)存管理的初始化)sched_init()(調(diào)度模塊的初始化)等。
init_task() :0號(hào)進(jìn)程,初始化的起點(diǎn)
struct task_struct init_task = INIT_TASK(init_task);
可以看出 init_task(0號(hào)進(jìn)程)是 task_struct 類型,是進(jìn)程描述符,使用宏INIT_TASK對(duì)其進(jìn)行初始化,并且init_task是唯一沒有通過(guò)fork方式產(chǎn)生的進(jìn)程。
rest_init( ):
在此函數(shù)中調(diào)用kernel_thread進(jìn)程來(lái)創(chuàng)建kernel_init和kthreadd內(nèi)核線程
kernel_init()內(nèi)核線程為1號(hào)內(nèi)核線程,負(fù)責(zé)執(zhí)行內(nèi)核的部分初始化工作及進(jìn)行系統(tǒng)配置,最后調(diào)用do_execve加載init程序,最后演變成用戶態(tài)1號(hào)進(jìn)程——init進(jìn)程。
kthreadd()函數(shù)的任務(wù)是管理和調(diào)度其他內(nèi)核線程 kernel_thread。for 循環(huán)中運(yùn)行 kthread_create_list 全局鏈表中維護(hù)的 kthread, 在create_kthread()函數(shù)中,會(huì)調(diào)用 kernel_thread 來(lái)生成一個(gè)新的進(jìn)程并被加入到此鏈表中,因此所有的內(nèi)核線程都是直接或者間接的以 kthreadd 為父進(jìn)程。
小結(jié):
本周學(xué)習(xí)了Linux內(nèi)核源代碼,對(duì)于內(nèi)核的源代碼目錄,編譯過(guò)程有了進(jìn)一步的了解,但在學(xué)習(xí)中總會(huì)遇到新的問(wèn)題,例如kernel_thread進(jìn)程是由init零號(hào)進(jìn)程fork出來(lái)的,以及idle進(jìn)程與0號(hào)進(jìn)程的關(guān)系,內(nèi)核線程與用戶進(jìn)程的區(qū)別,這些問(wèn)題在CSDN論壇中大部分都以解決,但發(fā)現(xiàn)內(nèi)核內(nèi)部的知識(shí)非常高深,還需多多查閱資料
轉(zhuǎn)載于:https://www.cnblogs.com/20189210mujian/p/9906672.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的2018-2019-1 20189210 《LInux内核原理与分析》第四周作业的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 解析.DBC文件, 读懂CAN通信矩阵,
- 下一篇: postgresql 高可用 etcd