美文网首页
内核模块学习

内核模块学习

作者: 为瞬间停留 | 来源:发表于2018-01-04 15:28 被阅读28次

    linux内核的框架很大,组件很多,如果把所有东西全编译进内核,内核会很大,如果我们要进行修改时,还要重新编译内核,耗时费力.linux的模块机制解决了这样的问题,模块本身不编译进内核,控制了内核的大小,模块一旦被加载,和内核中其他部分一样.

    一.简单的例子

    说的多,不如贴代码,一个简单的例子程序如下:

    /*bike.c*/
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    
    
    static char * bike_name = "mobike";
    module_param(bike_name,charp,S_IRUGO);
    
    static int bike_num = 3000;
    module_param(bike_num,int,S_IRUGO);
    
    static int __init bike_init(void)
    {
        printk(KERN_INFO "hello bike module\n");
        printk(KERN_INFO "bike-name:%s\n",bike_name);
        printk(KERN_INFO "bike_num:%d\n",bike_num);
        return 0;
    }
    module_init(bike_init);
    
    static void __exit bike_exit(void)
    {
        printk(KERN_INFO "bike module exit\n");
    }
    module_exit(bike_exit);
    
    MODULE_AUTHOR("Trice");
    MODULE_LICENSE("GPL v2");
    MODULE_DESCRIPTION("A simple program for testing kernel module");
    MODULE_VERSION("V1.0");
    

    一个内核模块主要由:
    1.模块加载函数
    2.模块卸载函数
    3.模块声明
    4.模块参数(可选)
    5.模块作者(可选)


    模块加载函数

    static int __init bike_init(void)
    {
        printk(KERN_INFO "%s\n",bike_name);
        printk(KERN_INFO "%d\n",bike_num);
        return 0;
    }
    module_init(bike_init);
    

    linux中,标识为__init的函数如果直接编译进内核,连接时会放在.init.text段,初始化时,内核会调用这些__init函数,完成后释放.类似数据可以标识为__initdata.
    所以bike_init以__init标识,加载时用module_init指定.


    模块卸载函数

    static void __exit bike_exit(void)
    {
        printk(KERN_INFO "bike module exit\n");
    }
    module_exit(bike_exit);
    

    卸载函数用__exit标识,用module_exit指定


    模块声明

    MODULE_AUTHOR("Trice");
    MODULE_LICENSE("GPL v2");
    MODULE_DESCRIPTION("A simple program for testing kernel module");
    MODULE_VERSION("V1.0");
    

    声明一些信息,其中MODULE_LICENSE("GPL v2");声明模块的许可权限.


    模块参数

    static char * bike_name = "mobike";
    module_param(bike_name,charp,S_IRUGO);
    
    static int bike_num = 3000;
    module_param(bike_num,int,S_IRUGO);
    

    使用module_param(参数名,类型,参数读写权限),charp表示字符指针,传递时采用insmod 模块名 参数名=参数值,S_IRUGO,表示读,U->user G->group O->other.


    二.模块的编译

    上面的bike.c可以用下面的Makefile进行编译

    KVERS = $(shell uname -r)
    
    #kernel module
    obj-m += bike.o
    
    
    build:kernel_modules
    
    kernel_modules:
        make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
    
    clean:
        make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
    

    obj-m += bike.o这种在内核编译中很常见,意思把bike.c编成模块,进入相应目录使用里面Makefile进行编译,M=$(CURDIR)指定目标.
    如果有多个文件可以使用:

    obj-m := xx.o
    xx-objs := file1.o file2.o
    

    三.测试结果

    huang@ubuntu:~/test$ ls
    bike.c  Makefile
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ make
    make -C /lib/modules/3.16.0-30-generic/build M=/home/huang/test modules
    make[1]: Entering directory `/usr/src/linux-headers-3.16.0-30-generic'
      CC [M]  /home/huang/test/bike.o
      Building modules, stage 2.
      MODPOST 1 modules
      CC      /home/huang/test/bike.mod.o
      LD [M]  /home/huang/test/bike.ko
    make[1]: Leaving directory `/usr/src/linux-headers-3.16.0-30-generic'
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ ls
    bike.c   bike.mod.c  bike.o    modules.order
    bike.ko  bike.mod.o  Makefile  Module.symvers
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ sudo insmod bike.ko
    huang@ubuntu:~/test$ lsmod | grep bike
    bike                   12665  0 
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ dmesg | tail -3
    [19695.556447] hello bike module
    [19695.556453] bike-name:mobike
    [19695.556456] bike_num:3000
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ sudo rmmod bike
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ lsmod | grep bike
    huang@ubuntu:~/test$ 
    huang@ubuntu:~/test$ dmesg | tail -1
    [19804.797345] bike module exit
    huang@ubuntu:~/test$ sudo insmod bike.ko bike_name=ofo bike_num=666
    huang@ubuntu:~/test$ dmesg | tail -3
    [20692.083907] hello bike module
    [20692.083913] bike-name:ofo
    [20692.083915] bike_num:666
    huang@ubuntu:~/test$ sudo rmmod bike;dmesg | tail -1
    [20760.653996] bike module exit
    

    insmod rmmod lsmod分别用于装载 卸载 查看模块
    dmesg用于显示打印信息
    tail -n显示最后n行

    四.总结

    内核模块只是把.c文件编译成.ko文件,其实就是一种目标文件的形式,然后在装载时,由内核实现模块的链接运行,同时,在内核加载和卸载的过程中,会通过函数回调用户定义的模块入口函数和模块出口函数,实现相应的功能。

    相关文章

      网友评论

          本文标题:内核模块学习

          本文链接:https://www.haomeiwen.com/subject/ldxrnxtx.html