Write Simple Kernel Module
编写简单的HelloWorld Kernel Module
普通的用户态下的C编程,估计很多人都可以熟练编写掌握。但是跨入内核层之后,用户态的函数与头文件统统变了。
首先我们要更改头文件,然后编写代码
#include <\linux/module.h>
#include <\linux/kernel.h>
#include <\linux/init.h>
static int __init lkp_init(void)
{
printk("Hello,world from module!\n");
return 0;
}
static void __exit lkp_exit(void)
{
printk("Goodbye,from module!\n");
}
module_init(lkp_init);
module_exit(lkp_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lzz");
MODULE_DESCRIPTION("hello");
MODULE_VERSION("prink");
__init __exit 表示一种初始化的宏,编译器将标__init的所有代码存在特殊的内存段中,初始化结束后就释放这段内存。
Makefile:
obj-m:= hello_module.o
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/lib/modules/$(LINUX_KERNEL)/build
all:#记住make之前是tab,要不编译不过去
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
这与我们一般的头文件不同。一般我们在用户态下编写C程序,头文件会放在:/usr/include/下。
而我们模块编程时,它使用的是内核中的头文件。一般在fedora下:cd /lib/modules/$(LINUX_KERNEL)/build。
build下有include/ 然后这个目录下linux/这个子目录中的头文件,因此模块编译的时候会自动在内核中的include/目录下找linux/kernel.h这样的头文件。
其次,printf到printk是一个典型的用户态下编程与内核模块编程的不同。可能我们一开始会比较奇怪,为什么我make成功,加载也成功,但是就是不能显示printk里面的语句呢?我们可以这么想printk就是专门为内核“服务”。它一般输出的语句都在内核的日志文件当中。
#insmod hello_world.ko
#dmesg | tail //查看
#rmmod hello_world.ko //卸载