- 浏览: 44032 次
文章分类
最新评论
内核模块编写
* 内核动态模块的的功能和作用*
Linux 模块是一些可以独立于内核单独编译的内核函数和数据类型集合,是可增删的内核部分。模块在内核启动时装载称为静态装载,在内核已经运行时装载称为动态装载。模块可以扩充内核所期望的任何功能,但通常用于实现设备驱动程序.
模块最基本的框架
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
static ini __init 模块名_init(void)
{
/*
* 安装模块的初始化工作 „„
*/
return 0;
}
Static void __exit 模块名_exit(void)
{
/*
* 卸载模块前的清理工作 „„
*/
}
module_init(模块名_init);
module_exit(模块名_exit);
动态模块的编译
Makefile 文件的约定
预定义的宏:
obj-m := 模块名.o
预定义的命令:
make –C 内核源代码的安装路径 M=动态模块源代码路径 modules
将生成动态安装的模块文件:模块名.ko
例如:
obj-m := hello.o
all:
make -C /lib/modules/<nobr><span class="math" id="MathJax-Span-772" style="width: 13.148em; display: inline-block;"><span style="display: inline-block; position: relative; width: 12.393em; height: 0px; font-size: 106%;"><span style="position: absolute; clip: rect(1.827em 1000.003em 3.211em -0.5em); top: -2.764em; left: 0.003em;"><span class="mrow" id="MathJax-Span-773"><span class="mo" id="MathJax-Span-774" style="font-family: MathJax_Main;">(</span><span class="mi" id="MathJax-Span-775" style="font-family: MathJax_Math-italic;">s</span><span class="mi" id="MathJax-Span-776" style="font-family: MathJax_Math-italic;">h</span><span class="mi" id="MathJax-Span-777" style="font-family: MathJax_Math-italic;">e</span><span class="mi" id="MathJax-Span-778" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-779" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-780" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-781" style="font-family: MathJax_Math-italic;">n</span><span class="mi" id="MathJax-Span-782" style="font-family: MathJax_Math-italic;">a</span><span class="mi" id="MathJax-Span-783" style="font-family: MathJax_Math-italic;">m</span><span class="mi" id="MathJax-Span-784" style="font-family: MathJax_Math-italic;">e</span><span class="mo" id="MathJax-Span-785" style="font-family: MathJax_Main; padding-left: 0.255em;">−</span><span class="mi" id="MathJax-Span-786" style="font-family: MathJax_Math-italic; padding-left: 0.255em;">r</span><span class="mo" id="MathJax-Span-787" style="font-family: MathJax_Main;">)</span><span class="texatom" id="MathJax-Span-788"><span class="mrow" id="MathJax-Span-789"><span class="mo" id="MathJax-Span-790" style="font-family: MathJax_Main;">/</span></span></span><span class="mi" id="MathJax-Span-791" style="font-family: MathJax_Math-italic;">b</span><span class="mi" id="MathJax-Span-792" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-793" style="font-family: MathJax_Math-italic;">i</span><span class="mi" id="MathJax-Span-794" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-795" style="font-family: MathJax_Math-italic;">d<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span class="mi" id="MathJax-Span-796" style="font-family: MathJax_Math-italic;">M<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.066em;"></span></span><span class="mo" id="MathJax-Span-797" style="font-family: MathJax_Main; padding-left: 0.255em;">=</span></span><span style="display: inline-block; width: 0px; height: 2.77em;"></span></span></span><span style="border-left-width: 0.003em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.203em; vertical-align: -0.33em;"></span></span></nobr><script type="math/tex" id="MathJax-Element-31">(shell uname -r)/build M=</script>(shell pwd) modules
clean:
make -C /lib/modules/<nobr><span class="math" id="MathJax-Span-798" style="width: 13.148em; display: inline-block;"><span style="display: inline-block; position: relative; width: 12.393em; height: 0px; font-size: 106%;"><span style="position: absolute; clip: rect(1.827em 1000.003em 3.211em -0.5em); top: -2.764em; left: 0.003em;"><span class="mrow" id="MathJax-Span-799"><span class="mo" id="MathJax-Span-800" style="font-family: MathJax_Main;">(</span><span class="mi" id="MathJax-Span-801" style="font-family: MathJax_Math-italic;">s</span><span class="mi" id="MathJax-Span-802" style="font-family: MathJax_Math-italic;">h</span><span class="mi" id="MathJax-Span-803" style="font-family: MathJax_Math-italic;">e</span><span class="mi" id="MathJax-Span-804" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-805" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-806" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-807" style="font-family: MathJax_Math-italic;">n</span><span class="mi" id="MathJax-Span-808" style="font-family: MathJax_Math-italic;">a</span><span class="mi" id="MathJax-Span-809" style="font-family: MathJax_Math-italic;">m</span><span class="mi" id="MathJax-Span-810" style="font-family: MathJax_Math-italic;">e</span><span class="mo" id="MathJax-Span-811" style="font-family: MathJax_Main; padding-left: 0.255em;">−</span><span class="mi" id="MathJax-Span-812" style="font-family: MathJax_Math-italic; padding-left: 0.255em;">r</span><span class="mo" id="MathJax-Span-813" style="font-family: MathJax_Main;">)</span><span class="texatom" id="MathJax-Span-814"><span class="mrow" id="MathJax-Span-815"><span class="mo" id="MathJax-Span-816" style="font-family: MathJax_Main;">/</span></span></span><span class="mi" id="MathJax-Span-817" style="font-family: MathJax_Math-italic;">b</span><span class="mi" id="MathJax-Span-818" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-819" style="font-family: MathJax_Math-italic;">i</span><span class="mi" id="MathJax-Span-820" style="font-family: MathJax_Math-italic;">l</span><span class="mi" id="MathJax-Span-821" style="font-family: MathJax_Math-italic;">d<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span class="mi" id="MathJax-Span-822" style="font-family: MathJax_Math-italic;">M<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.066em;"></span></span><span class="mo" id="MathJax-Span-823" style="font-family: MathJax_Main; padding-left: 0.255em;">=</span></span><span style="display: inline-block; width: 0px; height: 2.77em;"></span></span></span><span style="border-left-width: 0.003em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.203em; vertical-align: -0.33em;"></span></span></nobr><script type="math/tex" id="MathJax-Element-32">(shell uname -r)/build M=</script>(shell pwd) clean
如果有多个目标模块:
obj-m := hello.o
hello-objs := a.o b.o
与动态模块有关的 Shell 命令
列出已安装的动态模块名:
lsmod
安装一个动态模块:
insmod 模块名.ko
卸载一个动态模块:
rmmod 模块名.ko
安装依赖模块:
modprobe
显示模块信息:
modinfo 模块名.ko
模块安装时携带的可选参数
#include <linux/moduleparam.h>
module_param(变量名,类型,权限)
支持的类型:
Byte.short,ushort,int,uint,long,ulong,bool,charp
例如在 hello.c 中加入:
#include <linux/moduleparam.h>
static int test;
module_param(test,int,0644);
用法 :
insmod hello.ko test=10
许可和文档有关的宏
MODULE_LICENSE(“GPL”);
MODULE_DESCRIPTION(“xxxxxxxx”);
MODULE_AUTHOR(“xxxxxxx”);
在模块中使用内核的/proc 接口
//建立一个 proc 目录文件:
struct proc_dir_entry *proc_mkdir(const char *,
/*要创建的 proc 目录名*/
struct proc_dir_entry *
/*上级目录,NULL 代表/proc*/
);
//建立一个 proc 普通文件:
struct proc_dir_entry *create_proc_entry(const char *name,
/*要创建的 proc 文件名*/
mode_t mode,
/*proc 文件的权限*/
struct proc_dir_entry *parent/*上级目录,NULL 代表/proc*/
);
//删除一个 proc 文件:
void remove_proc_entry(const char *name, /*要删除的 proc 文件名*/
struct proc_dir_entry *parent /*上级目录,NULL 代表/proc*/
);
//proc 入口数据结构:
struct proc_dir_entry {
unsigned int low_ino;
/*目录入口的 inod 节点号*/
unsigned short namelen;
/*节点名长度*/
const char *name;
/*节点名*/
mode_t mode;
/*节点类型和权限*/
nlink_t nlink;
/*节点的连接数*/
uid_t uid;
/*拥有该节点的用户 uid*/
gid_t gid;
/*拥有该节点的组 gid*/
loff_t size;
/*节点的大小,除非限制长度否则为0*/
struct inode_operations * proc_iops;
/*对该节点的操作*/
const struct file_operations * proc_fops;
/*对该文件的操作*/
get_info_t *get_info;
/*如果定义,则当有读操作时调用*/
struct module *owner;
/*拥有该节点的模块*/
struct proc_dir_entry *next, *parent, *subdir;/*节点间的关系,初始为 NULL*/
void *data;
/*节点对应文件中内容*/
read_proc_t *read_proc;
/*读操作函数*/
write_proc_t *write_proc;
/*写操作函数*/
atomic_t count;
/* 节点引用计数 */
int deleted;
/* 节点删除标志 */
void *set;
};
//其中几个重要的字段:
owner=THIS_MODULE;
data=指向文件数据区(自己定义)
read_proc=指向你的读操作处理函数(自己定义)
write_proc=指向你的写操作处理函数(自己定义)
//读写操作函数的参数:
int (read_proc_t)(char *page,
/*存读出数据的地址*/
char **start, /*内核中不用*/
off_t off, /*读出数据结构在page中的偏量*/
int count, /*读出数据字节数*/
int *eof, /*文件尾标志*/
void *data); /*文件数据的地址*/
int (write_proc_t)(struct file *file,
/*通常不用*/
const char __user *buffer, /* 用 户 空 间 数 据 地 址 , 需 要 用
copy_from_user 写入*/
unsigned long count,
/*从用户空间写入的数据长度*/
void *data);
/*写入文件的地址*/
下面我们编辑一个Hello World模块
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
int init_module(void){
printk("Hello Module!!\n");
return 0;
}
void cleanup_module(void){
printk("bye module!!\n");
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hello World!!");
MODULE_AUTHOR("bobo");
其中的Makefile文件为:
obj-m := hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
我们使用make命令进行编译,编译之后的结果是在目录中形成下面的文件:
下面我们将terminal终端的操作目录切换到当前目录下,动态加载该模块:
sudo insmod hello.ko
我们使用dmesg命令查看内核模块内容的输出:
dmesg
下面是我的模块的输出结果:
现在我们使用卸载模块的命令进行卸载:
sudo rmmod hello
模块输出信息为:
这是一个最简单的内核模块.
下面我们使用内核模块来创建proc文件,并向文件中写入内容.下面是我的程序的实现:
/********************************************
编写创建proc文件系统的模块,该程序创建在/proc目录下
创建mydir目录,在mydir目录下创建保存当前系统时间
: jiffies 值的文件 myfile
***********************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <linux/moduleparam.h>
#define MODULE_NAME "Myproc"
#define MYDATA_LEN 16
//放用户空间传入的数据
struct my_proc_data{
char value[MYDATA_LEN];
};
struct my_proc_data mydata;
//proc结构变量
static struct proc_dir_entry *example_dir;
static struct proc_dir_entry *date_file;
static int param;
module_param(param,int,0644);
//读文件myfile的读驱动函数
static int proc_read(char *page,char **start,off_t off,int count,int *eof,void *data){
int len = 0;
struct my_proc_data *mydatap = (struct my_proc_data *)data;
len += sprintf(page,"%s%ld\n",mydatap->value,jiffies);
return len;
}
//写文件myfile的写驱动函数
static int proc_write(struct file *file,const char *buffer,unsigned long
count,void *data){
int len;
struct my_proc_data *mydatap = (struct my_proc_data *)data;
if(count > MYDATA_LEN)
len = MYDATA_LEN;
else
len = count;
if(copy_from_user(mydatap->value,buffer,len)){
return -EFAULT;
}
mydatap->value[len-1] = '\0';
return len;
}
//装入模块
int init_module(void){
//创建/proc/myfile目录
example_dir = (struct proc_dir_entry *)proc_mkdir("mydir",0);
if(example_dir == 0){
printk("mkdir fail\n");
return -1;
}
//创建/proc/mydir/myfile文件
date_file = (struct proc_dir_entry *)create_proc_entry("myfile",0666,example_dir);
if(date_file == 0){
remove_proc_entry("myfile",0);
printk("mkfile fail\n");
return -ENOMEM;
}
strcpy(mydata.value,"Ticks=");
date_file->data = &mydata;
date_file->read_proc = &proc_read;
date_file->write_proc = &proc_write;
date_file->owner=THIS_MODULE;
return 0;
}
//卸载模块
void cleanup_module(void)
{
remove_proc_entry("myfile",example_dir);
remove_proc_entry("mydir",NULL);
printk("Goodbye.\n");
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TEST");
MODULE_AUTHOR("bobo");
其中,Makefile文件为:
obj-m := mod.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
同样的道理编译完成之后,我们使用insmod命令将文件加载到内核中,我们查看/proc目录下是否有我们创建的mydir文件夹,并且该文件夹下面存在一个名为myfile的文件,同时我们查看其中的内容.
下面我们编写一个用户空间程序,来测试用户读取/proc/mydir/myfile文件所用的时间,我们使用的是系统提供的gettimeofday函数.
其中gettimeofday()函数有两个参数:
int gettimeofday(struct timeval *tv,struct timezone *tz);
其中的数据结构timeval为:
struct timeval{
long int tv_sec; //秒数
long int tv_usec; //毫秒
};
数据结构timezone为时区,如果不用就设置为NULL
下面是我的用户测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#define path "/proc/mydir/myfile"
//字符串的长度
#define LEN 16
//读取之前的时间
struct timeval tv_begin;
//读取之后的时间
struct timeval tv_end;
//存储读出的字符串的长度
char buf[LEN];
int main()
{
FILE *fp;
gettimeofday(&tv_begin,NULL);
fp = fopen(path,"r");
printf("%s\n",fgets(buf,LEN,fp));
gettimeofday(&tv_end,NULL);
printf("used %d s %d us\n",tv_end.tv_sec-tv_begin.tv_sec,tv_end.tv_usec-tv_begin.tv_usec);
return 0;
}
我们使用命令:
gcc test.c -o test
编译之后,运行
./test
其运行结果为:
下面一篇博客我将使用内核模块从当前进程开始,向前遍历,一直遍历到初始进程,将其信息保存到proc文件中.
## 未完待续!!!!##
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关推荐
北邮操作系统课程设计——基于linux的内核模块编写+源代码+文档说明+实验报告 - 小白不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审...
嵌入式操作系统作业,Linux自定义内核模块编写,Linux进程间通信(Socket IPC)+源代码+文档说明 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源...
详细解释了内涵模块的编写,是以实验形式的来写的,总结提高必备,觉得很好。
本例子是关于如何添加一个内核模块的代码,已经测试通过,下载后make可以直接使用。
LINUX内核模块编程LINUX内核模块编程LINUX内核模块编程
这是我从网上找的一篇关于Linux内核模块编写的方法,写得很好很详细,适合Linux内核初学者
【项目资源】: 包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。 ... 【项目质量】: 所有源码都经过严格测试,...
linux内核模块编写 例子程序 导出符号的使用
接下来会在第3章对内核模块的细节做更多详细的分析, 以便我们能深入理解内核模块, 并编写出专业的内核模块. 这一章需要反复阅读理解. 可能过段时间或者遇到具体项目的时候, 还需要拿出来再重新阅读. 最后第4章是驱动...
你是否曾经疑问过我们编写的内核模块是什么时候,如何加载到内核的,本文将为你揭开迷惑。
为了解决这个问题,引入了内核机制,从而可以动态的想内核中添加或者删除模块。模块不被编译在内核中,因而控制了内核的大小。然而模块一旦被插入内核,他就和内核其他部分一样。这样一来 就会曾家一部分系统开销。同时,...
内核模块的编写示例代码
锈编写内核模块 加州州立大学-奇科 通过布莱恩·迪克森 介绍 此作业的目的是让您更加熟悉内核模块的编写方式以及使用这些模块的 Linux 操作系统的各个方面。 物流 唯一的“交接”将是电子的。 对作业的任何澄清和...
Linux内核模块和驱动的编写 Linux内核模块和驱动的编写
介绍linux内核模块的开发,内核驱动的编写,对从事驱动开发的人员可能会有用
Linux内核模块的编写及技巧 运行环境:linux gcc
适用于操作系统第3版微课版
实验目标:在Linux内核中增加一个系统调用,并编写对应的linux应用程序。利用该系统调用能够遍历系统当前所有进程的任务描述符,并按进程父子关系将这些描述符所对应的进程id(PID)组织成树形结构显示。 实验环境:...
linux内核可加载模块编写的实例,包括编译和加载,以及运行过程的示例,可以供初学者学习使用。
此例为linux 内核模块相互调用实例,亲自编写,开发linux 驱动理解内核工作原理必备