前言
认真阅读源码很重要,应该钻研并尝试着手改一些代码,寻找一个bug然后去修改它,改进你的硬件设备的驱动程序
第一章 linux内核简介
1.1 unix的历史
unix特点:
- 简洁
- 所有东西都被当做文件对待,通过一套相同的系统调用接口
- C语言编写,硬件移植能力强
- 进程创建迅速,独特的fork()系统调用
- 简单而稳定的进程间通信元语
1.3 操作系统和内核简介
操作系统:指系统中负责完成最基本功能和系统管理的部分。包括:内核、设备驱动程序、启动引导程序、命令行shell或其他种类的用户界面、基本的文件管理和系统工具。
内核组成:中断服务程序、进程调度程序、内存管理程序、网络/进程间通信等。许多OS的中断服务程序,包括linux的,都不在进程上下文中执行,在一个与所有进程无关的、专门的中断上下文中运行。
应用程序通过系统调用与内核通信。
1.4 linux内核和传统unix内核比较
- linux支持动态加载内核模块
- linux支持对称多处理机制(SMP)
- linux内核可抢占
- linux对线程的支持:内核不区分线程与其他一半的进程。
- linux提供设备类的面向对象设备模式、热插拔,以及用户空间的设备文件系统(sysfs)
1.5 linux内核版本
内核有两种:稳定的和处于开发中的。
主版本号.从版本号(偶数稳定,奇数不稳定).修订版本号.稳定版本号
不过后来的版本不遵守这个了,比如4.16-rc6表示非稳定,4.16.0才是稳定
第二章 从内核出发
- /usr/src/linux目录
- 内核源码树:…
- 编译内核
配置内核:**make menuconfig**
/ make gconfig, make defconfig会基于默认配置创建,make oldconfig的作用是备份当前.config文件为.config.old,如若make config/menuconfig设置不当可用于恢复先前的.config。 make -jn
- 安装新内核:将arch/i386/boot/bzImage拷贝到/boot目录下,像vmlinuz-version命名它,编辑/etc/grub/grub.conf文件,为新内核建立新的启动项(目前OS可省略这一步)
make modules_install
,将所有已编译的模块安装到正确的主目录/lib/modules下- 编译时,也会在内核源码树的根目录下创建一个
System.map
,这是一个符号对照表,将内核符号和他们的起始地址对应起来。
2.4 内核开发特点
- 内核编程不能访问C库也不能访问标准C的头文件
- 内核编程必须使用GNU C
- 缺乏用户空间的内存保护机制
- 难以执行浮点运算
- 每个进程只有很小的定长堆栈
- 内核支持异步中断、抢占、SMP,必须时刻注意同步和并发
-
头文件
基本的头文件:include目录(#include <linux/inotify.h>
)
体系结构相关:arch/<architecture>/include/asm目录(#include <asm/ioctl.h>
) -
GNU C
Linux 上可用的 C 编译器是 GNU C 编译器。 GNU C 对标准 C 进行一系列扩展,以增强标准 C 的功能。不符合ANSI C标准,内核开发者总是要用到gcc的拓展部分。内核开发使用的C语言涵盖ISO C99和GNU C扩展特性。内联函数: 对时间要求高,而本身长度较短的函数定义为内联
static inline void wolf(unsigned long tail_size)
需要使用static作为关键字、inline进行限定;内联函数必须在使用前就定义好,否则无法展开(static inline的内联函数,一般情况下不会产生函数本身的代码,而是全部被嵌入在被调用的地方。如果不加static,则表示该函数有可能会被其他编译单元所调用,所以一定会产生函数本身的代码。所以加了static,一般可令可执行文件变小。内核里一般见不到只用inline的情况,而都是使用static inline。)
内联汇编: asm()嵌入汇编在代码
分支声明: likely()和unlikely(),內建指令优化
没有内存保护机制: 内核错误导致oops,内核中的内存都不分页
容积小而固定的栈: 8K或16K
同步和并发: 自旋锁和信号量