第二章:构造和允许模块(part2)

原创 2012年03月29日 11:19:26

内核符号表

当模块被装入内核后,它所导出的任何符号都会变成内核符号表的一部分。

模块层叠技术是一个常用的方案。modprobe是处理层叠模块的一个使用工具,它除了装入指定模块外还同时装入了指定模块所依赖的其他模块。(从当前目录装入自己的模块仍需要insmod,因为modprobe只能从标准的以安装模块目录中搜索需要装入的模块)

如果一个模块需要向其他模块导出符号,则应该使用下面的宏:

EXPORT_SYMBOL(name);

EXPORT_SYMBOL_GPL(name);

注意_GPL版本使得导出的符号只能被GPL许可证下的模块使用;符号必须在模块文件的全局部分导出,不能再函数中导出(因为两个宏会被扩展为一个特殊变量,而这个变量必须是全局变量,该变量在可执行文件的一个特殊的部分保存,即”ELF”,装载模块时,内核通过这个段来寻找导出的变量)。

预备知识

所有的模块代码都包含下面两行代码:

#include <linux/module.h>

#include <linux/init.h>

module.h包含可装载模块需要的大量符号和函数的定义。init.h是用来指定初始化和清除函数。

此外,大多数模块代码也包含moduleparam.h,这样我们可以在装载模块时向模块传递参数。

模块中包含的其他描述性定义:

MODULE_LICENSE (“GPL”);

模块一般需指定所使用的许可证。内核可识别的许可证有”GPL”、”GPL v2”、”GPL and additional rights”、”Dual BSD/GPL”、”Dual MPL/GPL”以及”Proprietary”。

MODULE_AUTHOR(“Lujianpeng”); 描述模块作者。

MODULE_DESCRIPTION (“Drive for Device”); 描述模块用途。

MODULE_VERSION (“2.6.10”); 代码修订号。

MODULE_ALIAS(); 模块别名。

MODULE_DEVICE_TABLE(); 用来告诉用户空间模块所支持的设备。

一般情况下,这些声明放在文件的最后。

注意:这些宏描述的定义可以通过modinfo命令来查看。

初始化和关闭

模块的初始化负责注册模块所提供的任何设施(可能是一个完整的驱动程序,也可能仅仅是一个新的软件抽象)。

初始化函数的实际定义通常如下:

	static int __init initialization_function(void)
	{
		/*这里是初始化代码*/
	}
	module_init(initialization_function);

若干解释:

l 为什么声明为static?因为这种函数在特定文件之外没有其他意义。这并不是强制性规则,因为如果一个函数要对内核其他部分课件,则必须显式导出。

l __init__initdata的作用:表明该函数尽在初始化期间使用,模块装载之后初始化函数会被扔掉,释放内存以作他用。两者的使用是可选的。在内核源代码会遇到__devinit__devinitdata,只有在内核未被配置为支持热插拔设备的情况下,这两个标记才会被翻译为_init__initdata

l module_init的使用是强制性的。用于说明内核初始化函数所在的位置。

模块可以出则许多不同类型的设施,不同的设施对应具体的内核函数用来完成注册。传递到注册函数的参数通常是一个指向某数据结构的指针,此数据结构中包含指向模块函数的指针。

清除函数

清除函数定义如下:

static void __exit cleanup_function(void)
{
    /*这里是清除代码*/
}
Module_exit(cleanup_function);

若干解释:

l 函数无返回值,被声明为void

l __exit:标记该代码仅用于模块卸载,只能在卸载模块或者关闭系统时被调用,其他的任何调用都是错误的。若模块直接内嵌到内核中,或者内核不允许卸载模块,则被标记__exit的函数将被简单的丢弃。

l module_exit:帮助内核找到模块的清除函数。如果一个模块未定义清除函数,则内核不允许卸载该模块。

初始化过程中的错误处理

如果发生了某个特定类型的错误之后无法继续装在模块,则要将出错之前的任何注册工作撤销掉。错误处理有时使用goto语句比较有效。如:

int __init my_init_function(void)
{
	int err;
	/*使用指针和名称注册*/
	err = register_this(ptr1, “skull”);
	if (err) goto fail_this;
	err = register_that(ptr2, “skull”);
	if (err) goto fail_that;
	err = register_those(ptr3, “skull”);
	if (err) goto fail_those;
	
	return 0;  /*成功*/
	
	fail_those: unregister_that(ptr2, “skull”);
	fail_that: unregister_this(ptr1, “skull”);
	fail_this: return err; /*返回错误*/
}

linux内核中,错误编码是定义在<linux/errno.h>中的负整数。

模块的清除函数需要撤销初始化函数所注册的所有设施,习惯上以相反于注册的顺序撤销设施。

当初始化和清除工作涉及很多设施时,goto方法就显得麻烦;此时,我们可以在初始化函数中调用清除函数,当然,清除函数在撤销每项设施的注册之前检查它的状态。(此处可以参看原书代码)

模块装载竞争

在用来支持某个设施的所有内部初始化完成之前,不要注册任何设施。

模块参数

使用insmod以及modprobe装载模块时,可以设定其中若干的参数值。这些参数值在程序中必须使用module_param宏来声明。这个宏定义在moduleparam.h中。

module_param(name, int, S_IRUGO); // 用来声明一个变量

module_param_array(name, type, num, perm); // 用来声明一个数组

解释:

name:变量名;type:类型,支持bool, invbool, charp, int, long, short, uint, ulong, ushort; perm:访问许可值; num:一个整数变量。

所有模块参数需要给一个默认值,insmod只会在用户明确的设置了参数的值的情况下才会改变参数的值。模块可以根据默认值来判断是否是一个显式指定的值。

查漏补缺

#include <linux/sched.h>

该文件包含驱动程序使用的大部分内核API定义。

vermagic.o

内核源代码目录一个目标文件,它描述了模块的构造环境。

#include <linux/kernel.h>

int printk(const char *fmt, …);

 



 

第二章:构造和允许模块(part1)

注:这是当初学习《linux设备驱动程序》的学习笔记,只有提纲挈领的作用,不足之处还请大家多多包涵,多多指点。 Hello world模块 模块能够调用printk是因为在insmod函数装入模块...
  • ljp827
  • ljp827
  • 2012年03月29日 11:09
  • 186

第二章 构造和运行模块(笔记)

1. 设置测试系统 如果读者正在编写一个只适用于某特定发行版的驱动程序,则应该针对相关内核创建和测试自己的驱动程序。 2.6.x内核构造模块,必须在自己的系统中配置并构造好内核树(因为2.6内核的...

LDD3笔记:第二章 构造和运行模块

在正式进行驱动开发前,需要了解有关模块编程和内核编程的一些基本概念。在本节中将会构造几个完整的(但绝对没啥功用的)模块。设置测试系统一般的发行版本都会装好内核代码树的,用过的Red Hat Enter...

【Linux 驱动】第二章 构造和运行模块

设置测试系统开发环境及Hello World入门模块在前面博文中已经讲到,请参考http://blog.csdn.net/tianshuai11/article/details/7442168   ...

第二章 构造和运行模块(1)

第二章开始进入到实际的编程了。第一个测试代码:Hello World。 第一件事就是建立测试系统。 我安装的系统是rhel-5.1-server-i386-dvd.iso,你可以到网上下载其他版本...

第二章:构造和运行模块

1、一个简单的hello,world的模块: #include /* 用于指定初始化和清楚函数 */ #include /* 包含有可装载模块所需的大量符号和函数定义 */ #includ...

源码-PL/SQL从入门到精通-第二章-PL/SQL基本概念-Part 2

随书光盘中的源码没有序号,部分找不到或者有bug,调试过程中一并更正。 其中,还有两个彩蛋:“双十九”乘法口诀表和“双九九”加法口诀表的输出(PL/SQL实现),以及一个附加(加薪函数的调用) ...

Android数据库ORMlite框架翻译系列(第二章:part 2)

前言 这章的内容的确不少,所以这次仍然没有翻译完。需要快速上手的话你最好看看原文档。 -------------------------------------------------------...
  • QQzyb
  • QQzyb
  • 2013年12月12日 16:43
  • 614

Android数据库ORMlite框架翻译系列(第二章:part 2)

前言 这一部分继续Android数据库ORMlite框架翻译系列(第二章:part 1)部分。这章的内容的确不少,所以这次仍然没有翻译完。需要快速上手的话你最好看看原文档。 -----...

深入研究SSL【第二章 part-2】-SSL握手协议的研究

博客分类:  SSL Exchange应用服务器JDK浏览器算法  第一章. 对SSL的基本概念和框架的介绍  第二章.对SSL握手协议的研究(part-1 )  第三章.对SSL握...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:第二章:构造和允许模块(part2)
举报原因:
原因补充:

(最多只允许输入30个字)