Linux内核模块编程

1.Linux内核模块编程特点

1)不能使用C库和C标准头文件
2)必须使用GNU规范
3)没有内存保护机制
4)不能处理浮点运算
5)注意同步和并发的问题
6)注意可移植性

2.函数架构

int xxx(void)
{
    return 0;//成功
    return 负值;//失败
}    

void yyy(void)
{
    
}
/* 使用module_init()函数告诉内核模块的加载函数
*  使用module_exit()函数告诉内核模块的卸载函数   
*/

module_init(xxx);
module_exit(yyy);

 

3.编译模块可以使用内核中编译模块的方法


3.1 模块的操作命令


insmod:加载模块,内核会执行模块加载函数;
rmmod:卸载模块,内核会执行模块卸载函数;
lsmod:查看当前已加载的模块;

modinfo:查看模块信息;
modprobe:加载模块,内核会执行模块加载函数;

modprobe和insmod的区别
    modprobe需要模块信息文件的支持modules.dep,modprobe还会检查模块的依赖,自动加载依赖的模块,insmod则没有这些性质。
    modinfo也需要modules.dep的支持。

3.2 模块许可证(GPL)

MODULE_LICENSE("GPL v2");

如果不加,内核提示警告信息,内核有些函数将无法使用。

3.3 内核的输出级别和printk的输出级别

printk函数时具有打印级别,级别0-7,数字越小,级别越高。内核也有默认的输出级别。
当printk的输出级别小于内核的输出级别时,printk打印的内容就可以被打印出来。否则printk的打印信息将被忽略。

查看内核的输出级别
cat /proc/sys/kernel/printk
7       4       1       7

内核输出级别为7,printk的默认级别为4

如何修改内核的默认输出级别
方法1:

echo 5 > /proc/sys/kernel/printk         //方法1无法修改在内核启动时的输出信息

方法2:
通过uboot的环境变量bootargs传递打印级别的参数
set bootargs root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/home/student/workdir/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:on console=ttySAC0,115200 debug //级别为10

set bootargs root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/home/student/workdir/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:on console=ttySAC0,115200 quiet //级别为4

set bootargs root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/home/student/workdir/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:on console=ttySAC0,115200 loglevel=6 //直接指定级别


4.内核模块参数

4.1 作用

     在加载模块和加载模块后,能够给模块传递相应的参数信息
4.2 使用

module_param();
module_param_array();



//在其它文件调用时候,extern 申明下就可以了,但是加载insmod的时候,必须先加载所依赖的模块,再加载自己

/sys/module/模块名/paramters/  目录下有对应的文件。
如果模块参数的权限为0,在该目录下就不会有对应的文件;
如果模块参数的权限非0,在该目录下有对应的同名文件,同时该文件的权限和定义模块参数是提供的权限相同。

我们可以通过修改这些文件的内容来实现对模块参数的修改。


5.内核模块依赖

一个模块使用了另一个模块的变量或者函数,第一个模块就依赖于第二个模块

模块的导出符号
如果一个模块中的变量或者函数希望被别的模块使用,需要将对应的变量或者函数导出

EXPORT_SYMBOL();
EXPORT_SYMBOL_GPL();


前一个导出的内容所有模块都能使用,后一个导出的内容只有遵循GPL协议的模块才能使用。所以模块编程是一定要添加:MODULE_LICENSE("GPL v2");


6.linux系统调用的原理和实现

6.1 作用

      为用户提供统一的硬件抽象层,操作一个文件,无需关心这个文件是存在于哪个硬件上(硬盘 SD卡 U盘 nand flash),只需要调用对应的系统调用即可(open read write...)。
6.2 原理
1)应用程序调用open
2)进程会调用C库中对应的open函数的实现
3)C库的open的实现会将open对应的系统调用号保存到寄存器中
4)C库的open的实现会调用软中断swi(svc)触发一个软中断异常
5)进程就会跳转到内核实现定义的一个位置(异常向量表)
6)该位置对应的异常向量入口是(vector_swi)
7)这个函数会根据系统调用号,在系统预先定义的一个系统调用表中找到open函数对应的内核实现sys_open
8)执行该函数
9)执行完毕,原路返回

6.3 添加一个系统调用
1)添加系统调用的内核实现
在arch/arm/kernel/sys_arm.c中添加新系统调用的内核实现sys_add;
2)添加新的系统调用号
在arch/arm/include/asm/unistd.h中添加一个新的系统调用号__NR_add;
3)更新系统调用表
在arch/arm/kernel/calls.S中的系统调用表中添加新的一项:CALL(sys_add);

重新编译内核,新内核就有新的系统调用,可以在用户空间使用syscall函数完成对新的系统调用的调用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值