linux内核模块设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
内核模块概述
太多的设备驱动和内核功能集成 在内核中,内核过于庞大。 在内核中,内核过于庞大。如何 解决? 解决?
Linux内核引入内核模块 机制。通过动态加载内核 模块,使得在运行过程中 扩展内核的功能。不需要 的时候,卸载该内核模块。
www.gec-edu.org
内核模块概述
什么是内核模块? 什么是内核模块?
www.gec-edu.org
内核模块概述
内核模块的卸载 当我们不需要内核模块了,为了减少系统资源的开销 为了减少系统资源的开销, 当我们不需要内核模块了 为了减少系统资源的开销 需要卸载时使用命令 #rmmod module_name 或者 #modprobe –r module_name 查看系统已经加载的模块,使用命令 查看系统已经加载的模块 使用命令 #lsmod
www.gec-edu.org
实验:Hello World模块 实验 模块
模块参数 module_param(name,type,perm); perm是一个权限值,控制谁可以存取模块参 数在 sysfs 中的表示。 perm 被设为 0, 就根本没有 sysfs 项 这个宏定义应当放在任何函数之外, 典型地 是出现在源文件的前面。 应该总是为变量赋初值。
www.gec-edu.org
实验:Hello World模块 实验 模块
模块参数 声明一个数组参数: module_param_array(name,type,num,perm); • name 数组的名子(也是参数名) • type 数组元素的类型 • num 是数组元素的个数,模块加载者拒绝比数组 能放下的多的值。2.6.9传递数组个数变量名, 2.6.11传递数组个数变量的地址。 • perm 是通常的权限值. 如果数组参数在加载时 设置。
#include <linux/init.h> // for module_init() #include <linux/module.h> // must be include #include <linux/kernel.h> // for printk() static int __init hello_init(void) { printk(“Hello world\n”); “ ” return 0; } static void __exit hello_exit(void) { printk(“Hello module exit\n”); “ ” } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE(“GPL”); “ ” MODULE_AUTHOR(“hsq”); “ ”
内核模块是一种没有经过链接,不能独立运行的目标文件, 是在内核空间中运行的程序。经过链接装载到内核里面成为 内核的一部分,可以访问内核的公用符号(函数和变量)。 内核模块可以让操作系统内核在需要时载入和执 行,在不 需要时由操作系统卸载。它们扩展了操作系统内核的功能却 不需要重新启动系统。 如果没有内核模块,我们不得不一次又一次重新编译生成单 内核操作系统的内核镜 像来加入新的功能。这还意味着一 个臃肿的内核。
www.gec-edu.org
实验:Hello World模块 实验 模块
说明: 说明 1) 模块入口函数为 模块入口函数为hello_init(), 由module_init() 宏指定,在模块被加载的时候被调用向系统 宏指定 在模块被加载的时候被调用向系统 注册, 就象应用程序的main()一样 主要来 一样,主要来 注册 就象应用程序的 一样 完成模块的初始化工作 2) 入口函数的返回值为 表示成功 非0表示失败 入口函数的返回值为0表示成功 表示成功, 表示失败 3) 模块的退出函数为 模块的退出函数为hello_exit(),由module_exit()宏 由 宏 指定,在模块被卸载是被调用向系统注销 在模块被卸载是被调用向系统注销,主要来完成 指定 在模块被卸载是被调用向系统注销 主要来完成 资源的清理工作,它被调用完毕后 它被调用完毕后,就模块就被内核清除了 资源的清理工作 它被调用完毕后 就模块就被内核清除了 4) 一个模块最少需要有入口和退出函数
www.gec-edu.org
实验:Hello World模块 实验 模块 步骤: 步骤 新建模块目录 用编辑器(vi)编辑源文件 用编辑器 编辑源文件 用编辑器编辑Makefile 用编辑器编辑 在内核源码树外编译 把模块加到内核源码树并把配置信息同时加入
www.gec-edu.org
实验:Hello World模块 实验 模块
www.gec-edu.org
实验:Hello World模块 实验 模块
写内核程序需要注意: 写内核程序需要注意
www.gec-edu.org
Baidu Nhomakorabea
实验:Hello World模块 实验 模块
内核模块的Makefile: 内核模块的
CONFIG_HELLO_WORLD ?= m ifneq ($(KERNELRELEASE),) hello_world-objs := hello.o obj-$(CONFIG_HELLO_WORLD) += hello_world.o else KERNELDIR = /$(your_kernel_source)/ PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif clean: rm –rf *.o *~ core .depend . *.cmd *.ko *.mod.c .tmp_versions
Linux 2.6内核模块设计 内核模块设计
www.gec-edu.org
www.gec-edu.org
内核模块概述
Linux内核是整体式结构,各个子系统联系紧密,作为一个大程 内核是整体式结构,各个子系统联系紧密, 内核是整体式结构 序在内核空间运行。 序在内核空间运行。
www.gec-edu.org
www.gec-edu.org
内核模块概述
模块机制的优点: 模块机制的优点: 减小内核映像尺寸,增加系统灵活性; 节省开发时间;修改内核,不必重新编译整个内核。 模块的目标代码一旦被链入内核,作用和静态链接 的内核目标代码完全等价。 模块机制的缺点: 模块机制的缺点: 对系统性能有一定损失; 使用不当时会导致系统崩溃;
www.gec-edu.org
实验:Hello World模块 实验 模块
模块参数 内核允许对模块指定参数,这些参数可在装载模块 时改变。在运行insmod或者modprobe命令时给出 参数的值。 insmod hellop.ko howmany=10 whom="Mom" 如何定义实现模块参数呢? 要传递参数给模块,首先将获取参数值的变量声明 为全局变量。然后使用宏moudle_param来声明 来声明 int myint = 3; module_param(myint, int,0);
www.gec-edu.org
实验:Hello World模块 实验 模块
printk( )函数 函数
printk 函数在 Linux 内核中定义并且对模块可用,为内 核提供日志功能, 记录内核信息或用来给出警告。与 标准 C 库函数 printf 的行为相似。 每个printk() 声明都会带一个优先级。内核总共定义了 八个优先级的宏, 在linux/kernel.h中定义。若你不指明 优先级,DEFAULT_MESSAGE_LOGLEVEL这个默认 优先级将被采用。 信息添加到文件 /var/log/messages,可直接查看,或 者用命令dmesg查看。在X-windows下的终端insmod 一个模块,日志信息只会记录在日志文件中,而不在终 端打印。
www.gec-edu.org
实验:Hello World模块 实验 模块
参数数组的定义: 参数数组的定义: static int test[5] = {1,2,3,4,5}; static int num =5; module_param(num,int,0); module_param_array(test,int,num,0); MODULE_PARM_DESC(test, "test array"); 参数数组的加载方式: 参数数组的加载方式: insmod test.ko test=6,7,8,9,10 num=5
www.gec-edu.org
实验:Hello World模块 实验 模块
模块参数 宏MODULE_PARM_DESC() 用来注解该模块可以 接收的参数。该宏两个参数:变量名和一个对该变 量的描述。 模块可以用这样的命令行加载: ./insmod mymodule.ko myvariable=2 例子:hello-5.c
www.gec-edu.org
实验:Hello World模块 实验 模块
说明: 说明
关于__init和__exit宏 关于 和 宏
如果该模块被编译进内核,而不是动态加载,则宏 __init的使用会在初始化完成后丢弃该函数并收回所占 内存。 如果该模块被编译进内核,宏__exit将忽略“清理收尾” 的函数。 这些宏在头文件linux/init.h定义,用来释放内核占用的 内存。例如启动时看到的信息“Freeing unused kernel memory: 236k freed”,正是内核释放这些函数所占用 空间时的打印信息。
www.gec-edu.org
实验:Hello World模块 实验 模块
内核模块证书和内核模块文档说明
2.4内核后,引入识别代码是否在GPL许可下发布的机 制 。在使用非公开的源代码产品时会得到警告。通过 宏MODULE_LICENSE(“GPL”),设置模块遵守GPL证 书,取消警告信息。 宏MODULE_DESCRIPTION()用来描述模块的用途。 宏MODULE_AUTHOR()用来声明模块的作者。 宏MODULE_SUPPORTED_DEVICE() 声明模块支持 的设备。 这些宏都在头文件linux/module.h定义。使用这些宏只 是用来提供识别信息。 范例:hello-4.c
www.gec-edu.org
内核模块概述
内核模块是如何被调入内核工作的? 内核模块是如何被调入内核工作的 当操作系统内核需要的扩展功能不存在时, 内核模块管理守护进程kmod执行modprobe 去加载内核模块。 modprobe遍历文件 /lib/modules/$(version)/modules.dep 来判 断是否有其它内核模块需要在该模块加载前 被加载。 最后modprobe调用insmod先加载被依赖的 模块,然后加载该被内核要求的模块。
注意: 注意: your_kernel_source,是你的linux kernel源代码的目录
www.gec-edu.org
实验:Hello World模块 实验 模块
Makefile说明 说明: 说明
为2.6版本内核构造模块 版本内核构造模块
首先需要有配置并构建好的2.6内核源代码树。而 且最好运行和模块对应的内核。 2.6 内核的模块要 和内核源代码树中的目标文件连接。 2.6 内核的构建系统Kbuild,使得内核源码外的内 核模块编译跟内核编译统一起来,无须手动给定这 些参数。 改变目录到用 -C 选项提供的内核源码目录,在那 里找到内核的顶层makefile。M= 选项使 makefile 在试图建立模块目标前, 回到模块源码目录。
www.gec-edu.org
实验:Hello World模块 实验 模块
编译加载/卸载 编译加载 卸载: 卸载 在hello world模块目录上 模块目录上 #make 得到hello_world.ko就是产生的内核模块 在 就是产生的内核模块,在 得到 就是产生的内核模块 评估板上使用 #insmod hello_world.ko 和 #rmmod hello_world 观察控制台输出的结果