前幾天大家對Linux的啟動有些討論。 于是整理了一下前段時間與他人交流的提綱,希望起到拋磚引玉的作用。 xiaoman04@hotmail.com 這是一次對Linux介紹后的整理。 對象是一些剛對Linux核心感興趣,并且準(zhǔn)備進(jìn)一步研究和改造的同志。 因?yàn)槭怯商峋V整理而成,有些亂,見諒!
四部分內(nèi)容: 一、Linux核心源碼結(jié)構(gòu)介紹 二、編譯和配置的過程 三、系統(tǒng)啟動順序的相關(guān)文件 四、核心改造的一些經(jīng)驗(yàn) 一、 當(dāng)我們安裝好一個Linux系統(tǒng),通常核心源碼存放在/usr/src/linux/目錄。 下面先看看這目錄下的各個子目錄及文件。 [/]#cd /usr/src/linux [linux]#ls -aF ./ MAINTAINERS drivers/ kernel/ scripts/ ../ Makefile fs/ lib/ COPYING README include/ mm/ CREDITS Rules.make init/ modules/ Documentation/ arch/ ipc/ net/ 下面我們逐一描述: COPYING ## GPL版權(quán)申明,看后你至少應(yīng)該知道,你對具有GPL版權(quán)的源代碼改動而 形成的程序,或使用GPL工具產(chǎn)生的程序,具有使用GPL發(fā)表的義務(wù)。其中之一就是 公開源代碼。 CREDITS ## 光榮榜,你應(yīng)當(dāng)感謝的一些人的信息,其中的每一個人都對Linux做出過 很大貢獻(xiàn)。 Documentation/ ## 文檔目錄,可有選擇地看一下你感興趣的部分 MAINTAINERS ## 維護(hù)人員列表,對當(dāng)前版本的內(nèi)核各部分都有誰負(fù)責(zé),如果你研究的 夠深入,可以與他們討論 Makefile ## 如果你在UNIX編譯過程序,可以看明白 README ## Linus 所寫,核心及其編譯配置方法簡單介紹 Rules.make ## make時使用的一些共同規(guī)則 arch/ ## architecture(體系結(jié)構(gòu))我關(guān)心的i386啟動過程在其中, ## 包括Linux在多種平臺下的實(shí)現(xiàn)。如果要移植系統(tǒng)到一個新的 ##CPU環(huán)境中,這就是你要關(guān)心的目錄 drivers/ ## 驅(qū)動程序目錄,包含大量設(shè)備驅(qū)動的實(shí)現(xiàn),按類別分子目錄 fs/ ## 文件系統(tǒng),實(shí)現(xiàn)了當(dāng)前流行的幾乎所有文件系統(tǒng)。Cool include/ ## 嵌入文件目錄 init/ ## 初始化文件,包含main.c和version.c兩個文件。Initialize ipc/ ## ipc的實(shí)現(xiàn),與SYS V兼容 kernel/ ## 最核心代碼,調(diào)度,中斷,信號等的處理 lib/ ## 一些工具。 mm/ ## 內(nèi)存管理,Memory Manager,虛擬頁、緩沖的實(shí)現(xiàn)。 modules/ ## 模塊文件目錄,用于存放編譯時產(chǎn)生的模塊目標(biāo)文件(參考編譯過程) net/ ## 網(wǎng)絡(luò)實(shí)現(xiàn),包括TCP/IP在內(nèi)的大量網(wǎng)絡(luò)協(xié)議的實(shí)現(xiàn)。 scripts/ ## 描述文件,腳本,用于對核心的配置。
二、 構(gòu)造內(nèi)核 常用命令包括: make config, dep, clean, mrproper, zImage, bzImage, modules, modules_install (1) make config 核心配置,調(diào)用./scripts/Configure 按照arch/i386/config.in 來進(jìn)行 配置。 命令執(zhí)行完后產(chǎn)生文件.config,其中保存著配置信息。 下一次再做make config將產(chǎn)生新的.config文件,原.config被改名為.config.old (2)make dep 尋找依存關(guān)系。 產(chǎn)生兩個文件.depend和.hdepend 其中.hdepend表示每個.h文件都包含其它哪些嵌入文件。 而.depend 文件有多個,在每個會產(chǎn)生目標(biāo)文件(.o)文件的目錄下均有, 它表示每個目標(biāo)文件都依賴哪些嵌入文件(.h)。
(3)make clean 清出以前構(gòu)核所產(chǎn)生的所有目標(biāo)文件、模塊文件、核心以及一些臨時文件等, 不產(chǎn)生任何文件
(4)make rmproper 刪除所有因構(gòu)核過程中產(chǎn)生的所有文件,及除了做make clean外,還要 刪除.config,.depend等文件,把核心源碼恢復(fù)到最原始的狀態(tài)。 下次構(gòu)核時就必須重新配置了。
(5)make, make zImage, make bzImage make: 構(gòu)核。通過各目錄的Makefile文件進(jìn)行。 會在各個目錄下產(chǎn)生一大堆目標(biāo)文件,若核心代碼沒有錯誤,將 產(chǎn)生文件vmlinux,這就是所構(gòu)的核心。并產(chǎn)生映射文件System.map 通過各目錄的Makefile文件進(jìn)行。 .version 文件中的數(shù)加1,表示版本號(又產(chǎn)生一個新的版本了),讓你 明白,你已經(jīng)對核心改動過多少次了。 make zImage: 在make的基礎(chǔ)上產(chǎn)生壓縮的核心映象文件./arch/$(ARCH)/boot/zImage 以及在./arch/$(ARCH)/boot/compresed/目錄下產(chǎn)生一些臨時文件。 make bzImage: 在make 的基礎(chǔ)上產(chǎn)生壓縮比例更大的核心映象文件 ./arch/$(ARCH)/boot/bzImage 以及在./arch/$(ARCH)/boot/compresed/目錄下產(chǎn)生一些臨時文件。 在核心太大時進(jìn)行。 (6)make modules 編譯模塊文件,你在make config時所配置的所有模塊將在這時編譯, 形成模塊目標(biāo)文件,并把這些目標(biāo)文件存放在modules目錄中。 使用如下命令看一看。 ls modules (7)make modules_install 把上面編譯好的模塊目標(biāo)文件目錄/lib/modules/$KERNEL_VERSION/ 中。 比如我的版本是2.0.36,做完這個操作后可使用下面的命令看看: ls /lib/modules/2.0.36/
相關(guān)的命令還有很多,有興趣可看相關(guān)資料和Makefile文件。 另外注意,這兒我們產(chǎn)生了一些隱含文件 .config .oldconfig .depend .hdepend .version 它們的意義應(yīng)該很清楚了。 三、 系統(tǒng)的啟動順序及相關(guān)文件 仍在核心源碼目錄下,看以下幾個文件 ./arch/$ARCH/boot/bootsect.s ./arch/$ARCH/boot/setup.s ./init/main.c
bootsect.S 及 setup.S 這個程序是linux kernel的第一個程序,包括了linux自己的bootstrap程序, 但是在說明這個程序前,必須先說明一般IBM PC開機(jī)時的動作(此處的開機(jī)是指 "打開PC的電源"): 一般PC在電源一開時,是由內(nèi)存中地址FFFF:0000開始執(zhí)行(這個地址一定 在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此處的內(nèi)容則是一個 jump指令,jump到另一個位於ROM BIOS中的位置,開始執(zhí)行一系列的動作,包 括了檢查RAM,keyboard,顯示器,軟硬磁盤等等,這些動作是由系統(tǒng)測試代碼 (system test code)來執(zhí)行的,隨著制作BIOS廠商的不同而會有些許差異,但都 是大同小異,讀者可自行觀察自家機(jī)器開機(jī)時,螢?zāi)簧纤@示的檢查訊息。 緊接著系統(tǒng)測試碼之后,控制權(quán)會轉(zhuǎn)移給ROM中的啟動程序 (ROM bootstrap routine),這個程序會將磁盤上的第零軌第零扇區(qū)讀入 內(nèi)存中(這就是一般所謂的boot sector,如果你曾接觸過電腦病 毒,就大概聽過它的大名),至於被讀到內(nèi)存的哪里呢? --絕對 位置07C0:0000(即07C00h處),這是IBM系列PC的特性。而位在linux開機(jī) 磁盤的boot sector上的正是linux的bootsect程序,也就是說,bootsect是 第一個被讀入內(nèi)存中并執(zhí)行的程序?,F(xiàn)在,我們可以開始來 看看到底bootsect做了什么。 第一步 首先,bootsect將它"自己"從被ROM BIOS載入的絕對地址0x7C00處搬到 0x90000處,然后利用一個jmpi(jump indirectly)的指令,跳到新位置的 jmpi的下一行去執(zhí)行, 第二步 接著,將其他segment registers包括DS,ES,SS都指向0x9000這個位置, 與CS看齊。另外將SP及DX指向一任意位移地址( offset ),這個地址等一下 會用來存放磁盤參數(shù)表(disk para- meter table ) 第三步 接著利用BIOS中斷服務(wù)int 13h的第0號功能,重置磁盤控制器,使得剛才 的設(shè)定發(fā)揮功能。
第四步 完成重置磁盤控制器之后,bootsect就從磁盤上讀入緊鄰著bootsect的setup 程序,也就是setup.S,此讀入動作是利用BIOS中斷服務(wù)int 13h的第2號功能。 setup的image將會讀入至程序所指定的內(nèi)存絕對地址0x90200處,也就是在內(nèi)存 中緊鄰著bootsect 所在的位置。待setup的image讀入內(nèi)存后,利用BIOS中斷服 務(wù)int 13h的第8號功能讀取目前磁盤的參數(shù)。 第五步 再來,就要讀入真正linux的kernel了,也就是你可以在linux的根目錄下看 到的"vmlinuz" 。在讀入前,將會先呼叫BIOS中斷服務(wù)int 10h 的第3號功能, 讀取游標(biāo)位置,之后再呼叫BIOS 中斷服務(wù)int 10h的第13h號功能,在螢?zāi)簧陷?/font> 出字串"Loading",這個字串在boot linux時都會首先被看到,相信大家應(yīng)該覺 得很眼熟吧。 第六步 接下來做的事是檢查root device,之后就仿照一開始的方法,利用indirect jump 跳至剛剛已讀入的setup部份 比較 把大家所熟知的MS DOS 與linux的開機(jī)部份做個粗淺的比較,MS DOS 由位於 磁盤上boot sector的boot程序負(fù)責(zé)把IO.SYS載入內(nèi)存中,而IO.SYS則負(fù)有把DOS 的kernel --MSDOS.SYS載入內(nèi)存的重責(zé)大任。而linux則是由位於boot sector 的 bootsect程序負(fù)責(zé)把setup及linux的kernel載入內(nèi)存中,再將控制權(quán)交給setup。 ##這幾步內(nèi)容主要參照一個臺灣同胞寫的文檔,setup.s的內(nèi)容希望有人補(bǔ)充。
start_kernel() 當(dāng)核心被載入后,首先進(jìn)入的函數(shù)就是start_kernel。 ./init/main.c 中函數(shù)start_kernel包含核心的啟動過程及順序。 通過它來看核心整個初始化過程。 首先進(jìn)行一系列初始化,包括: trap_init(); ##./arch/i386/kernel/traps.c 陷入 init_IRQ(); ##./arch/i386/kernel/irq.c setup IRQ sched_init(); ##./kernel/sched.c 調(diào)度初始化,并初始化bottom_half time_init(); ##./arch/i386/kernel/time.c init_modules(); ##模塊初始化 mem_init(memory_start,memory_end); buffer_init(); ## ./fs/buffer.c 緩沖區(qū) sock_init(); ## ./net/socket.c socket初始化,并初始化各協(xié)議(TCP等) ipc_init(); sysctl_init(); 然后通過調(diào)用kernelthread()產(chǎn)生init進(jìn)程,全權(quán)交由init進(jìn)程處理。調(diào)用cpu_idle(NULL)休息。 感興趣又有時間的同志可以寫一個startkernel()函數(shù)的詳細(xì)分析報(bào)告。
下面看一看init進(jìn)程的工作: 首先創(chuàng)建進(jìn)程 bdflush ##./fs/buffer.c 緩沖區(qū)管理 和kswapd ##./mm/vmscan.c 虛擬內(nèi)存管理 這兩個進(jìn)程非常重要 系統(tǒng)初始化(系統(tǒng)調(diào)用setup) 系統(tǒng)初始化包含設(shè)備初始化及各文件系統(tǒng)初始化。 sys_setup (./fs/filesystems.c) | |-device_setup | | | -- chr_dev_init(); ##字符設(shè)備 | blk_dev_init(); ##塊設(shè)備 | scsi_dev_init(); ##SCSI | net_dev_init(); ##網(wǎng)絡(luò)設(shè)備 | console_map_init(); ##控制臺 |-binfmt_setup(); |-init_nls() ##各文件系統(tǒng)初始化 |-init_ext_fs() |-init_ext2_fs() . . . . . . |-init_autofs_fs() --mount_root() ##mount root fs ##從這兒看看設(shè)備及文件的初始化順序,加入我們的設(shè)備時就有了大局觀。 執(zhí)行/etc/rc ( rc.sysinit, rc.local, rc.# ) 和 執(zhí)行/bin/sh ______________________________________________________ END |
|