在尝试内核开发之前,需要对内核有个整体的了解。
主要内容:
获取内核源码
内核源码的结构
编译内核的方法
内核开发的特点
1. 获取内核源码内核是开源的,所有获取源码特别方便,参照以下的网址,可以通过git或者直接下载压缩好的源码包。
2. 内核源码的结构
目录
说明
arch
特定体系结构的代码
block
块设备I/O层
crypo
加密API
Documentation
内核源码文档
drivers
设备驱动程序
firmware
使用某些驱动程序而需要的设备固件
fs
VFS和各种文件系统
include
内核头文件
init
内核引导和初始化
ipc
进程间通信代码
kernel
像调度程序这样的核心子系统
lib
同样内核函数
mm
内存管理子系统和VM
net
网络子系统
samples
示例,示范代码
scripts
编译内核所用的脚本
security
Linux 安全模块
sound
语音子系统
usr
早期用户空间代码(所谓的initramfs)
tools
在Linux开发中有用的工具
virt
虚拟化基础结构
3. 编译内核的方法
还未实际尝试过手动编译内核,只是用yum更新过内核。这部分等以后手动编译过再补上。
安装新的内核后,重启时会提示进入哪个内核。当多次安装新的内核后,启动列表会很长(因为有很多版本的内核),显得不是很方便。
下面介绍3种删除那些不用的内核的方法:(是如何安装的就选择相应的删除方法)
3.1 rpm 删除法rpm -qa | grep kernel* (查找所有linux内核版本)
rpm -e kernel-(想要删除的版本)
yum remove kernel-(要删除的版本)
3.3 手动删除删除/lib/modules/目录下不需要的内核库文件
删除/usr/src/kernel/目录下不需要的内核源码
删除/boot目录下启动的核心档案禾内核映像
更改grub的配置,删除不需要的内核启动列表
为了保证内核的小和高效,内核开发中不能使用C标准库,所以连最常用的printf函数也没有,但是还好有个printk函数来代替。
4.2 使用GNU C,推荐用gcc 4.4或以后的版本来编译内核因为使用GNU C,所有内核中常使用GNU C中的一些扩展:
4.2.1 内联函数内联函数在编译时会在它被调用的地方展开,减少了函数调用的开销,性能较好。但是,频繁的使用内联函数也会使代码变长,从而在运行时占用更多的内存。
所以内联函数使用时最好要满足以下几点:函数较小,会被反复调用,对程序的时间要求比较严格。
内联函数示例:static inline void sample();
4.2.2 内联汇编内联汇编用于偏近底层或对执行时间严格要求的地方。示例如下:
unsigned int low, high; asm volatile("rdtsc" : "=a" (low), "=d" (high)); /* low 和 high 分别包含64位时间戳的低32位和高32位 */
4.2.3 分支声明如果能事先判断一个if语句时经常为真还是经常为假,那么可以用unlikely和likely来优化这段判断的代码。
/* 如果error在绝大多数情况下为0(假)*/
if (unlikely(error)) {
/* ...*/
}
/* 如果success在绝大多数情况下不为0(真)*/
if (likely(success)) {
/* ...*/
}
因为内核是最低层的程序,所以如果内核访问的非法内存,那么整个系统都会挂掉!!所以内核开发的风险比用户程序开发的风险要大。
而且,内核中的内存是不分页的,每用一个字节的内存,物理内存就少一个字节。所以内核中使用内存一定要谨慎。
4.4 不使用浮点数内核不能完美的支持浮点操作,使用浮点数时,需要人工保存和恢复浮点寄存器及其他一些繁琐的操作。
4.5 内核栈容积小且固定内核栈的大小有编译内核时决定的,对于不用的体系结构,内核栈的大小虽然不一样,但都是固定的。
查看内核栈大小的方法:
ulimit -a | grep "stack size"
4.6 同步和并发Linux是多用户的操作系统,所以必须处理好同步和并发操作,防止因竞争而出现死锁。
4.7 可移植性Linux内核可用于不用的体现结构,支持多种硬件。所以开发时要时刻注意可移植性,尽量使用体系结构无关的代码。