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