06-Linux内核
1. 编译内核
有很多复杂的configure
- 配置
- make
- 启用内核
1.1. 编译选项
- config模式
- Y:加入内核
- N:不加入内核
- M:模块形式,先留一个地址,
.ko
文件。需要功能的时候可以去加载。
1.2. 启用新内核
- make install:把内核复制到\boot目录下
- 慎用,一般手动做这个操作
grub的引导菜单会多一个刚编译的内核
1.3. 初始化程序的建立
- initrd
- 系统启动时的第一个用户态程序,没有父进程的进程
2. 驱动
常见驱动的源代码集成在内核源码中
也有第三方驱动的开发,可以单独编译成模块.ko
编译需要内核头文件的支持
2.1. 加载模块
系统开机时没有加载,但可以在运行的时候加载模块
e.g. U盘驱动
- 底层命令
- insmod:把模块装载到内核里
- rmmod:从内核里释放模块
- 高层命令
- modprobe:装载
- modprobe -r:释放
2.2. 模块依赖
- lsmod:看当前已经装载到内核的模块
- 和
cat /proc/modules
等价
- 和
- modinfo
- moddep
模块依赖:模块A引用模块B导出的符号,即模块B被模块A引用。如果要装载模块A,就要先装载模块B。
高层命令会解决依赖关系,而底层命令不会。
2.3. 模块通信
- 共享变量
- 调用函数
2.4. 👍Linux内核模块与应用程序模块的区别
C | Linux内核模块 | |
---|---|---|
运行 | 用户空间 | 内核空间 |
入口 | main() | module_init()指定 |
出口 | 无 | module_exit()指定 |
运行 | 直接指定 | insmod |
调试 | gdb | kdbug,kdb,kgdb等 |
- 内核模块其实并不存在入口出口,init做初始化,exit做释放,加载后一直在内存里待命
- 内核模块真正执行的时候是用户态程序调用相关功能
- e.g. 内核加载了一段打印机的驱动,一直在内存里待命,在用户态程序(如Word)里点了打印,这段驱动才会被调用(通过系统调用)
- 要考虑并行会出现的问题,可能有多个用户同时打印
2.5. 内核程序注意事项
- 不能调用C库来开发驱动程序
- 没有内存保护机制
- 小内核栈
- 内核一般不用递归否则会占用大量内存空间
- 并发考虑
- 内核代码/Shell脚本没有类型浮点支持
1 |
|
2.6. 编译
内核Makefile和一般的不一样,而且经常更新
2.7. 模块参数传递
- 传递方式
- 参数在模块加载时传递
- shell:
insmod hello.ko test=2
- shell:
- 参数需要使用module_param宏来声明
module_param(变量名称,类型, 访问许可掩码)
- 参数在模块加载时传递
- 支持参数类型
- Byte, short, ushort, int, uint, long, ulong, bool, charp
- Array (module_param_array(name, type, nump, perm))
1 |
|
3. 字符型设备
3.1. 驱动程序的初始化加载过程
- 申请设备号
- 定义文件操作结构体 file_operations
- 创建并初始化定义结构体 cdev
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
void cdev_init(struct cdev *cdev, struct file_operations *fops);
和2功能差不多。
- 将cdev注册到系统,并和对应的设备号绑定
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
- 在/dev文件系统中用mknod创建设备文件,并将该文件绑定到设备号上
mknod {{path/to/device_file}} c {{major_device_number}} {{minor_device_number}}
3.2. 主设备号和次设备号
- 一个字符设备或者块设备都有一个主设备号和次设备号。
- 主设备号和次设备号统称为设备号。
- 主设备号用来表示一个特定的驱动程序。
- 次设备号用来表示使用该驱动程序的各设备。
3.3. 应用程序调用驱动
- 加载设备驱动:应用程序需要加载一个驱动模块(.ko文件),这个过程会生成一个设备文件,该文件代表了驱动程序控制的硬件设备或本地设备
- 打开设备文件:应用程序使用系统提供的函数(如
open()
)来打开设备文件。这些函数最终会通过内核转发到相应的驱动函数。每个设备文件都有一个对应的inode结构体,包含了设备的主次设备号,是设备的唯一标识 - 执行系统调用:应用程序通过执行系统调用(如
read()
,write()
,ioctl()
等)与设备驱动进行交互。这些调用最终会通过内核转发到相应的驱动函数
- 标题: 06-Linux内核
- 作者: Charlie
- 创建于 : 2024-05-13 11:05:00
- 更新于 : 2024-07-05 12:55:04
- 链接: https://chillcharlie357.github.io/posts/612388c4/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论