static int __init my_init(void)
__init 宏展开是 .init.text __attribute__ ((__section__(#S))),这是编译器的一个属性,就是将有这个
前缀的函数代码放到一个代码段中,.init.text段,在内核启动的时候会把这个代码段中的所有函数都执行一遍。
__attribute__只适用于GNU C,因为内核都是用GNU C的标准写的
备注:
在跟代码的时候看到buildin的函数都是内联函数,是在编译器中实现的
通过 module_init(my_init) 进行加载模块
| |
|.init.text | --->如果模块配置选择的是Y,通过__init这个宏会把标记的代码放到.init.text的代码段中,
| | 内核启动的时候会把这个代码段总的代码都执行一遍
|-------------|
| bss | --->未初始化的全局变量
|-------------|
| data | --->初始化的全局变量
|-------------|
| text | --->text代码段
| |
如果模块退出的时候,将会执行exit函数:
static void __exit my_exit(void)
__exit 的含义和__init类似
通过 module_exit(my_eixt)进行挂在退出函数,当模块被卸载的时候会被调用
printk(KERNEL_ALERT"hello module\n");
printk使用方法和printf是一样的,就是在最前面printk可以设置打印消息的优先级
注意:优先级和后面的内容之间是没有逗号隔开的
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
编译好的模块可以通过:
insmod插入,rmmod删除,lsmod查看,modinfo查看模块的信息,modprob, 根据以来关系进行insmod加载模块 modprob -r
lsmod查看到后面引用是有模块名称的则为内核模块之间的调用,如果只有数字没有名字的话可能是用户态调用
printk默认打印的信息在dmesg中,dmesg是一个128K的一个缓冲区,通过dmesg -c清空这个缓冲区,但是这里的信息会存放在
/var/log/message
modprob模块必须把ko文件放到/lib/modules中
内核有一个全局变量来存放当前运行的进,current。
current->comm 当前运行进程的名称 current->pid 当前运行进程的pid,直接可以通过printk进行打印
带有双下划线的函数慎用__一般为内核的底层组建不是提供的外部接口,不要在内核中使用浮点运算。
模块和模块之间的函数是不同进行相互调用,要调用要使用EXPORT_SYMBOL() / EXPORT_SYMBOL_GPL()来将函数描述符导出。
模块的传参:
参数的类型
int 有符号整数
long 有符号长整数
short 有符号短整数
uint 无符号整数
ulong 无符号长整数
ushort 无符号短整数
charp 字符
bool true/false
invbool ~ true/false
使用方法:
static int num = 100;
static char *str = "hello world";
module_param(num,int,0755);
module_param(str,charp,0755);
name type perm
static int num[10] = {10,20,30};
module_param_array(num,int,10,0755);
name type count perm
perm通常为权限
可以在/sys/module/'module name'/parameters/这里面的文件就是用于模块传递参数用的
查看模块的信息,可以在/proc/module文件中
常用的头文件
#include
#include
#include struct task_struct *current; comm,pid
其他:
内核内存分配函数kzalloc和用户态内存分配模式的区别:
kzalloc是分配一块物理连续的内存空间,最大为4M,kzalloc就两种模式,GFP_KERNEL会导致休眠,所以不能用于中断,而GFP_ATOMIC则是使用的紧急内存,不会导致休眠,如果失败则直接返回。
内存不足休眠期间可以调整出内存:可以通过SWAP将不常用的内存交换到硬盘上去
malloc分配的内存空间是虚拟地址连续,物理地址不一定连续的。
阅读(963) | 评论(0) | 转发(0) |