一个简单的内核模块编写到测试的全过程。由于是初学者,第一次接触内核模块编写,所以今天花了5个小时才完全搞通。本文针对的linux内核版本号是:linux-2.4.20.8
1. 模块程序的编写
建立testmodule.c 文件,输入以下代码
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
代码为:
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "asm/uaccess.h"
#include "linux/errno.h"
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include<linux/modversions.h>
#endif
int open(struct inode *inode,struct file *filp)
{
MOD_INC_USE_COUNT;
printk("This module is in open!\n");
return 0;
}
void release(struct inode *inode,struct file *filp)
{
MOD_DEC_USE_COUNT;
// return 0;
#ifdef DEBUG
printk("release(%p,%p)\n",inode,filp);
#endif
}
int read(struct file *filp,char *buf,int count,loff_t *t)
{
int leave;
char ch='a';
//if(verify_area(VERIFY_WRITE,buf,count)==DEFAULT)
//return -1; 这里之所以注释掉是因为我没找到DEFAULT的定义
verify_area(VERIFY_WRITE,buf,count);
for(leave=count;leave>0;leave--)
{
__put_user('A',buf);
//if(__copy_to_user(buf,&ch,1))
//printk("copy_to_user failed!\n");
buf++;
}
return count;
}
int write(struct inode *inode,struct file *filp,const char *buf,int count)
{
return count;
}
struct file_operations chr_fops={
owner:THIS_MODULE,
read:read,
write:write,
open:open,
release:release
};
//struct file_operations chr_fops;
int dev;
int init_module()
{
int res;
printk("Hello! This is a testing moudle!\n");
if((res=register_chrdev(0,"gogogog",&chr_fops))<0)
printk("register failed!\n");
dev=res;
return 0;
}
void cleanup_module()
{
unregister_chrdev(dev,"gogogog");
printk("Sorry! The testing module is unloading now!\n");
}
2. 编译选项为:
gcc -O2 -Wall -DMODULE -D__KERNEL__ -DLINUX -I /usr/src/linux-2.4.20-8/include/ -c testmodule.c
编译后出现以下情况
我看都是警告,所以就没继续修改(也不知道怎么修改,如果您知道了,希望能相告,共同学习!
参数解释:
l -O2 表示需要对模块程序进行优化编译、链接
l -Wall 参数向装在程序传递all。
l -I /usr/src/linux-2.4.20-8/include/ 这个参数很重要。否则会提示错误`struct file' declared inside parameter list、`struct inode' declared inside parameter list、In file included from /usr/include/linux/fs.h:23,from testmodule.c:4:
/usr/include/linux/string.h:8:2: warning: #warning Using kernel header in userland!等错误。
#warning Using kernel header in userland! 这个也许会好奇,我怎么加了-I参数后还会有这个警告呢。原因很简单,你包含头文件时用的是尖括号。尖括号大家都知道是去系统默认路径中找。所以这里应该改成双引号包含!!!
当然如果嫌输入的编译命令太多,那么可以写makefile文件。
3. 编写测试程序test.c
代码如下:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int i,testmoduledev;
char buf[10]={0};
testmoduledev=open("/dev/moduledev",O_RDWR);
printf("%d\n",testmoduledev);
if(testmoduledev==-1)
{
printf("can't open the file!\n");
exit(0);
}
read(testmoduledev,buf,10);
for(i=0;i<10;i++)
printf("%d\n",buf[i]);
close(testmoduledev);
return 0;
}
4. 装载模块
Insmod testmodule.o
此时模块装入到内核中。
5. 然后我们要做的是这个模块设备创建设备文件moduledev(一个名字而已)。使用命令mknod /dev/moduledev c major minjor.其中c表示moduledev是字符设备。major是该设备的主设备号。其实后面读该设备时用到的也是主设备号。这个主设备号不能自己随意而定而是由系统分配的。因为装载模块后只要你的驱动程序通过函数register_chrdev(0,"gogogog",&chr_fops))注册后便会在系统中得到主设备号,此时只需要通过命令cat /proc/devices 查看便可,所以上面的major要到这里查看得到的值。
此时已经建立好了该设备的设备文件。然后便可以编译运行测试文件,从该设备文件中读取字符。
注意:
l #include "asm/uaccess.h" 这个头文件,如果不包含头文件会提示警告:warning: implicit declaration of function `__put_user' 如果你不管这个警告,继续强行装入模块时,会遇到下面的无法解析sysbol 的错误。
以上是自己经过一晚上的努力才搞通的一个简单系统模块。贴出来跟大家分享~。我的内核版本是:2.4.20-8