2021-Linux程序设计-Lec4-Kernel Driver
Lec4-Kernel Driver
1. Linux内核简介
- 什么是内核
- 操作系统是一系列程序的集合,其中最重要的部分构成了内核
- 单内核/微内核
- 单内核是一个很大的进程,内部可以分为若干模块,运行时是一个独立的二进制文件,模块间通讯通过直接调用函数实现
- 微内核中大部分内核作为独立的进程在特权下运行,通过消息传递进行通讯
- Linux内核的能力
- 内存管理,文件系统,进程管理,多线程支持,抢占式,多处理支持
- Linux内核区别于其他UNIX商业内核的优点
- 单内核,模块支持
- 免费/开源
- 支持多种CPU,硬件支持能力非常强大
- Linux开发者都是非常出色的程序员
- 通过学习Linux内核的源码可以了解现代操作系统的实现原理
2. 层次结构

3. 内核源代码获取
- https://www.kernel.org/
- apt-get方式
- apt-cache search linux-source //查看内核版本
- apt-get install linux-source-3.2
- 下载下来的位置一般在/usr/src
- 从Ubuntu的源码库中获得内核源码
- git clone git://kernel.ubuntu.com/ubuntu/ubuntuhardy.git
3.1. 后续操作
- 解压:tar jxvf /home/ldd/linux-3.2.tar.bz2
- 清除先前编译产生的目标文件:make clean
- 配置内核:make menuconfig
3.2. 编译选项
- 内核组件
- Y(*) 要集成该组件
- N() 不需要该组件,以后会没有这项功能
- M 以后再加该组件为一个外部模块
3.3. 编译内核
- make
- make zImage
- make bzImage
- make modules
3.4. 启用新内核
- make install(慎用)
- 将编译好的内核copy到/boot
- 配置引导菜单
3.5. 初始化程序的建立
- initrd
- mkinitrd /boot/initrd.img $(uname -r)
- initramfs
- mkinitramfs -o /boot/initrd.img 2.6.24-16
- update-initramfs -u
3.6. Debian和Ubuntu的简便办法
- make-kpkg
- 用于make menuconfig之后
- 好处
- 后面所有的部分自动做完
- 会把编译好的内核打成deb安装包
- 可以拷到其它机器安装
3.7. 驱动
- 许多常见驱动的源代码集成在内核源码里
- 也有第三方开发的驱动,可以单独编译成模块.ko
- 编译需要内核头文件的支持
3.8. 加载模块
- 底层命令
- insmod:加载模块
- rmmod:释放模块
- 高层命令
- modprobe
- modprobe -r
3.9. 模块依赖
- 一个模块A引用另一个模块B所导出的符号,我们就说模块B被模块A引用。
- 如果要装载模块A,必须先要装载模块B。否则,模块B所导出的那些符号的引用就不可能被链接到模块A中。这种模块间的相互关系就叫做模块依赖。
3.10. 模块的依赖
- 自动按需加载
- 自动按需卸载
- moddep
- lsmod
- modinfo
3.11. 模块之间的通讯
- 模块是为了完成某种特定任务而设计的。其功能比较的单一,为了丰富系统的功能,所以模块之间常常进行通信。其之间可以共享变量,数据结构,也可以调用对方提供的功能函数。
3.12. 模块相关命令
insmod <module.ko> [module parameters]- Load the module
- 注意,只有超级用户才能使用这个命令
- rmmod
- Unload the module
- lsmod
- List all modules loaded into the kernel
- 这个命令和cat /proc/modules等价
modprobe [-r] <module name>:这个文件是个假文件,如果打印出来,得到的是当前内核加载的模块列表,不可修改、不可删除。- Load the module specified and modules it depends
3.13. Linux内核模块与应用程序的区别

注意点
- 不可以使用C库来开发驱动程序
- 没有内存保护机制
- 小内核栈
- 并发上的考虑
最简单的内核模块例子
1 | |
- static int __init hello_init(void)
- static void __exit hello_exit(void)
- Static声明,因为这种函数在特定文件之外没有其它意义
- __init标记, 该函数只在初始化期间使用。模块装载后,将该函数占用的内存空间释放
- __exit标记 该代码仅用于模块卸载。
- Init/exit
- 宏:module_init/module_exit
- 声明模块初始化及清除函数所在的位置
- 装载和卸载模块时,内核可以自动找到相应的函数
- module_init(hello_init);
- module_exit(hello_exit);
编译内核模块
- Makefile文件
1 | |
- Module includes more files
1 | |
和硬件打交道
1 | |
2021-Linux程序设计-Lec4-Kernel Driver
https://spricoder.github.io/2021/05/03/2021-Linux-Programming/2021-Linux-Programming-Lec4-Kernel%20Driver/