模块和应用程序的区别
模块 | 应用程序 |
init_module 为入口函数 | main入口函数 |
cleanup_module | return |
被动调用 | 主动执行 |
内核空间 | 用户空间 |
系统调用 | 库函数、系统调用 |
Printk | printf |
权限要求高 | 权限要求低 |
源程序
这是一个最简单的内核模块程序,以后的内核程序就是从这里扩展。
// 1. 包含头文件
#include <linux/module.h>
//添加模块信息,不加也行
//标明遵循 GPL 协议,
MODULE_LICENSE("GPL");
//模块编写作者信息
MODULE_AUTHOR("ssss, ssss1122@ssss.com,185XXXXXXX");
//模块功能描述
MODULE_DESCRIPTION("this a driver for XXXX device");
// 2. 模块入口函数实现 返回值为int
int init_mymodule(void)
{ //在内核模块编程中 打印函数为 printk()
// 打印输出信息,这个信息只有在控制台 输入命令 dmesg | tail
printk("hello, enter mymodule\n");
return 0;
}
// 3. 模块出口函数实现,返回值必须为void
void exit_mymodule(void)
{ //在内核模块编程中 打印函数为 printk()
// 打印输出信息,这个信息只有在控制台 输入命令 dmesg | tail
printk("hello, exit mymodule\n");
}
// 4. 这里是对内核这个内核模块函数的入口声明。
module_init(init_mymodule);
// 5. 这里是对内核模块出口函数的声明
module_exit(exit_mymodule);
Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
else
obj-m := mymodule.o
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
编译内核模块
linux@ubuntu:$ make
make -C /lib/modules/3.2.0-29-generic-pae/build M=/home/linux/DriverDemo/module_base modules
make[1]: Entering directory `/usr/src/linux-headers-3.2.0-29-generic-pae'
CC [M] /home/linux/DriverDemo/module_base/mymodule.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/linux/DriverDemo/module_base/mymodule.mod.o
LD [M] /home/linux/DriverDemo/module_base/mymodule.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.2.0-29-generic-pae'
加载内核模块
linux@ubuntu:$ sudo insmod ./mymodule.ko
检查是否已经加载
linux@ubuntu:$ lsmod | grep mymodule
mymodule 12421 0 /*这里已经显示我们编译的内核模块已经加载到当前内核中*/
linux@ubuntu:$ dmesg | tail /*使用dmesg查看内核打印信息,一般的新加载的内核信息会在最后*/
[ 21.007173] ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 21.007262] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 21.415989] init: tftpd-hpa main process (1419) terminated with status 66
[ 21.416015] init: tftpd-hpa main process ended, respawning
[ 71.494568] audit_printk_skb: 21 callbacks suppressed
[ 71.494571] type=1400 audit(1588024692.001:24): apparmor="DENIED" operation="open" parent=1 profile="/usr/lib/telepathy/mission-control-5" name="/usr/share/gvfs/remote-volume-monitors/" pid=3074 comm="mission-control" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[87122.587690] [0]: VMCI: Updating context from (ID=0xffffffff) to (ID=0xb64eaa40) on event (type=0).
[100701.280414] [0]: VMCI: Updating context from (ID=0xb64eaa40) to (ID=0xb64eaa40) on event (type=0).
[139493.831559] [2173]: VMCI: Updating context from (ID=0xb64eaa40) to (ID=0xb64eaa40) on event (type=0).
[155503.674251] hello, enter mymodule /*这里就是我们的内核模块入口输出信息*/
卸载内核模块
linux@ubuntu:$ sudo rmmod mymodule /*卸载内核模块*/
linux@ubuntu:~/DriverDemo/module_base$ dmesg | tail /*使用dmesg查看内核打印输出信息*/
[ 21.007262] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[ 21.415989] init: tftpd-hpa main process (1419) terminated with status 66
[ 21.416015] init: tftpd-hpa main process ended, respawning
[ 71.494568] audit_printk_skb: 21 callbacks suppressed
[ 71.494571] type=1400 audit(1588024692.001:24): apparmor="DENIED" operation="open" parent=1 profile="/usr/lib/telepathy/mission-control-5" name="/usr/share/gvfs/remote-volume-monitors/" pid=3074 comm="mission-control" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[87122.587690] [0]: VMCI: Updating context from (ID=0xffffffff) to (ID=0xb64eaa40) on event (type=0).
[100701.280414] [0]: VMCI: Updating context from (ID=0xb64eaa40) to (ID=0xb64eaa40) on event (type=0).
[139493.831559] [2173]: VMCI: Updating context from (ID=0xb64eaa40) to (ID=0xb64eaa40) on event (type=0).
[155503.674251] hello, enter mymodule /*刚刚的内核模块加载输出信息*/
[155605.563102] hello, exit mymodule /*内核模块退出输出信息*/
linux@ubuntu:$ lsmod | grep mymodule /*已经卸载了内核模块*/