添加内核模块
来自:http://wenku.baidu.com/link?url=F0zJi8vzupprB4wKS26mXvJkzA6yTZYb5882Oz6X0o_G1u6veks2EcrrCJMVcfukzzEZYH8UU6RCA4fIUYQ4KGbjsFeIM5ezHavzeJUZOFG
编写helloworld模块,了解模块的编程方法。
首先编写一个helloworld程序,如下图:
图1 HelloWorld模块测试c程序
两个头文件linux/module.h和linux/init.h是编写模块所必需的;
程序里面有两个函数,第一个函数moduletest_init实现模块加载时的动作,第二个函数moduletest_exit实现模块卸载是的动作。两个函数的函数名可以任意指定。
module_init和module_exit是两个宏,括号里的函数名才是真正的模块加载和卸载时要执行的函数,即不管上面的两个函数的函数名是什么,只要经过这两个宏的指定,就会称为模块加载和卸载时运行的函数。
最后一句表示模块遵循公共许可证,一般来说都要加上,不加会出现警告。
然后编译内核模块
(1)编写Makefile文件;
在与源文件同目录下,新建文件名为Makefile,注意M要大写。编辑Makefile文件,添加以下内容并保存,如图:
(2)编译内核模块;
打开终端,进入当前所在的目录。执行命令 make命令成功执行后,会在当前目录下生成许多文件,HelloWorld.o HelloWorld.ko HelloWorld.mod.o HelloWorld.mod.c Modules.symvers 其中,HelloWorld.ko是我们要加载的模块。
(3)最后加载和卸载模块;
终端在当前目录下,输入命令 insmod ./HelloWorld.ko;
输入命令lsmod,能找到名为HelloWorld的模块,说明模块已经加载;
输入命令dmesg,查看最后一行,会有模块加载时调用的函数输出;
输入命令rmmod HelloWorld ,卸载模块(注意与加载时不同),然后输入lsmod,已经找不到HelloWorld模块,说明模块已经卸载;
输入命令dmesg,查看模块卸载是调用的函数输出。
可以用 make clean 命令清除编译生成的文件,以便重新编译。
编写系统时钟的模块实验
编写clock.c文件
然后编写一个测试函数test.c
编译test.c 生成test可执行文件 。
最后进行测试
先加载clock模块,此时通过终端进入/proc目录,用ls命令,会发现存在一个名为clock的文件,卸载模块之后,再查看/proc,将找不到clock文件。加载clock模块后,运行test可执行文件,查看输出。
程序分析
(1)模块程序
模块加载时刻调用create_proc_read_entry函数,struct proc_dir_entry *create_proc_read_entry( const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void *data );
详细内容请查看/usr/src/linux-版本/include/linux/proc_fs.h文件。
create_proc_read_entry函数实现在/proc文件夹下创建名为name的文件,并且这个文件只能以只读方式被打开。一旦文件被打开,就会调用参数read_proc指向的函数,这里是myread。(关于/proc的详细说明,请看http://www.ibm.com/developerworks/cn/linux/l-proc.html)
参数read_proc的类型是 read_proc_t,read_proc_t的定义也在proc_fs.h中。
Linux 在 源代码/include/linux/time.h中定义了关于时间的数据结构: struct timespec{ time_t tv_sec; //秒 long tv_nsec; //纳秒 } 和
struct timeval{ time_t tv_sec; //秒 long tv_usec; //微秒 }
Linux中定义了一个全局的系统变量struct timespec xtime,用这个变量保存当前时间;
myread函数的第一个参数指向了/proc/clock文件的缓冲区,因此调用了sprintf后,系统时间xtime的值被格式化输入到了clock文件中。
模块卸载后,执行remove_proc_entry删除了在/proc下创建的文件。
(2)测试程序
首先尝试打开/proc/clock文件,如果打开成功,则调用了myread函数。使用fgets从clock
文件中读出了myread输入的系统时间,然后调用gettimeofday函数,其定义在/usr/include/sys/time.h文件中。gettimeofday的第一个参数是timeval类型。
最终的输出结果,秒的值是一样的,由于系统时间是纳秒,gettimeofday返回的是微秒,值会不同。
3 内核2.4的方法主要有以下不同:
编译模块是不需要Makefile文件,直接在终端下输入命令 : gcc –D__KERNEL__ -DMODULE -Wall -c HelloWorld.c -I /usr/src/linux-版本/include (注意 KERNEL前后各是两
条下划线,不是一条)
命令生成目标程序HelloWorld.o
加载时 insmod ./HelloWorld.o (2.6加载的是.ko文件) 卸载同2.6
在2.4内核中,系统变量xtime 类型是timeval,与gettimeofday的参数类型相同,因此在2.4内核下查看结果,第一个是秒,第二个是微秒,数值分别相同。