首先按照課程中的內容編譯并用gdb+qemu調試運行我們的Linux操作系統(tǒng).其命令如下:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
再打開另一個終端窗口,進入gdb,如下:
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加載符號表
(gdb)target remote:1234 # 建立gdb和gdbserver之間的連接,按c 讓qemu上的Linux繼續(xù)運行
(gdb)break start_kernel # 斷點的設置可以在target remote之前丙号,也可以在之后
(gdb)c #繼續(xù)運行,使得qemu開始繼續(xù)執(zhí)行并在start_kernel函數入口停下.
結果如圖1所示:
start_kernel()中調用了一系列初始化函數湿右,以完成kernel本身的設置耍共。這些動作有的是公共的茬高,有的則是需要配置的才會執(zhí)行的.
start_kernel啟動過程分析
內核的初始化程序在start_kernel這個函數中,可以在線查看這些代碼: start_kernel。通過閱讀start_kernel代碼,可以大致了解到內核在初始化的時候,做了以下工作:1. lockdep_init():初始化內核依賴關系表致扯,初始化hash表
- boot_init_stack_canary():為棧增加保護機制,預防一些緩沖區(qū)溢出之類的攻擊
- tick_init():初始化內核時鐘系統(tǒng)
- boot_cpu_init():激活當前CPU
- setup_arch():對不同體系結構的CPU設置不同的參數当辐、選項等
- trap_init():初始化硬件中斷抖僵,函數中設置了很多中斷門
- mm_init():建立內核的內存分配器
- sched_init():初始化任務調度
- init_irq():中斷向量的初始化.... 很多初始化工作。
- rest_init():剩下的初始化工作缘揪,這里面其實做了很多工作.
其中幾個重要的步驟跟蹤如下:
- set_task_stack_end_magic(&init_task);
在該函數中初始化了系統(tǒng)第一個task_struct結構體耍群,主要社設置了該任務的堆棧。跟蹤如下:
跟蹤進入函數:
可以看出在此處設置了該任務的堆棧找筝。
- 561行上的trap_init()函數:
在該處設置斷點后執(zhí)行并步入(step) 該函數,可看待如下內容:
在該函數中,對我們分析代碼來說最重要的是如下語句:
即839行上的set_system_trap_gate(SYSCALL_VECTOR, &system_call);調用.使得系統(tǒng)調用與SYSCALL_VECTOR(0x80)號中斷相關聯(lián).為以后從用戶態(tài)調用系統(tǒng)中提供的系統(tǒng)調用功能提供了途徑.
- 最后,該函數調用 rest_init()函數進行最后的初始化工作,包括創(chuàng)建1號進程(init),第一個內核線程等操作.
首先我們在該函數的調用設置斷點:
進入函數,看到初始化以一個進程(init 進程)和第一個內核線程:
該函數調用了 do_fork 進行新線程的創(chuàng)建.
可以看到, pid 目前是逐個累加,也可以看出內核線程確實實在 1號進程即pid 為1的進程(init)創(chuàng)建之后創(chuàng)建.
最后內核線程調用cpu_startup_entry,再在其中調用cpu_idle_loop函數進入睡眠循環(huán).節(jié)省CPU 能耗.即0號進程
總結:本實驗主要是跟蹤linux內核的啟動過程蹈垢,這里是從start_kernel到init,從而來理解linux的第一個進程及后面進程的產生過程袖裕。整個linux系統(tǒng)的所有進程是一個樹形結 構曹抬。樹根是系統(tǒng)自動構造的,樹根即是0號進程 急鳄。Linux一開始先在無進程的情況下將一直從初始化部分的代碼執(zhí)行到start_kernel谤民,然后再到其最后一個函數調用rest_init。從rest_init開始疾宏,Linux開始產生進程张足,在rest_init中,通過init_task產生pid=0的進程灾锯,即0號進程(idle進程)兢榨,它是內核狀態(tài)下的進程;在rest_init函數中顺饮,內核通過kernel_ini創(chuàng)建1號進程,它是第一個用戶態(tài)進程凌那。關于init_task(也就是idle)兼雄,當運行隊列中沒有別的就緒進程時,init_task(也就是idle)將會被調用帽蝶,它的核心是一個while(1)循環(huán)赦肋,在循環(huán)中它將會調用schedule函數以便在運行隊列中有新進程加入時切換到該新進程上。