博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2.linux内核模块
阅读量:4125 次
发布时间:2019-05-25

本文共 8097 字,大约阅读时间需要 26 分钟。

2.1 驱动模块框架

Linux内核的整体架构非常庞大,其包含组件也非常多,怎样把需要的部分包含在内核中?

一种方法是把所需要的功能编译到linux内核中,这会导致两个文件,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。

Linux提供了这样一种机制,称为模块(Moudle)。可使编译出的内核本身并不包含所有的功能,而在这些被使用的时候,其对应的代码可被动态的加载到内核。

模块的特点

    模块本身不被编译到内核映像,从而控制了内核的大小。

    模块一旦被加载,它就和内核中的其他部分完全一样。

2.1.1对驱动模块进行操作的shell命令

insmod demo.ko  插入驱动模块

lsmod           查看插入正在运行驱动模块

rmmod demo      移除驱动模块  

modinfo demo.ko 查看驱动模块信息

dmesg           查看内核缓存信息

dmesg -c        清除内核缓存信息

有依赖关系的

modprobe (智能安装) xx(不加.ko)

modprobe -r 移除(注意:移除需要依赖的模块,同时会移除被依赖的模块)

2.1.2一个最简单的linux内核模块代码如下:

A.hello world驱动模块 demo.c

#include 
#include
static int __init demo_init(void){ printk("hello,word! driver module is inserted!\n"); return 0;}module_init(demo_init);/*指定驱动模块入口点*/static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);/*指定驱动模块出口*/MODULE_LICENSE("GPL");/*公共许可声明*/MODULE_AUTHOR("Songze Lee");/*作者*/MODULE_VERSION("Verson 1.0");/*版本号*/MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/

内核模块中用于输出的函数的内核空间的printk(),用法和printf基本相似,但可以定义输出级别。

Makefile编写如下:

obj-m	:= demo.oOUR_KERNEL := /ARM/linux-3.5-songze/all:	make -C $(OUR_KERNEL) M=$(shell pwd) modules#	进入到变量目录(内核源码目录)下编译  M 编译pwd路径下的模块clean:	make -C $(OUR_KERNEL) M=`pwd` clean

调试结果如下:

[projct /]# insmod demo.ko

[ 1670.390000]hello,word! driver module is inserted!

  [projct /]#rmmod demo

  [ 1681.215000]goodbye, word! driver is removed!

  rmmod: module'demo' not found

B.驱动模块调用子函数编写

demo.c

/** * 驱动模块调用子函数 * 注意Makefile的编写 */#include 
#include
extern void call_func0(void);static int __init demo_init(void){ call_func0(); printk("hello,word! driver module is inserted!\n"); return 0;}module_init(demo_init);/*指定驱动模块入口点*/static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);/*指定驱动模块出口*/MODULE_LICENSE("GPL");/*公共许可声明*/MODULE_AUTHOR("Songze Lee");/*作者*/MODULE_VERSION("Verson 1.0");/*版本号*/MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/
fun0.c

#include 
#include
extern void call_func1(void);void call_func0(void){ call_func1();}

fun1.c

#include 
#include
void call_func1(void){ printk("you are a good boy.\n");}

Makefile(重点注意)

obj-m	:= team_hehe.oteam_hehe-objs	:= demo.o fun0.o fun1.oOUR_KERNEL := /ARM/linux-3.5-songze/all:	make -C $(OUR_KERNEL) M=$(shell pwd) modulesclean:	make -C $(OUR_KERNEL) M=`pwd` clean

调试结果如下:

   [projct /]# insmod team_hehe.ko

    [ 1920.880000]you are a good boy.

    [ 1920.880000]hello,word! driver module is inserted!

    [projct /]#rmmod team_hehe

    [ 1932.020000]goodbye, word! driver is removed!

    rmmod: module'team_hehe' not found

2.1.3导出符号

    Linux的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址。

    模块可以使用如下宏导出符号到内核符号表中:

    EXPORT_SYMBOL(符号表);

    EXPORT_SYMBOL_GPL(符号表);

    导出的符号(变量或函数)可以被其他模块使用,只需要使用前声明一下即可。EXPORT_SYMBOL_GPL()只适用于包含GPL许可权的模块。

    示例代码如下:

demo1.c

#include 
#include
extern int sure;extern void pri_value(int);extern void call_func0(void);static int __init demo_init(void){ sure = 3856; pri_value(sure); printk("hello,word! driver module is inserted!\n"); return 0;}module_init(demo_init);static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Songze Lee");MODULE_VERSION("verson 1.0");MODULE_DESCRIPTION("It is a simple demo for driver module");

demo2.c

#include 
#include
static int sure = 9527;/*符号导出 static定义的变量或函数其他模块可以调用*/EXPORT_SYMBOL_GPL(sure);static void pri_value(int val){ printk("In %s: sure = %d\n", __FILE__, sure);}EXPORT_SYMBOL_GPL(pri_value);static int __init demo_init(void){ pri_value(sure); printk("hello,word! driver module is inserted!\n"); return 0;}module_init(demo_init);static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Songze Lee");MODULE_VERSION("verson 1.0");MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果如下:

[projct /]# insmod demo02.ko

[ 2484.680000] In/ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 9527

[ 2484.680000] hello,word! driver module is inserted!

[projct /]# insmod msb.ko

[ 2491.690000] In /ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 3856

[ 2491.690000] hello,word! driver module is inserted!

[projct /]# rmmod demo02

rmmod: remove 'demo02': Resource temporarily unavailabl两者有依赖关系

[projct /]# rmmod msb

[ 2531.345000] goodbye, word! driver is removed!

rmmod: module 'msb' not found

[projct /]# rmmod demo02

[ 2542.910000] goodbye, word! driver is removed!

rmmod: module 'demo02' not found

2.1.4模块参数

    在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递命令行参数。

module_param宏是Linux 2.6内核中新增的,该宏被定义在include/linux/

moduleparam.h文件中,具体定义如下:

    #define module_param(name, type, perm)              

       module_param_named(name, name, type,perm)

由此可知module_param的实现是通过module_param_named(name, name, type,perm)的。

module_param(name,type, perm)

name:参数名 type:参数类型perm:参数读写权限

    参数类型可以是byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool或invbool(布尔的反),在模块被编译时会将module_param中声明的类型与变量定义的类型进行比较、判断是否一致。

    module_param_array(name,type,num,perm)

name:数组名 type:数组类型num:数组长 perm:参数读写权限

perm参数的作用是什么?

最后的 module_param字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 <linux/stat.h> 中定义的值. 这个值控制谁可以存取这些模块参数在 sysfs 中的表示.

当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录, 带有给定的权限.。

权限在include/linux/stat.h中有定义

比如:

    #define S_IRWXU 00700

    #define S_IRUSR 00400

    #define S_IWUSR 00200

    #define S_IXUSR 00100

    #define S_IRWXG 00070

    #define S_IRGRP 00040

    #define S_IWGRP 00020

    #define S_IXGRP 00010

    #define S_IRWXO 00007

    #define S_IROTH 00004

    #define S_IWOTH 00002

    #define S_IXOTH 00001

使用 S_IRUGO 参数可以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR 允许 root 来改变参数.注意, 如果一个参数被 sysfs 修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.

示例A:module_param(name, type, perm)

/** *module_param(name, type, perm) 内核模块传参 *向当前模块传参 */#include 
#include
static int x_rel = 480, y_rel = 272;module_param(x_rel, int, 0);module_param(y_rel, int, 0);static char *info = "mdg: lol?";static int num=10;module_param(num,int,S_IRUGO);module_param(info, charp, 0);static int __init demo_init(void){ printk("hello,word! driver module is inserted!\n"); printk("x: %d, y: %d\n %s\n", x_rel, y_rel, info); printk("num=%d\n",num); return 0;}module_init(demo_init);static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Songze Lee");MODULE_VERSION("version 1.0");MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果:

[projct /]# insmod demo.ko num=110 x_rel=123 y_rel=345info="hello world"

[ 4140.560000] hello,word! driver module is inserted!

[ 4140.560000] x: 123, y: 345

[ 4140.560000] hello world

[ 4140.560000] num=110

[projct /]# cat /sys/module/demo/parameters/num

110

[projct /]# ls -l /sys/module/demo/parameters/num

-r--r--r--    10        0             4096 Jan  1 14:06 /sys/module/demo/parameters/num

可发现num为只读文件

示例B:module_param_array(name,type,num,perm)

#include 
#include
#define CNT 16static int num = CNT;static int array[CNT] = {1,2,3,4,5,6,7};module_param_array(array, int, &num, 0);static int __init demo_init(void){ int i; printk("Insert module ok!\n"); for(i = 0; i < num; i++){ printk("array[%d] = %d\n", i, array[i]); } return 0;}module_init(demo_init);static void __exit demo_exit(void){ printk("goodbye, word! driver is removed!\n");} module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("millet9527");MODULE_VERSION("uplooking plus 7");MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果:

[projct /]# insmod demo.koarray=11,22,33,44,55,66,77,88,99

[ 4965.605000] Insert module ok!

[ 4965.605000] array[0] = 11

[ 4965.605000] array[1] = 22

[ 4965.605000] array[2] = 33

[ 4965.605000] array[3] = 44

[ 4965.605000] array[4] = 55

[ 4965.605000] array[5] = 66

[ 4965.605000] array[6] = 77

[ 4965.605000] array[7] = 88

[ 4965.605000] array[8] = 99

获取源码: git clone https://www.github.com/lisongze2016/Tiny4412_kernel.git

转载地址:http://zglpi.baihongyu.com/

你可能感兴趣的文章
路径搜索算法-A星算法
查看>>
Hadoop的HA高可靠性集群搭建(Hadoop+High availability+Zookeeper)
查看>>
hadoop集群-单词计数wordcount
查看>>
Hadoop的HA集群HDFS搭建-错误记录
查看>>
图算法-Prim、Kruskal、Dijkstra、Floyd、Bellman
查看>>
智能优化算法-粒子群算法
查看>>
MapReduce开发环境搭建
查看>>
hadoop计算框架shuffle-计算每个月最高三个温度出现的时间
查看>>
微信公众号平台搭建连接javaweb
查看>>
推荐系统-计算用户关联度fof(hadoop计算)
查看>>
hadoop-hive初始化
查看>>
基于深度循环神经网络的单通道人声与音乐的分离-论文翻译
查看>>
hadoop-mapreduce基于物品的协同推荐算法ItemCF
查看>>
Hadoop-HBase集群搭建
查看>>
hadoop-hbase几个错误记录
查看>>
hadoop集群简化安装-CDH的安装和使用
查看>>
Zookeeper-Zookeeper leader选举
查看>>
Redis实战:第一章-初识Redis案例-文章投票
查看>>
Redis实战:第二章-使用redis构建web应用
查看>>
Redis实战:第三章-redis命令练习
查看>>