安大大 + 原創作品轉載請注明出處 + 《Linux操作系統分析》MOOC課程
實驗
- 使用自己的Linux系統環境搭建MenuOS的過程
# 下載內核源代碼編譯內核
cd ~/LinuxKernel/
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz
xz -d linux-3.18.6.tar.xz
tar -xvf linux-3.18.6.tar
cd linux-3.18.6
make i386_defconfig
make # 一般要編譯很長時間,少則20分鐘多則數小時
# 制作根文件系統
cd ~/LinuxKernel/
mkdir rootfs
git clone https://github.com/mengning/menu.git # 如果被墻,可以使用附件menu.zip
cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread #init是系統啟動后默認啟動1號進程,init是第一個用戶態進程,第一個用戶態進程是1號進程
cd ../rootfs
cp ../menu/init ./ #把init拷貝到rootfs目錄下邊
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img #使用cpio方式把當前rootfs目錄下所有的文件打包成rootfs.img一個鏡像文件
#至此一個最簡單的根文件系統鏡像制作完畢
# 啟動MenuOS系統
cd ~/LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
- 重新配置編譯Linux使之攜帶調試信息
1.在原來配置的基礎上,make menuconfig選中如下選項重新配置Linux,使之攜帶調試信息
2.1 kernel hacking—>
2.2 [*] compile the kernel with debug info #把debug信息打開
#使得跟蹤調試時可以邊跟蹤邊看跟蹤到某一點的某一行代碼時上下那一段的源代碼
3.make重新編譯(時間較長)
- 內核啟動完成后進入menu程序:
把menu編譯好的init文件放在rootfs里,然后把rootfs做成rootfs.img。根文件系統是rootfs.img,內核啟動完后加載根文件系統,根文件系統里的init可執行文件就被執行起來了
使用gdb跟蹤調試內核:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 關于-s和-S選項的說明:
-S freeze CPU at startup (use ’c’ to start execution) CPU初始化之前凍結起來
-s shorthand for -gdb tcp::1234 在這個端口上創建了一個gdb server,若不想使用1234端口,則可以使用-gdb tcp:xxxx來取代-s選項
另開一個shell窗口:
gdb
(gdb)file linux-3.18.6/vmlinux # 把一個帶有符號表的內核鏡像加載進來,在gdb界面中targe remote之前加載符號表
(gdb)target remote:1234 # 建立gdb和gdbserver之間的連接,按c 讓qemu上的Linux繼續運行
(gdb)break start_kernel # 設置斷點,跟蹤內核,斷點的設置可以在target remote之前,也可以在之后
全局變量init_task即手工創建的PCB在這里初始化,0號進程即最終的idle進程。
不管分析內核的哪一部分都會涉及到start_kernel,因為要通過start_kernel進行初始化。
trap_init();初始化一些中斷向量
mm_init();內存管理模塊初始化
sched_init();調度模塊初始化
等等
start_kernel的最后一句rest_init();
當系統沒有進程需要執行時就調度到idle進程
Linux內核啟動過程相關的參考資料
計算機的啟動過程概述
x86 CPU啟動的第一個動作CS:EIP=FFFF:0000H(換算為物理地址為000FFFF0H,因為16位CPU有20根地址線),即BIOS程序的位置。http://wenku.baidu.com/view/4e5c49eb172ded630b1cb699.html
BIOS例行程序檢測完硬件并完成相應的初始化之后就會尋找可引導介質,找到后把引導程序加載到指定內存區域后,就把控制權交給了引導程序。這里一般是把硬盤的第一個扇區MBR和活動分區的引導程序加載到內存(即加載BootLoader),加載完整后把控制權交給BootLoader。
引導程序BootLoader開始負責操作系統初始化,然后起動操作系統。啟動操作系統時一般會指定kernel、initrd和root所在的分區和目錄,比如root (hd0,0),kernel (hd0,0)/bzImage root=/dev/ram init=/bin/ash,initrd (hd0,0)/myinitrd4M.img
內核啟動過程包括start_kernel之前和之后,之前全部是做初始化的匯編指令,之后開始C代碼的操作系統初始化,最后執行第一個用戶態進程init。
一般分兩階段啟動,先是利用initrd的內存文件系統,然后切換到硬盤文件系統繼續啟動。initrd文件的功能主要有兩個:1、提供開機必需的但kernel文件(即vmlinuz)沒有提供的驅動模塊(modules) 2、負責加載硬盤上的根文件系統并執行其中的/sbin/init程序進而將開機過程持續下去
道生一(start_kernel....cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三個進程),三生萬物(1號進程是所有用戶態進程的祖先,2號進程是所有內核線程的祖先),新內核的核心代碼已經優化的相當干凈,都符合中國傳統文化精神了。