内核源码目录结构

arch                特定体系结构的源码
block               块设备I/O
crypto              加密API
Documentation       文档
drivers             驱动程序
firmware            使用某些驱动需要的设备固件
fs                  VFS和各种文件系统
include             内核头文件
init                内核引导和初始化
ipc                 进程间通信
kernel              内核子系统,例如调度程序
lib                 通用内核函数
mm                  内存管理子系统,VM
net                 网络子系统
samples             示例代码
scripts             编译内核用的脚本
security            安全模块
sound               语音子系统
usr                 早期用户空间代码
tools               开发内核用的工具
virt                虚拟化

编译内核

配置内核

# 原始的配置方法,需要在命令行中选择非常多的选项,非常耗时,需要几小时
make config

# 图形配置界面,更方便
make menuconfig
make gconfig

# 默认配置,这个最快
make defconfig

配置项会保存在根目录下的.config文件中,可以自己修改。修改完.config文件或者用已有的.config文件配置新的代码树时,应该验证和更新配置,需要执行:

make oldconfig

选项CONFIG_IKCONFIG_PROC会把压缩的配置文件放在/proc/config.gz,在编译时可以解压出一个配置文件。

zcat /proc/config.gz > .config
make oldconfig

配置完成后,开始编译,多线程加快编译速度

make -j4

内核开发的特点

  • 不能访问C函数库,不能访问标准C头文件
  • 必须使用GNU C
  • 没有用户空间的内存保护机制
  • 难以执行浮点运算
  • 内核给每个进程只有很小的栈,通常是8KB
  • 内核支持异步中断、抢占、SMP,必须注意同步和并发
  • 需要考虑可移植性

GNU C

内联函数,例如:

static inline void wolf(unsigned long tail_size){
    // ...
}

内联汇编,例如:

unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d", (high));

分支声明,编译器可以根据likely()unlikely()对条件分支选择进行优化,例如:

if (unlikely(error)){
    // ...
}

if (likely(success)){
    // ...
}