内核模块嵌入式

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

一,模块函数
(1)加载函数:

//将模块函数用关键字static修饰,避免和内核函数重名

//_init 把标记的函数放在ELF文件的特定代码段,模块加载这些段的时候会单独分配内存,这些函数被成功调用后,模块的加载程序会释放这部分的内存空间。

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

(2)卸载函数:
static void _exit xxx(void)
{
      xxxx
}

(3)使用module_init和module_exit修饰:告诉内核模块的加载函数和卸载函数
二,模块如何使用
模块的操作命令
insmod
      加载模块,内核会执行模块加载函数
rmmod
      卸载模块,内核会执行模块卸载函数
lsmod
      查看当前已加载的模块
modinfo 
      查看模块信息
modprobe
      加载模块,内核会执行模块加载函数
modprobe和insmod的区别
      modprobe需要模块信息文件的支持modules.dep,modprobe还会检查模块的依赖,自动加载依赖的模块,insmod则没有这些性质
modinfo也需要modules.dep的支持
模块许可证(GPL)
MODULE_LICENSE("GPL v2");
如果不加,内核提示警告信息,内核有些函数将无法使用
内核的输出级别和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=/linuxrcnfsroot=192.168.1.141:/home/student/workdir/rootfsip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:onconsole=ttySAC0,115200 debug //级别为10
set bootargs root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/home/student/workdir/rootfsip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:onconsole=ttySAC0,115200 quiet //级别为4
set bootargs root=/dev/nfs init=/linuxrcnfsroot=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:onconsole=ttySAC0,115200 loglevel=6 //直接指定级别
三,内核模块参数
作用:在加载模块和加载模块后,能够给模块传递相应的参数信息
(1)参数格式
module_param(name,type,perm)
module_param_array(name,type,nump,perm)
(2)查看模块参数对应文件的权限
cat /sys/module/模块名/paramters/  目录下有对应的文件
如果模块参数的权限为0,在该目录下就不会有对应的文件
如果模块参数的权限非0,在该目录下有对应的同名文件,同时该文件的权限和定义模块参数是提供的权限相同
我们可以通过修改这些文件的内容来实现对模块参数的修改


四,内核模块依赖

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

如果一个模块中的变量或者函数希望被别的模块使用,需要将对应的变量或者函数导出。
(1)工作原理:

利用EXPORT_SYMBOL宏生产一个特定的结构并放在ELF文件的一个特定段中,内核启动过程中,会将之前没有分配地址的变量和函数(符号内心是U)提供一个地址,并将这个地址填充到结构体中。模块加载时候,加载程序将去处理U符号,在特殊段中搜索符号的名字(变量,函数等),如果找到了,则将获得的地址填充在被加载模块的相应段中。=》确定符号的地址。
(2)模块的导出符号

EXPORT_SYMBOL

EXPORT_SYMBOL_GPL

注:引用模块的变量和函数(导出变量)时:使用extern

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

 

内核模块和普通应用程序的差异对比:

(1)  内核模块是操作系统内核的一部分,运行在内核空间。而应用程序运行在用户空间。

(2)  内核模块中的函数时被动调用的,应用程序是顺序执行的。

(3)  内核模块处于C函数库之下,所以不能够调用C函数库。

(4)  内核模块要做一些清除性的工作,比如在一个操作失败后或者在内核的清除函数中。而应用程序有些工作不需要做。

(5)  内核模块如果产生了非法访问,将很有可能导致系统的崩溃,而应用程序通常只会影响到自己。

(6)  Pritk和peintf行为很相似,但是printk不支持浮点数。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值