Chinaunix首页 | 论坛 | 博客
  • 博客访问: 478259
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-10-28 22:04:01

一、内核模块基础
1.1 什么是内核模块
Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢,
方法1:把所有的组件都编
方法1:把所有的组件都编译进内核文件,即:zImage或bzImage,但这样会导致一个问题:占用内存过多.
有没有一种机制能让内核文件本身并不包含某组件,而是在该组件需要被使用的时候,动态地添加到正在运行的内核中呢?
1.2 内核模块特点
模块本身并不被编译进内核文件(zImage或者bzImage)
②可以更具需求,在内核运行期间动态的安装或卸载
1.3 内核安装与卸载
安装 insmod 
例:insmod /hoem/dnw_usb.ko
卸载rmmod 
例:rmmod dnw_usb
查看 lsmod
例:lsmod
二、内核模块设计
2.1 内核的三要素:
头文件:linux/init.h linux/module.h
insmod,运行模块入口:module_init();
rmmod,运行模块退出:module_exit();
2.2 内核的思维导图

2.3 内核的helloworld编写
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. static int hello_init(void)
    4. {
    5.     printk(KERN_WARNING"Hello, world !\n");
    6.     return 0;
    7. }
    8. static void hello_exit(void)
    9. {
    10.     printk(KERN_INFO "Goodbye, world\n");
    11. } 
    12. module_init(hello_init);
    13. module_exit(hello_exit);
printk日志级别一共有8个级别,printk的日志级别定义如下(在include/linux/kernel.h中):
#define KERN_EMERG 0/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/
#define KERN_ALERT 1/*报告消息,表示必须立即采取措施*/
#define KERN_CRIT 2/*临界条件,通常涉及严重的硬件或软件操作失败*/
#define KERN_ERR 3/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/
#define KERN_WARNING 4/*警告条件,对可能出现问题的情况进行警告*/
#define KERN_NOTICE 5/*正常但又重要的条件,用于提醒*/
#define KERN_INFO 6/*提示信息,如驱动程序启动时,打印硬件信息*/
#define KERN_DEBUG 7/*调试级别的消息*/
2.4 内核Makefile编写
Makefile
    1. obj-m := helloworld.o                              //默认使用obj-m的形式
    2. #hello-objs := file1.o file2.o file3.o             //这个可以分模块的方式
    3. KDIR := /home/doctmp/part4/linux-tq2440            //设置tq2440的内核目录
    4. all:
    5.     make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm    //-C 表明使用的内核目录  M表示需要编译的目录(PWD大写!) modules:make modules (编译内核)后面用交叉工具链
    6. clean:
    7.     rm -f *.o *.ko *.order *.symvers *.mod.c            //设置清除指令

三、内核模块可选信息
3.1 模块申明
1、MODULE_LICENSE(”遵守的协议”)
申明该模块遵守的许可证协议,如:“GPL“、”GPL v2“等
2、MODULE_AUTHOR(“作者”)
申明模块的作者
3、MODULE_DESCRIPTION(“模块的功能描述")
申明模块的功能
4、MODULE_VERSION("V1.0")
申明模块的版本

3.2 模块参数
在应用程序中int main(int argc, char** argv),argc表示命令行输入的参数个数,argv中保存输入的参数。
同理:
同理:通过宏module_param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。
module_param(name,type,perm);
name:变量的名称
type:变量类型,bool:布尔型 int:整型 charp:字符串型
perm是访问权限。 S_IRUGO:读权限 S_IWUSR:写权限
例:nt a = 3;
char *st;
module_param(a,int, S_IRUGO);
module_param(st,charp, S_IRUGO);

3.3 符号输出
内核符号的导出使用宏
EXPORT_SYMBOL(符号名)
EXPORT_SYMBOL_GPL(符号名)
说明:其中EXPORT_SYMBOL_GPL只能用于包含GPL许可证的模块。

再写一个add.c,修改helloworld调用add()函数。
  1. #include <linux/init.h>
  2. #include <linux/module.h>

  3. MODULE_LICENSE("GPL");

  4. int add(int a, int b)
  5. {
  6.     return a+b;
  7. }

  8. static int add_init(void)
  9. {
  10.     return 0;
  11. }

  12. static void add_exit(void)
  13. {
  14.     printk(KERN_WARNING"add_exit");
  15. }

  16. EXPORT_SYMBOL(add);

  17. module_init(add_init);
  18. module_exit(add_exit);
如果不加EXPORT_SYMBOL的话,会出现以下错误:
  1. # insmod add.ko
  2. # insmod helloworld.ko
  3. helloworld: Unknown symbol add
  4. insmod: cannot insert 'helloworld.ko': unknown symbol in module or invalid parameter
尽管加上extern表示外部引用,最后依然不能完成加载,哪怕顺序一致。加上export_symbol后就能让helloworld使用了。


阅读(579) | 评论(0) | 转发(0) |
0

上一篇:根文件系统制作

下一篇:Linux内核子系统

给主人留下些什么吧!~~