啥事 ko?
ko(Kernel Object)
是Linux内核中的可加载模块,它可以动态地向内核添加功能。在运行时,可以通过加载或卸载ko模块来扩展或减少内核功能。
我们可以通过编写内核模块扩展内核功能,添加新的驱动程序或文件系统,或者修改内核的行为,而不需要重新编译整个内核。
基本步骤
- 编写模块代码:包括初始化和清除函数,以及其他需要的函数。
- 编写Makefile文件:定义编译模块的规则,指定编译器和编译选项等。
- 编译模块:使用make命令编译模块,生成ko文件。
- 查看模块信息:使用modinfo命令查看模块的信息,包括作者、版本、描述等。
- 加载模块:使用insmod命令加载模块。
- 卸载模块:使用rmmod命令卸载模块。
示例代码
1、demo.c
KLOGS_ERR
封装了一次 printk() 函数。KERN_ERR
应该是内核的一种输出类型,类似的还有KERN_INFO
、KERN_DEBUG
。int __init hello_init(void)
是初始化函数void __exit hello_exit(void)
是清理函数
为什么不用 C 的库函数输出?
因为 ko 就是跑在内核里边的,没有标准的C库函数。(我猜的)
#include <linux/init.h> //头文件信息
#include <linux/module.h>
#define KLOGS_ERR(fmt, args...) do { \
struct timespec64 ts; \
struct tm tm; \
ktime_get_real_ts64(&ts); \
time64_to_tm(ts.tv_sec, 0, &tm); \
printk(KERN_ERR "[%04ld-%02d-%02d %02d:%02d:%02d][timer_demo]:" fmt "\n", \
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \
tm.tm_hour, tm.tm_min, tm.tm_sec, ##args); \
} while(0)
static int __init hello_init(void) //初始化函数
{
KLOGS_ERR("Hello World!");
return 0;
}
static void __exit hello_exit(void) //清理函数
{
KLOGS_ERR("Good Bye World!");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL"); //表明该模块的源代码使用 GPL 许可证,可以在 GPL 许可证下被复制、修改和重新发布。如果模块没有正确声明许可证,那么它将被认为是专有软件,从而可能违反 GPL 许可证的条款。
MODULE_AUTHOR("wyt"); //作者信息
MODULE_DESCRIPTION("How to write a ko demo."); //内核模块描述
2、Makefile
在 Makefile 中赋值,尽量使用:=
或者+=
,因为=
会将Makefile展开,获取到的值是最后计算完成的值。
M=
:指定模块所需源码的所在目录。-C
:将工作目录,转移至指定目录。(一般转移至当前系统正在运行的内核的源代码目录)modules
:不懂,但是写内核模块就要加这个属性。
注意:make 命令之前不能有空格,一定要用 tab。
obj-m := demo.o #内核模块名字,即生成demo.ko。demo是模块名,也是.c的文件名
KDIR := /lib/modules/$(shell uname -r)/build #指向当前系统正在运行的内核的源代码目录
PWD := $(shell pwd) #当前路径
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
编译KO,并查看模块信息
[root@w ko_demo]# make
make -C /lib/modules/5.10.0-182.0.0.95.oe2203sp3.x86_64/build M=/ko_demo modules
make[1]: Entering directory '/usr/src/kernels/5.10.0-182.0.0.95.oe2203sp3.x86_64'
CC [M] /ko_demo/demo.o
MODPOST /ko_demo/Module.symvers
CC [M] /ko_demo/demo.mod.o
LD [M] /ko_demo/demo.ko
make[1]: Leaving directory '/usr/src/kernels/5.10.0-182.0.0.95.oe2203sp3.x86_64'
[root@w ko_demo]# modinfo demo.ko
filename: /ko_demo/demo.ko
description: How to write a ko demo.
author: w
license: GPL
srcversion: DF352F197303CAAD611B0F1
depends:
retpoline: Y
name: demo
vermagic: 5.10.0-182.0.0.95.oe2203sp3.x86_64 SMP mod_unload modversions
运行KO
首先将 ko 文件传输到本地,然后传输至目标机。
确认当前编译环境内核版本,发现与ko版本一致,则可直接在目标机上运行ko文件。
[root@localhost w]# uname -r
5.10.0-182.0.0.95.oe2203sp3.x86_64
修改 ko 文件的读写权限。
[root@localhost w]# chmod 777 demo.ko
[root@localhost w]# ll
-rwxrwxrwx. 1 root root 64408 Aug 23 17:53 demo.ko
新建窗口使用dmesg
打开内核日志。
[root@localhost w]# dmesg -Hw
- -H:把时间戳修改为人能看懂的年月日
- -w:持续跟踪新的内核消息,直到退出
插入模块。
insmod demo.ko
拔出模块。
rmmod demo.ko
通过下图可以看到,内核消息同步输出了 Error 类型的日志。