一、什么是内核驱动?
内核驱动,是指运行在 Linux 内核空间,由内核直接管理和控制的程序,主要负责和硬件打交道,为上层用户程序提供硬件访问的接口。比如:网卡驱动、显卡驱动、USB 设备驱动、磁盘驱动等等。
简单理解:
用户程序 ←→ 系统调用 ←→ 内核驱动 ←→ 硬件设备
- 内核驱动=硬件与操作系统之间的桥梁
二、什么是内核模块?
内核模块(Kernel Module),是可以被单独编译、按需加载到内核中的一段功能代码。内核模块不仅包括驱动模块,还可以是文件系统、网络协议、扩展功能等。
Linux 内核有两种主要的代码集成方式:
- 内置(Built-in):代码直接被编译进内核本体,开机就加载,不能动态卸载。
- 模块(Module):编译为单独的
.ko文件,可以在系统运行时用insmod、modprobe等命令动态加载/卸载,更加灵活。
大部分硬件驱动都会做成“内核模块”形式,提高灵活性。
三、内核驱动与内核模块的关系
- 内核驱动有两种存在形式:内置驱动、模块驱动(即驱动模块)。
- 底层本质都是 “ 内核代码 ” ,只是在集成方式和使用管理上有区别。
| 类别 | 加载时机 | 是否可卸载 | 文件形式 | 典型命令 |
|---|---|---|---|---|
| 内置驱动 | 启动时 | 否 | 无独立文件 | 编译进内核,烧录内核镜像开机即用 |
| 模块驱动 | 动态或启动时 | 是 | .ko | insmod, modprobe, rmmod |
总结:
我们一般开发时采用模块驱动形式,便于调试和升级。
四、内置驱动测试
我们在上一节中编写了第一个驱动,生成了一个 hello_world.ko 文件,这是内核模块的形式。
这次我们来尝试将这个驱动变为内核驱动,变为内置驱动,首先我们需要在内核目录中找到一个合适的目录中,将我们的这个源码添加进去。
1、内核添加源码
创建一个 02_kernel_helloworld/ 文件夹,具体的路径是:
TaishanPi-3-Linux/kernel-6.1/drivers/02_kernel_helloworld
我们将上一节编写的 hello_world.c 复制到 02_kernel_helloworld/ 这个目录下:
继续在 02_kernel_helloworld/ 目录下创建一个新的 Makefile 文件,并且编写以下的内容:
obj-y += hello_world.o这次非常的简洁,具体原因我们之后进行详细讲解。
我们需要找到 02_kernel_helloworld/ 这个目录上一级的 TaishanPi-3-Linux/kernel-6.1/drivers/Makefile 文件,在其中添加一句:
obj-y += 02_kernel_helloworld/类似于套娃一样,一层套一层,层层的引用。
2、编译内核
可以参考这个这个文档单独编译内核 Debian12单独编译内核
./build.sh kernel出现了 .o 文件,就说明源文件被编译了。
3、烧录内核测试
参考 分散镜像烧录 单独烧录 TaishanPi-3-Linux/kernel-6.1/boot.img 内核镜像。
启动之后我们进入系统,输入下面的命令,搜索日志里面所有和 hello 相关的语句:
dmesg | grep -E hello说明此驱动已经被包含进了内核镜像中了,不需要我们进行手动加载驱动。
五、说明
我们添加内核驱动时,制作的Makefile语句非常的简洁,而且还需要加入上一层的 Makefile 文件中。
这是因为 内置驱动 的编译方式和模块驱动有所不同。
对于模块驱动(生成 ko 文件):
obj-m += hello_world.o而对于内核内置驱动,只需:
obj-y += hello_world.o区别分析:
obj-m:告诉内核编译系统,对象文件要编译成模块(.ko),可以动态加载/卸载。obj-y:告诉内核编译系统,对象文件要作为内核的一部分被编译和链接,不生成独立模块。
内置驱动其编译目标是直接参与整个内核的编译流程,所使用的编译器是更顶层的配置文件决定的。每级目录下的 Makefile 要递归告知 “ 本目录内容要编译 ” ,所以外层 Makefile 也必须加一行:
obj-y += 02_kernel_helloworld/这样内核编译系统会递归进入 02_kernel_helloworld 目录,处理 hello_world.c 源文件。
六、内核源码目录结构和集成流程
Linux 内核采用层层递归编译的方式,目录结构和 Makefile 像“套娃”一样递归引用:
kernel-6.1/
└── drivers/
├── Makefile # 外层汇总
└── 02_kernel_helloworld/
├── Makefile
└── hello_world.c2
3
4
5
6
- 顶层 Makefile(
kernel-6.1/drivers/Makefile)负责收集所有需要编译的子目录和源文件。 - 各子目录 Makefile(如
02_kernel_helloworld/Makefile)负责指定本目录的具体编译目标。 - 编译时,内核会递归查找和编译所有指定的文件,最后整体链接为内核镜像。
这种机制,方便了各个驱动功能的灵活集成和管理,也便于维护和升级。