• 编写内核模块及安装查看卸载过程


    之前我们写的代码都是直接编译到内核中,这样每次都要进行内核的重新编译,并且还要刷机才能够看到效果,很是麻烦.这回我们来学习一下如何直接编译一段代码,以模块的方式安装到内核执行:

      一个文件编译成一个内核模块:

      找一个文件夹:touch module_test1.c Makefile

      vim module_test1.c

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 
      5 //当模块安装的时候执行
      6 static __init int test_init(void)
      7 {
      8         printk("test_init
    ");
      9         return 0;
     10 }
     11 //当模块卸载的时候执行
     12 static __exit int test_exit(void)
     13 {
     14         printk("test_exit
    ");
     15         return 0;
     16 }
     17 //注册这两个函数
     18 module_init(test_init);
     19 module_exit(test_exit);
     20 //声明开源规则
     21 MODULE_LICENSE("GPL");

      vim Makefile

      1 LINUX_SRC :=/home/liuye/tiny4412/FriendlyARM_kernel/linux-3.5  #指定我们板子上用的内核路径,使用这个内核编译的代码才能成功运行在我们的板子上.
      2 obj-m   += module.o            #生成module.ko   但我们写module.o就可以
      3 module-objs=module_test1.o     #这里写要编译文件
      4 #obj-m +=module_test1.o        #这是单文件的编译:上面两行是多文件的编译,更加方便
      5 
      6 all:
      7         make -C $(LINUX_SRC) M=`pwd` modules
      8 clean:
      9         make -C $(LINUX_SRC) M=`pwd` modules clean

      make  生成 module.ko

      cp module.ko /myroot/liuye     即nfs共享路径下   运行看下效果吧

    root@board liuye_dir#insmod module.ko 
    [ 3817.370000] test_init
    root@board liuye_dir#lsmod
    Module                  Size  Used by    Tainted: G  
    module                   740  0 
    root@board liuye_dir#rmmod module.ko 
    [ 3821.550000] test_exit
    root@board liuye_dir#

     /*****************************************************************************************************************************************************************************************************/

    多个文件编译成一个内核模块:

      touch module_test1.c module_test2.c Makefile

      vim module_test1.c 调用module_test2.c内的函数 

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 //内核代码中不允许有警告,因为在编译的时候可能是警告,但是在逻辑尚有可能是个错误
      5 extern int my_print(int no);
      6 //当模块安装的时候执行
      7 static __init int test_init(void)
      8 {
      9         printk("test_init
    ");
     10         my_print(5);
     11         return 0;
     12 }
     13 //当模块卸载的时候执行
     14 static __exit int test_exit(void)
     15 {
     16         printk("test_exit
    ");
     17         return 0;
     18 }
     19 //注册这两个函数
     20 module_init(test_init);
     21 module_exit(test_exit);
     22 //声明开源规则
     23 MODULE_LICENSE("GPL");

      vim module_test2.c

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 int my_print(int no)
      5 {
      6         int i;
      7         for(i=0;i<no;i++)
      8         {
      9                 printk("no=%d
    ",no);
     10         }
     11         return 100;
     12 }

      vim Makefile

      1 LINUX_SRC :=/home/liuye/tiny4412/FriendlyARM_kernel/linux-3.5
      2 obj-m   += module.o            #生成module.ko   但我们写module.o就可以
      3 module-objs=module_test1.o  module_test2.o   #这里写要编译的文件
      4 #obj-m +=module_test1.o        #这是单文件的编译:上面两行是多文件的编译,更加方便
      5 
      6 all:
      7         make -C $(LINUX_SRC) M=`pwd` modules
      8 clean:
      9         make -C $(LINUX_SRC) M=`pwd` modules clean

      make  生成module.ko 到开发板上安装查看卸载  

    root@board liuye_dir#insmod module.ko 
    [ 5324.040000] test_init
    [ 5324.040000] no=5
    [ 5324.040000] no=5
    [ 5324.040000] no=5
    [ 5324.040000] no=5
    [ 5324.040000] no=5
    root@board liuye_dir#lsmod
    Module                  Size  Used by    Tainted: G  
    module                   913  0 
    root@board liuye_dir#rmmod module.ko 
    [ 5327.515000] test_exit
    root@board liuye_dir#

     /*****************************************************************************************************************************************************************************************************/

    多个文件编译成多个内核模块:

      vim module_test1.c

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 //内核代码中不允许有警告,因为在编译的时候可能是警告,但是在逻辑尚有可能是个错误
      5 extern int my_print(int no);
      6 //当模块安装的时候执行
      7 static __init int test_init(void)
      8 {
      9         printk("test_init
    ");
     10         my_print(5);
     11         return 0;
     12 }
     13 //当模块卸载的时候执行
     14 static __exit int test_exit(void)
     15 {
     16         printk("test_exit
    ");
     17         return 0;
     18 }
     19 //注册这两个函数
     20 module_init(test_init);
     21 module_exit(test_exit);
     22 //声明开源规则
     23 MODULE_LICENSE("GPL");

      vim module_test2.c

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 static __init int test_init(void)
      5 {
      6         return 0;
      7 }
      8 static __exit int test_exit(void)
      9 {
     10         return 0;
     11 }
     12 int my_print(int no)
     13 {
     14         int i;
     15         for(i=0;i<no;i++)
     16         {
     17                 printk("no=%d
    ",no);
     18         }
     19         return 100;
     20 }
     21 //模块之间的关系要进行符号导出
     22 //模块1调用了模块2内部的函数my_print,虽然函数之前没有添加static修饰,但是在模块之间调用,相当于的添加了static修饰,所以该函数不支持其他模块的调用,
        只支持当前文件和当前模块的调用.所以模块2安装完成,模块1依然insmod不上,为了解决模块1依赖模块2的问题,所以要进行符号导出.
        我们写的驱动程序都需要调用内核提供的方法,内核里面的方法都是经过符号导出的.
    23 //其中module_init和module_exit是宏实现的:宏定义在:#include<linux/module.h>中 24 EXPORT_SYMBOL(my_print); 25 module_init(test_init); 26 module_exit(test_exit); 27 MODULE_LICENSE("GPL"); ~

      vim Makefile

      1 LINUX_SRC :=/home/liuye/tiny4412/FriendlyARM_kernel/linux-3.5
      2 #obj-m  += module.o            #生成module.ko   但我们写module.o就可以
      3 #module-objs=module_test1.o  module_test2.o   #这里写要编译文件
      4 obj-m +=module_test1.o module_test2.o       #这是单文件的编译会生成多个ko:上面两行是多文件的编译,更加方便
      5 
      6 all:
      7         make -C $(LINUX_SRC) M=`pwd` modules
      8 clean:
      9         make -C $(LINUX_SRC) M=`pwd` modules clean

      在安装的时候要先安装模块2在安装模块一,在卸载的时候要先卸载模块1再卸载模块2;

      解释depmod:请参见另一片文章

      modprobe:

      以及内核传参数的代码请查看另一篇文章:

     /*****************************************************************************************************************************************************************************************************/

      1 LINUX_SRC :=/home/liuye/tiny4412/FriendlyARM_kernel/linux-3.5
      2 #obj-m  += module.o            #生成module.ko   但我们写module.o就可以
      3 #module-objs=param.o     #这里写要编译文件
      4 obj-m +=param.o param1.o       #这是单文件的编译:上面两行是多文件的编译,更加方便
      5 
      6 all:
      7         make -C $(LINUX_SRC) M=`pwd` modules
      8 clean:
      9         make -C $(LINUX_SRC) M=`pwd` modules clean
    makefile
      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 
      5 static __init int test1_init(void)
      6 {
      7         printk("this is liuye test1_init
    ");
      8         return 0;
      9 }
     10 static __exit void test1_exit(void)
     11 {
     12         printk("this is liuye test1_exit
    ");
     13 }
     14 
     15 module_init(test1_init);
     16 module_exit(test1_exit);
     17 MODULE_LICENSE("GPL");
     18 void my_print(int no)
     19 {
     20         printk("no = %d
    ",no);
     21 }
     22 EXPORT_SYMBOL(my_print);
    param1.c
      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/sched.h>
      4 extern void my_print(int name);
      5 
      6 int name=0;
      7 char *buf;
      8 bool boolc;
      9 int arr[10];
     10 int len;
     11 //module_param_named(name,name,int,0);
     12 //module_param_named(buf,buf,charp,0);
     13 //module_param_named(boolc,boolc,bool,0);
     14 
     15 module_param(name,int,0660);
     16 module_param(buf,charp,0660);
     17 module_param(boolc,bool,0660);
     18 module_param_array(arr,int,&len,0660);
     19 static __init int test_init(void)
     20 {
     21         int i;
     22         printk("this is liuye test_init
    ");
     23 //      my_print(name);
     24         printk("name =%d
    ",name);
     25         printk("buf =%s
    ",buf);
     26         printk("boolc =%d
    ",boolc);
     27         for(i=0;i<len;i++)
     28         {
     29                 printk("arr[%d]=[%d]
    ",i,arr[i]);
     30         }
     31         printk("len =%d
    ",len); //这里的长度,等于实际输入的数组元素个数
     32         my_print(333333)        
     33         return 0;
     34 } 
     35 static __exit void test_exit(void)
     36 {
     37         int i;
     38         printk("this is liuye test_exit
    ");
     39 //      my_print(name);
     40         printk("name =%d
    ",name);
     41         printk("buf =%s
    ",buf);
     42         printk("boolc =%d
    ",boolc);
     43         for(i=0;i<len;i++)
     44         {
     45                 printk("arr[%d]=[%d]
    ",i,arr[i]);
     46         }
     47         printk("len =%d
    ",len); //这里的长度,等于实际输入的数组元素个数
     48         
     49 }
     50 
     51 module_init(test_init);
     52 module_exit(test_exit);
     53 MODULE_LICENSE("GPL");
    param.c
    有时候,不小心知道了一些事,才发现自己所在乎的事是那么可笑。
  • 相关阅读:
    Kafka 再均衡监听器示例
    Spring boot中异步线程池
    【Java&Go并发编程系列】4.等待一组并发任务完成——CountDownLatch VS sync.WaitGroup
    Redis常用命令对应到Redisson对象操作
    js清空缓存,ajax
    phpexcel用法 转、
    composer 使用
    转:git操作
    手机微信内支付
    微信扫码支付
  • 原文地址:https://www.cnblogs.com/axjlxy/p/8964637.html
Copyright © 2020-2023  润新知