之前我们写的代码都是直接编译到内核中,这样每次都要进行内核的重新编译,并且还要刷机才能够看到效果,很是麻烦.这回我们来学习一下如何直接编译一段代码,以模块的方式安装到内核执行:
一个文件编译成一个内核模块:
找一个文件夹: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
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);
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");