内核版本:3.4.24
大家发现什么错误一定要告诉我,大家共同学习了;
########## 内核模块 ###########
1.开发阶段,不能每改一次程序就重新编译一次内核,所以我们通过向内核添加模块的方式调试注:a.编译内核时,出现的警告也不能忽略,可能导致大错误
b.向其添加模块的内核必须是正确编译通过的
2.向内核添加模块,必须:
a.与内核版本有关;不能把写好的模块插入到其它版本的内核中
b.与内核配置相关;不能把写好的模块插入到相同版本不同配置的内核中
抢占式内核(2.6板之后的内核支持):
默认不支持,可配置成支持抢占
抢占式内核响应迅速,并且一个进程意外死在内核里不会影响整个内核
3.代码参考/nfsroot/code/01module
vim Makefile //创建 Makefile
--> LINUX_PATH := /home/musesea/arm_class/smdk6410_lzy/src/linux3.4 //内核所在路径
obj-m += module_test.o //编译模块
prefix ?= /home/musesea/nfsroot
//以下格式是固定的
//涵义:告诉内核的Makefile,模块在这,内核的Makefile 来给你编译,并将生成的文件放在这个目录下
all:
make -C $(LINUX_PATH) M=`pwd` modules
//-C:指定编译路径;
//M=`pwd`:模块所在路径,pwd是命令,显示当前路径;
//modules:内核对于编译模块实现的一个宏
//注意,pwd 上的两个单引号是键盘 Tab 键上面的那个键
clean:
make -C $(LINUX_PATH) M=`pwd` modules clean
//modules clean:内核对于删除模块实现的一个宏
install:
make -C $(LINUX_PATH) M=`pwd` modules_install INSTALL_MOD_PATH=$(prefix)
//modules_install:内核对于安装模块实现的宏
//INSTALL_MOD_PATH=$(prefix):将实现的模块安装到变量prefix 定义的路径下
<-- //INSTALL_MOD_PATH:内核实现的宏
=======================================================================================
= make 之后生成xxx.ko 文件就是模块
= make install 后在本目录和创建的根文件系统目录/lib/modules/3.4.24/extra/都会有一个 .ko 文件
= 开发板在成功挂载根文件系统后,执行 insmod xxx.ko 命令即可插入模块
= 成功插入后,lsmod 查看插入的内核模块,会显示
= module_test1 585 0 - Live 0xbf018000 (O)
= 模块名字 模块大小 没有依赖(有依赖会显示个数,紧接着显示被谁依赖) 模块状态 位置
=======================================================================================
vim module_test1.c //编写练习程序
--> //这两个头文件一上来写上就好,宏和函数经常会用到
#include <linux/init.h>
#include <linux/module.h>
//实现来自modules_test2.c
//使用之前必须声明,以后在写C程序的时候在使用的时侯最好也声明,这样在编译的时候会检测函数参数的正确性
void my_printf(int num);
//规则和添加驱动时一样
static __init int module_test_init(void)
{
printk("hello world!\n");
my_printf(100);
return 0;
}
//类型是定死的,类型void,参数void;代码放在exit段,被保留到程序最后,最后执行,执行完释放
static __exit void module_test_exit(void)
{
printk("Bye bye\n");
}
//在插入模块的时候只执行一次
//insmod xxx.ko
module_init(module_test_init);
//在模块删除时执行
//rmmod xxx.ko
//rmmod xxx
module_exit(module_test_exit);
MODULE_LICENSE("GPL"); //开源规则;必须有这句,下面可有可无
MODULE_AUTHOR("musesea"); //声明作者
MODULE_VERSION("1.0"); //声明版本
MODULE_DESCRIPTION("Class test for module");//声明描述
vim module_test2.c //被上面的函数依赖
--> #include <linux/init.h>
#include <linux/module.h>
//普通的函数实现,相当于C语言中写函数,没有固定格式
void my_printf(int num)
{
printk("nihao module %d\n", num);
}
//模块间标号共享
EXPORT_SYMBOL(my_printf);
<-- MODULE_LICENSE("GPL");
===============================================================
= C语言函数名默认是共享的
= 汇编语言的标号默认是不共享的
= 内核模块函数名默认是不共享的,只有EXPORT_SYMBOL(函数名),才能共享
===============================================================
######### PS #####################################
inclede/linux/ 此目录下的代码一般是平台无关
include/asm/ 此目录下的代码一般是平台相关
include/linux/stat.h 保存的是和权限相关的宏定义
include/linux/moduleparam.h
module_param_named
module_param
module_param_string
module_param_array
###################################################
< 模块参数 >
vim module_test3.c
--> #include <linux/init.h>
#include <linux/module.h>
//insmod xxx.ko xxx(参数)
//与此int main(int argc, char *argv[])比较
//事先声明需传的参数
static int age = 10;
char * name = "zhangsan";
char s[100];//必须事先分配空间
int array[100];
//module_param_named(a, age, int, S_IRUGO);
//S_IRUGO 是文件的权限;宏定义的位置,include/linux/stat.h
//module_param_named(n, name, charp, S_IRUGO);
//默认名字和变量相同
module_param(age, int, S_IRUGO)
//等价于module_param_named(age, age, int, S_IRUGO);
module_param(name, charp, S_IRUGO) //charp 指针类型
//等价于module_param_named(name, name, charp, S_IRUGO);
module_param_string(s, s, 100, S_IRUGO);
//100传入字符串最大长度字节,可以小于100,规定大小为了防止越界
//内核会自动把传入的元素个数放入num
int num;
module_param_array(array, int, &num, S_IRUGO);
static __init int module_test_init(void)
{
printk("hello world!\n");
printk("age = %d\n", age);
printk("name = %s\n", name);
printk("string = %s\n", s);
while(num--)
printk("array[%d] = %d\n", num, array[num]);
return 0;
}
static __exit void module_test_exit(void)
{
printk("Bye bye\n");
}
module_init(module_test_init);
module_exit(module_test_exit);
MODULE_LICENSE("GPL");//开源规则