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

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

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

  找一个文件夹: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
有时候,不小心知道了一些事,才发现自己所在乎的事是那么可笑。
原文地址:https://www.cnblogs.com/axjlxy/p/8964637.html