Linux内核模块入门 Hello, World!

/*
* hello.c – The Hello, World! Kernel Module 
*/
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h>

/*
* hello_init – the init function, called when the module is loaded. * Returns zero if successfully loaded, nonzero otherwise.
*/
static int hello_init(void) {
        printk(KERN_ALERT “I bear a charmed life.\n”); return 0;
}
/*
* hello_exit – the exit function, called when the module is removed. */
static void hello_exit(void) {
        printk(KERN_ALERT “Out, out, brief candle!\n”);
}
module_init(hello_init); 
module_exit(hello_exit);
MODULE_LICENSE(“GPL”); 
MODULE_AUTHOR(“Shakespeare”); 
MODULE_DESCRIPTION(“A Hello, World Module”);

先看最后5行

  • module_init实际上并不是一个函数,而是一个宏macro。它的作用是在编译时把hello_init作为这个内核模块的初始化函数。
    *module_exit是在内核模块时调用hello_exit来做收尾工作。
  • MODULE_LICENSE 指明这个内核模块采用的许可证。如果你采用非GPL协议,那么编译内核时将提示,并且非GPL模块无法调用GPL symbol。这里涉及到法律因素,详细情况请了解GPL协议。
  • MODULE_AUTHOR 指明这个内核模块的作者。
  • MODULE_DESCRIPTION 是你对这个内核模块的简要描述。

hello_init

  • 内核模块的初始化函数无参数,返回值为int
  • 你必须返回0值来告知内核:“模块初始化成功”。返回非0值则表示模块初始化失败,内核将不会继续加载这个模块,同时你一定要做好清理工作(比如释放已经申请的内存、恢复硬件状态等等)。
  • 由于内核模块的初始化函数通常不会直接被外部调用,因此你可以标记它为static

hello_exit

  • 内核模块的退出函数同样是无参数,返回值为int
  • 你需要做各种清理工作。
  • 同样的,你可以考虑将它标记为static
  • 如果这个模块并不是单独编译为模块,而是直接静态编译到内核中,则退出函数不会也不需要被编译进去,因为它无法被卸载。

总结

Linux内核模块其实是非常简单的,并非想象中那么难。你只需要指明入口函数和出口函数,然后专注于实现具体的功能。