linux编写一个简单的内核模块 您所在的位置:网站首页 linux内核模块的基本结构有哪些 linux编写一个简单的内核模块

linux编写一个简单的内核模块

#linux编写一个简单的内核模块| 来源: 网络整理| 查看: 265

编写一个简单的内核模块 (一)实验目的

Linux 操作系统的内核是单一体系结构(monolithic kernel)的,也就是说,整个内核是一个单独的非常大的程序。这样,系统的速度和性能都很好,但是可扩展性和维护性就相对比较差。为了弥补单一体系结构的这种缺陷,Linux操作系统使用了一种全新的机制-模块机制,用户可以根据需要,在不需要对内核重新编译的情况下,模块能动态地载入内核或从内核移出。 本实验通过分析代码,学习Linux 是如何实现模块机制的;通过一个实例,掌握如何编写模块程序并进一步掌握内核模块的机理。

(二)实验内容

实验内容一:

(1)编写一个内核模块helloworld.c当用insmod命令加载模块后,会显示HelloWorld !

#include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("jiang shuliang"); MODULE_DESCRIPTION("Hello World Module"); static int __init hello_init(void) { printk(KERN_EMERG"Hello World!\n"); return 0; } static void __exit hello_exit(void) { printk("hello exit\n"); printk(KERN_EMERG"good bye!\n"); } module_init(hello_init); module_exit(hello_exit);

(2)编写Makefile文件

ifneq ($(KERNELRELEASE),) #注意ifneq后空格 obj-m := hello.o else KDIR := /lib/modules/$(shell uname -r)/build #改地址 all: make -C $(KDIR) M=$(PWD) modules #注意tab clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers endif

(3)执行make生成.ko文件 (4)加载模块 insmod 文件名.ko (5)lsmod | grep 文件名       查看加载的模块 (6)dmesg 查看日志文件中模块输出的内容 (7)rmmod 文件名.ko     移除模块可以使用(5)查看是否移除成功

注意: 1.在makefile编写要使用tab 2.注意ifneq后有空格 3. 内核中无法使用printf 4.注意makefile中obj-m后面.o文件名和.c一致 5.前面的if和后面的endif配对 6.__init __exit 后面的函数内参数要写上void 7.KDIR指向内核位置/lib/modules/内核名称/build是链接指向了/usr/src/内核名文件下 8.在ubuntu系统中设置了printk的级别也需要在dmesg中查看

实验内容二: 编写一个包含2.c文件的内核模块程序,进行编译,掌握多文件模块编译的方法及Makefile书写规则!

编写两个.c文件

hello1.c

#include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("jiang shuliang"); MODULE_DESCRIPTION("Hello World Module"); static int __init hello_init(void) { printk(KERN_EMERG"Hello World1!\n"); return 0; } static void __exit hello_exit(void) { printk("hello exit1!\n"); printk(KERN_EMERG"good bye!\n"); }

hello2.c

#include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("jiang shuliang"); MODULE_DESCRIPTION("Hello World Module"); static int __init hello_init(void) { printk(KERN_EMERG"Hello World2!\n"); return 0; } static void __exit hello_exit(void) { printk("hello exit2!\n"); printk(KERN_EMERG"good bye!\n"); } 编写Makefile ifneq ($(KERNELRELEASE),) obj-m := hello1.o hello2.o else KDIR := /lib/modules/$(shell uname -r)/build #改地址 all: make -C $(KDIR) M=$(PWD) modules #注意tab clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers endif

3.生成两个.ok文件同上个实验加载模块查看卸载即可

实验内容三:

一. 原理 module_param 1.为什么引入 在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递命令行参数. 2. module_param宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,具体定义如下:

/* Helper functions: type is byte, short, ushort, int, uint, long, ulong, charp, bool or invbool, or XXX if you define param_get_XXX, param_set_XXX and param_check_XXX.

*/ #define module_param_named(name, value, type, perm) param_check_##type(name, &(value)); module_param_call(name, param_set_##type, param_get_##type, &value, perm); __MODULE_PARM_TYPE(name, #type)

#define module_param(name, type, perm) module_param_named(name, name, type, perm)

由此可知 module_param的实现是通过module_param_named(name, name, type, perm)的。 3.module_param使用了3个参数:变量名,它的类型,以及一个权限掩码用来做一个辅助的sysfs入口。 这个宏定义应当放在任何函数之外,典型地是出现在源文件的前面。

eg: static char *whom=“world” static int tige=1; module_param(tiger,int,S_IRUGO); module_param(whom,charp,S_IRUGO);

4.模块参数支持许多类型: bool invbool 一个布尔型( true 或者 false)值(相关的变量应当是 int 类型). invbool 类型颠倒了值, 所以真值变成 false, 反之亦然. charp :一个字符指针值. 内存为用户提供的字串分配, 指针因此设置. int long short uint ulong ushort 基本的变长整型值. 以 u 开头的是无符号值. 5.数组参数, 用逗号间隔的列表提供的值, 模块加载者也支持。

声明一个数组参数, 使用: module_param_array(name,type,num,perm); 这里 name 是你的数组的名子(也是参数名), type 是数组元素的类型, num 是一个整型变量, perm 是通常的权限值. 如果数组参数在加载时设置, num 被设置成提供的数的个数. 模块加载者拒绝比数组能放下的多的值.

Tiger-John说明:

perm参数的作用是什么? 最后的 module_param 字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 中定义的值. 这个值控制谁可以存取这些模块参数在 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 修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.

二.实例:

说了这么多,看一个程序体验以下: file name : module_param.c

#include #include #include MODULE_LICENSE("GPL"); static char *who; static int times; module_param(who,charp,0644); module_param(times,int,0644); static int __init hello_init(void) { int i; for(i = 1;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有