1. 获取源码
获取Linux的源码常见方式:
https://github.com/torvalds/linux
https://www.kernel.org/
https://mirrors.tuna.tsinghua.edu.cn/ 清华大学
https://mirrors.aliyun.com/ 阿里云
2. 源码目录结构
在线查看:http://lxr.free-electrons.com/ 没有好的2.6版本的在线查看地址,还是下载源码用Source Insight工具查看方便。
内核源码一般在/usr/src/linux目录
目录 | 说明 |
---|---|
Documentation/ | 文档 |
arch/ | 特点体系结构代码 |
block/ | 块设备I/O |
certs/ | 证书 |
crypto/ | 加密API |
drivers/ | 设备驱动程序 |
firmware/ | 某些设备固件 |
fs/ | VFS和各种文件系统 |
include/ | 内核头文件 |
init/ | 内核引导和初始化 |
ipc/ | 进程间通信代码 |
kernel/ | 核心子系统 |
lib/ | 通用内核函数 |
mm/ | 内存管理子系统和VM |
net/ | 网络子系统 |
samples/ | 示例代码 |
scripts/ | 编译内核所用脚本 |
security/ | Linux安全模块 |
sound/ | 语音子系统 |
tools/ | 开发工具 |
usr/ | 早期用户空间代码(initramfs) |
virt/ | 虚拟化基础结构 |
COPYING | copyright |
CREDITS | 核心开发者列表 |
Kbuild | |
Kconfig | |
MAINTAINERS | 维护者列表 |
Makefile | for make |
- 打补丁: patch -pl < ../patch-x.y.z
3. 编译内核
Linux内核编译支持配置和定制,可以按需选取特定功能和驱动程序编译进内核,其他模块可以以内核模块的形式动态加载。
配置选项以CONFIG_FEATURE的形式表示,要么二选一:yes or no,要么三选一:yes、no or module,module即表示以内核模块的方式编译相关代码,驱动程序一般为三选一。
配置命令:
- make config
- make menuconfig **
- make gconfig
- make defconfig - 生成默认配置
- make oldconfig - 用已有配置文件进行配置
配置项最终会放在内核代码树根目录下的.config文件中
|
|
4. 内核开发的特点
4.1 无标准C函数库
常用C库都有内核版本的实现,基本头文件位于内核源码树include目录,体系结构相关头文件位于内核源码树的arch/
4.2 使用GNU C
内核使用的C语言涵盖了ISO C99标准和GNU C扩展特性
内联(inline)函数
- 内联函数在编译时会在它被调用的位置上展开,消除函数调用和返回所带来的开销,也利于编译器优化,性能较好。但是,内联函数会使代码变长,占用更多的内存或指令缓存。
- 例子: static inline void foo()
- 内联函数必须在使用之前定义好,通常在头文件中定义。
内联汇编
在偏近体系结构底层或对执行时间要求严格的地方,使用汇编语言分支声明
gcc内建了一条指令判断一个if语句时经常为真还是经常为假,内核封装成宏likely()和unlikely()没有内存保护机制
内核发生内存错误会导致oops,系统会挂掉;内核的内存都不分页,没用掉一个字节,物理内存就少一个字节,因此内核使用内存要谨慎不要使用浮点数
内核不能完美支持浮点操作,因为它本身不能陷入,使用浮点数时,除了要人工保存和恢复浮点寄存器还要其他一些繁琐的操作。容积小而固定的栈
内核的栈大小在编译时进行配置,之后固定不变,每个处理器都有自己的栈。不同的体系结构,栈的大小可能不同,但都不大同步和并发
Linux是多用户操作系统,内核支持异步中断、抢占和SMP,容易产生race condition,必须时刻考虑并发可移植性
Linux作为一个可移植的操作系统,在开发时要将与体系结构相关代码分离