內核源碼樹結構
目錄 | 描述 |
---|---|
arch | 特定體系結構的源碼 |
block | 塊設備I/O層 |
crypto | 加密API |
Documentation | 內核源碼文檔 |
drivers | 設備驅動程序 |
firmware | 使用某些驅動程序而需要的設備固件 |
fs | VFS和各種文件系統 |
include | 內核頭文件 |
init | 內核引導和初始化 |
ipc | 進程間通信代碼 |
kernel | 像調度程序這樣的核心子系統 |
lib | 通用內核函數 |
mm | 內存管理子系統和VM |
net | 網絡子系統 |
samples | 示例,示范代碼 |
scripts | 編譯內核所用的腳本 |
security | Linux安全模塊 |
sound | 語音子系統 |
usr | 早期用戶空間代碼(所謂的initramfs) |
tools | 在Linux開發中有用的工具 |
virt | 虛擬化基礎結構 |
配置、編譯及安裝內核
配置內核
內核提供了各種不同的工具來簡化內核配置。
一. 通過一個字符界面下的命令行工具
$ make config
這個工具會逐一遍歷所有配置項,要求用戶選擇yes
,no
或module
(如果是三選一的話),比較耗費時間
二. 通過基于ncurse
庫編制的圖形界面工具(需要預先安裝ncurse
)
$ make menuconfig
三. 通過基于gtk+
的圖形工具
$ make gconfig
四. 基于默認配置為你的體系結構創建一個配置
$ make defconfig
這些配置項會被存放在內核源碼樹根目錄下的.config
文件中,你可以找到它,并可以隨意修改它。在你修改過配置文件之后,或者在用已有的配置文件配置新的代碼樹的時候,你應該驗證和更新配置:
$ make oldconfig
編譯內核
一旦內核配置好了,就可以使用一個簡單的命令來編譯它了
$ make
或者你也可以衍生多個作業來加快編譯計數
$ make -jn
這里的n
是要衍生的作業數
安裝內核
一. 安裝內核模塊
$ make modules_install
二. 安裝內核
$ make install
Linux所謂的安裝即是拷貝文件,修改配置文件,內核安裝實際上也是如此
- 復制內核映像到
/boot
中,編譯成功后生成的內核映像文件bzImage
放在arch/<architecture>/boot/
中,該文件復制到/boot
后重命名為vmlinuxz-<kernel-version>
- 生成
initrd-<kernel-version>
.img文件 - 配置引導程序(
GRUB
方式編輯/etc/grub/grub.conf
,LILO
方式編輯/etc/lilo.conf
) -
reboot
進入新內核
內核開發的特點
- 無
libc
庫抑或無標準頭文件
為了保證內核的小而且高效,內核開發不能使用C標準庫,所以哪怕是最簡單的printf
函數也無法使用,不過有替代的printk
- 使用
GNU C
,推薦使用GNC 4.4或之后的版本
因為使用了GNC
,所以Linux內核常有一些GNC
的一些擴展 - 內聯(
inline
)函數
內核開發者通常把那些對時間要求比較高,而本身長度又比較短的函數定義成內聯函數。
定義一個內聯函數的時候,需要使用static
作為關鍵字,并使用inline
限定它,比如
```c
static inline void wolf(unsigned long tail_size)
```
- 內聯匯編
gcc
編譯器支持在C函數中嵌入匯編指令,在內核編程的時候,知道對應的體系結構,可以使用這個功能。通常使用asm()
指令嵌入匯編代碼,例如下面這條內核指令用于執行x86處理器的rdtsc
指令,返回時間戳(tsc)寄存器的值:
```c
unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
/* low 和 high 分別包含64位時間戳的低32位和高32位 */
```
- 分支聲明
如果事先知道一個條件經常為假,或者經常為真,我們可以使用unlikely()
和likely()
對條件分支選擇進行優化。
```c
/* 我們認為error絕大多數時間都會為0 */
if (unlikely(error)) {
/* ... */
}
```
```c
/* 我們認為success通常都不會為0 */
if (likely(success)) {
/* ... */
}
```
- 缺乏像用戶空間那樣的內存保護機制
- 難以執行浮點運算
- 內核給每個進程只有一個很小的定長堆棧
內核棧的大小由編譯內核時決定的,對于不用的體系結構,內核棧的大小雖然不一樣,但都是固定的。
查看內核棧大小的方法:
$ ulimit -a | grep "stack size"
- 由于內核支持異步中斷、搶占和SMP,因此必須時刻注意同步和并發
- 要考慮可移植性的重要性