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