存档

文章标签 ‘module’

Linux 2.6内核下实现一个操作/proc的内核模块

2009年5月18日 1 条评论

Linux课程实践的一次作业,要求在linux下构建一个在/proc中实现clock文件的模块,该文件支持读操作。
然后开始疯狂的google操作。进而发现整个流程应该是这样的
如果是ubuntu或者fedora发行版,需要配置对应的内核开发环境,而SUSE Enterprise则不用。我用的是ubuntu,在这里就简要的介绍一下ubuntu下内核开发环境的配置。
首先需要安装源build-essential这个包,对应的命令为

sudo apt-get install build-essential

然后再去下载自己的版本所对应的Linux源代码
查看自己的Linux版本的命令为

uname -a

我自己的显示是2.6.27-14-generic
所以应该去下载2.6.27的Linux源代码,命令为:

sudo apt-get install linux-source-2.6.27

好,等这个包安装完成以后,我们进入/usr/src这个目录下将其解压缩,因为默认是把这个文件下载到这个目录下的,你也可以拷贝这个文件到任何你想要放置的位置进行解压
解压完成以后,进入该目录,进行编译操作,命令如下
Step 1:

make mrproper

一下,这个动作是将你使用的源代码包恢复到初始状态
Step 2:
配置内核
保存原有系统配置文件,将/boot/下的config-2.6.27-14-generic拷贝到/usr/src/linux-source-2.6.27(刚下载下来解压的Linux源码下,并把名字改为.config)
对应命令为

sudo cp /boot/config-2.6.27-14-generic /usr/src/linux-source-2.6.27
sudo mv config-2.6.27-14-generic .config

接着进行内核的配置

sudo apt-get install libncurses5-dev

(make menuconfig要调用的)

make menuconfig

当你make menuconfig后,选倒数第二项:Load an alternate configuration file
把.config加载进来,这样你就能在原来内核的基础之上修改了
Step3:

make

让他编译吧,耐心等待,我笔记本性能比较差,要编译两个小时左右的时间
Step4:

make bzImage

Step5:

make modules

Step6:

make modules_install

Step7:

make install

重新启动
至此,内核树就建立啦,我们就可以进行相应的内核模块的开发了
贴上自己的clock.c文件,该文件读取内核时间,然后在/proc目录下创建一个clock文件,在clock文件里打印出系统自1970年1月1日起的秒数和纳秒数,中间用空格隔开

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#define PROCFS_NAME	"clock"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("conan");
 
static struct proc_dir_entry *clock_proc_file;
 
//called when a read is done on /proc/my_clock
int read_time(char *buf,char **start,off_t offset,int count,int *eof,void *data){
 
  struct timespec now;
  int len = 0;
  if (offset > 0)
  {
    printk(KERN_INFO "offset %d : /proc/%s : read_time, \
       wrote %d Bytes\n", (int)(offset),PROCFS_NAME, len);
    *eof = 1;
    return len;
  }
  now = current_kernel_time();
  len = sprintf(buf, "%ld %ld\n", now.tv_sec, now.tv_nsec);
  printk(KERN_INFO "now time is %s\n",buf);
  return len;
}
 
 
//called when module is inserted in system
int init_module(){
  int ret_value = 0;
  clock_proc_file=create_proc_entry(PROCFS_NAME,0644,NULL);
  clock_proc_file->read_proc = read_time;
  printk(KERN_INFO "Trying to create /proc/clock:\n");
  if (clock_proc_file == NULL)
  {
    ret_value = -ENOMEM;
    printk(KERN_INFO "Error: Could not initialize /proc/%s\n",PROCFS_NAME);
  }
  else
  {
    printk(KERN_INFO "Initialize /proc/%s\n",PROCFS_NAME);
  }
  return ret_value;
}
//called to remove module from system
void cleanup_module(){
  remove_proc_entry(PROCFS_NAME,NULL);
  printk(KERN_INFO "/proc/%s removed\n",PROCFS_NAME);
}

接着是这个文件的Makefile
obj-m := clock.o
KDIR = /usr/src/linux-source-2.6.27/
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions
编译的时候千万要注意Makefile和clock.c(不要改名,除非对应的Makefile也改)一定要在一个名字中没有空格的文件夹中,否则就会出现没有找到对应规则的错误!我搞了近两个小时才发现了这个问题。
编译完成之后使用命令insmod clock.ko装载该模块,这个时候就可以
cat /var/log/syslog查看相应的输出信息了,如果模块被正确装载,则会在这个文件的底部出现相应的调试信息。
接着,再是我的测试程序,这个程序对/proc/clock进行了读取,并将读取的值与gettimeofday获取的值作比较。
代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#define MAX 10
#define LENGTH 21
 
int main(){
   int i;
   FILE *my_clock;
   struct timeval gtodTimes[MAX];
   char procClockTimes[MAX][LENGTH];
 
   printf("Please wait for a while, test is running...\n");
   //getting times from both module and system call
   for(i=0;i<MAX;i++){
      my_clock = fopen("/proc/clock", "r");
      if (my_clock == NULL)
      {
         printf("/proc/clock doesn't exist\n");
         exit(1);
      }
      else
      {
         gettimeofday(&gtodTimes[i], NULL);
         fgets(procClockTimes[i], LENGTH, my_clock);
         fclose(my_clock);
         sleep(1);
      }
   }
   //printing data
   for(i=0;i<MAX;i++){
      char *nsec_pointer;
      char *delim = " ";
      nsec_pointer = strtok(procClockTimes[i],delim);
      nsec_pointer = strtok(NULL,delim);
      printf("At iteration %d, Gettimeofday=%lds %ldus, myClock=%ss %sns\n", i,
             gtodTimes[i].tv_sec, gtodTimes[i].tv_usec ,procClockTimes[i],nsec_pointer);
   }
   return(0);
}