日期:2014-05-16  浏览次数:20802 次

32位linux内核2.6.38.2添加系统调用,并编写模块模拟ps命令显示进程信息
现在我用的是虚拟机下ubuntu10.10,内核版本已经升级到2.6.38.2,要完成的任务有:

1,在内核的结构体task_struct中添加一个数据成员ctx,记录每个进程切换(被调度)的次数,并编写一个模块显示进程的信息,包括该数据成员的值;

2,在内核中增加一个系统调用,并编写用户态程序调用该系统调用;

首先,准备内核内核源码。

1,make mrproper;清除之前编译内核时的残存配置文件,和一些生成的映像,(据说可以不执行make mrproper和make clean来实现增量编译,但个人认为不可取,至于linux内核的增量编译目前个人并不懂,希望有人能讲解一下)。

2,为了任务1;在task_struct中添加一个数据成员,在include/linux/sched.h中找到task_struct所在位置,添加一个成员
unsigned int ctx;

在kernel/fork.c中找到do_fork函数,在其中舒适化该数据成员ctx,初始化的位置就是进程刚刚被建立的时候,而linux系统建立进程一般都是通过复制父进程的数据结构来完成的,所以在cope_process被执行后,添加
p->ctx=0;

在?kernel/sched.c中找到schedule函数,当进程(switch)发生切换时,添加
next->ctx++;

,该数值加1。

3,为了任务2;在kernel/sys.c中(结尾)添加一个自定义的函数(系统调用),

asmlinkage int sys_mycall(int num) 

{    

printk(KERN_INFO "success!\n");    

return num; 

}  
                 

在arch/x86/include/asm/unistd_32.h中添加一个系统调用号的定义
#define __NR_mycall  341
并把最后的那个__NR_syscall 341改为342,这相当于一个结束符,我们的系统调用号要加在该结束符前面;其最终代码如下:
 #define __NR_fanotify_mark	339
 #define __NR_prlimit64		340
 #define __NR_mycall			341
 #ifdef __KERNEL__
 #define NR_syscalls 342

在arch/x86/kernel/syscall_table_32.S
中添加
.long sys_mycall

;                           
               2,3两步可参考文后给出的patch文件内容。

4, 重新编译内核,请参考前一篇文章,但注意,无须编译内核模块,时间在30分钟左右,重启。
5,编写用户态程序
5.1)
任务1,编写一个模块,显示当前进程的状态信息:  
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>

#define MODULE_VERSION "1.0"
#define MODULE_NAME "proc_interface"
#define FOOBAR_LEN 8

struct fb_data_t {
	char name[FOOBAR_LEN+1];
 	char value[FOOBAR_LEN+1];
};


static struct proc_dir_entry *example_dir,*foo_file, *bar_file,*jiffies_file,*symlink;
struct fb_data_t foo_data,bar_data;


static int proc_read_jiffies(char *page,char **start, off_t off,int count,  int *eof,void *data)
{
	int len;
 	len=sprintf(page,"jiffies=%ld\n", jiffies);
 	return len;
}
static int proc_read_foobar(char *page,char **start, off_t off,int count, int *eof,void *data)
{
 	int len;
 	struct fb_data_t *fb_data=(struct fb_data_t *)data;
 	
 	len=sprintf(page,"%s='%s'\n", fb_data->name,fb_data->value);
 	
 	return len;
}

static int proc_write_foobar(struct file *file, const char *buffer, unsigned long count, void *data)
{
 	int len;
 	struct fb_data_t *fb_data=(struct fb_data_t *)data;
 	
 	if(count>FOOBAR_LEN)
		len=FOOBAR_LEN;
 	else
   		len=count;
	if(copy_from_user(fb_data->value,buffer,len)){
   		
   		return -EFAULT;
 	}
	fb_data->value[len]='\0';
 	
	return len;
} 

static int __init hello_init(void)
{
	 int rv=0;
	
 	example_dir=proc_mkdir(MODULE_NAME,NULL);
 	if(example_dir==NULL){
		rv=-ENOMEM;
   		goto out;
     	}
	example_dir->owner=THIS_MODULE;

	
 	jiffies_file=create_proc_read_entry("jiffies", 0444,example_dir, proc_read_jiffies, NULL);
 	if(jiffies_file==NULL){
		rv=-ENOMEM;
   		goto no_jiffies;
 	}
 	jiffies_file->owner=THIS_MODULE;

	
 	foo_file=create_proc_entry("foo",0644,example_dir);
 	if(foo_file==NULL){
   		rv=-ENOMEM;
  	 goto no_foo;
 	}

 	strcpy(foo_data.name,"foo");
 	strcpy(foo_data.value,"foo");
 	foo_file->data=&foo_data;
 	foo_file->read_proc=proc_read_foobar;
 	foo_file->write_proc=proc_write_foobar;
 	foo_file->owner=THIS_MODULE;

 	bar_file=create_proc_entry("b