- 浏览: 162745 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
yuanyu5237:
<div class="quote_title ...
32位linux内核2.6.38.2添加系统调用,并编写模块模拟ps命令显示进程信息 -
yuanyu5237:
haolifeng 写道如果不对客户端的连接文件描述符进行监听 ...
简单epoll多线程服务器 -
haolifeng:
如果不对客户端的连接文件描述符进行监听,你这个服务器是有问题的 ...
简单epoll多线程服务器 -
haolifeng:
我对你的代码有一个问题,当获得客户端的连接文件描述符后,为什么 ...
简单epoll多线程服务器 -
Michyo:
你好,我是用了您的第二段模块代码,但是为什么添加了模块后没有输 ...
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所在位置,添加一个成员
在kernel/fork.c中找到do_fork函数,在其中舒适化该数据成员ctx,初始化的位置就是进程刚刚被建立的时候,而linux系统建立进程一般都是通过复制父进程的数据结构来完成的,所以在cope_process被执行后,添加
在?kernel/sched.c中找到schedule函数,当进程(switch)发生切换时,添加
,该数值加1。
3,为了任务2;在kernel/sys.c中(结尾)添加一个自定义的函数(系统调用),
在arch/x86/include/asm/unistd_32.h中添加一个系统调用号的定义
#define __NR_mycall 341
并把最后的那个__NR_syscall 341改为342,这相当于一个结束符,我们的系统调用号要加在该结束符前面;其最终代码如下:
在arch/x86/kernel/syscall_table_32.S
中添加
;
2,3两步可参考文后给出的patch文件内容。
4, 重新编译内核,请参考前一篇文章,但注意,无须编译内核模块,时间在30分钟左右,重启。
5,编写用户态程序
5.1)
任务1,编写一个模块,显示当前进程的状态信息:
5.2;编写模块的Makefile:
5.3; 加载模块sudo insmod pro_example.ko
查看当前已加载模块信息:lsmod
卸载模块sudo rmmod pro_example
当加载完模块后,就可以查看/proc目录下是否生成了相应的文件,并使用cat命令查看文件内容,还可以使用dmesg查看后台打印信息,比如printk的输出,如果要看的更清除一点,使用sudo dmesg -c清除之前的信息
任务2;编写一个程序,调用自定义的系统调用:
5.4,使用syscall函数:
运行程序,输出结果studentnum=100,查看dmesg,有success;则系统调用添加成功,调用该系统调用正确;
5.5;给出我这两次实验的patch文件,不过因为我编程需要,我在proc_dir_entry中添加了一个成员struct proc_dir_entry *owner;
,最后总结一下这两个实验:
1》模块编程,无须重新编译内核,一定要写Makefile,要有入口和出口函数;
2》系统调用,3个步骤正确,且必须重新编译内核
************对于,很多人在使用/proc/plist来列出当前进程信息的时候,可能出现显示列表不全的问题,可使用下面的程序(主要使用了seq_file接口)来解决该问题:
我的理解,加载模块后可以去/proc下查看相关信息,那句话只是把相关的函数指针指向真正定义的函数,当你查看信息的时候就会调用这些函数
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("bar",0644,example_dir); if(bar_file==NULL){ rv=-ENOMEM; goto no_bar; } strcpy(bar_data.name,"bar"); strcpy(bar_data.value,"bar"); bar_file->data=&bar_data; bar_file->read_proc=proc_read_foobar; bar_file->write_proc=proc_write_foobar; bar_file->owner=THIS_MODULE; symlink=proc_symlink("jiffies_too",example_dir, "jiffies"); if(symlink==NULL){ rv=-ENOMEM; goto no_symlink; } symlink->owner=THIS_MODULE; printk(KERN_INFO "%s %s initialised\n",MODULE_NAME,MODULE_VERSION); return 0; no_symlink: remove_proc_entry("bar",example_dir); no_bar: remove_proc_entry("foo",example_dir); no_foo: remove_proc_entry("jiffies",example_dir); no_jiffies: remove_proc_entry(MODULE_NAME,NULL); out: return rv; } static void __exit hello_exit(void) { remove_proc_entry("jiffies_too",example_dir); remove_proc_entry("bar",example_dir); remove_proc_entry("foo",example_dir); remove_proc_entry("jiffies",example_dir); remove_proc_entry(MODULE_NAME,NULL); printk(KERN_INFO "%s %s removed\n",MODULE_NAME,MODULE_VERSION); } MODULE_DESCRIPTION("proc example"); MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);
5.2;编写模块的Makefile:
obj-m+=pro_example.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
5.3; 加载模块sudo insmod pro_example.ko
查看当前已加载模块信息:lsmod
卸载模块sudo rmmod pro_example
当加载完模块后,就可以查看/proc目录下是否生成了相应的文件,并使用cat命令查看文件内容,还可以使用dmesg查看后台打印信息,比如printk的输出,如果要看的更清除一点,使用sudo dmesg -c清除之前的信息
任务2;编写一个程序,调用自定义的系统调用:
5.4,使用syscall函数:
#include <linux/unistd.h> #include <stdio.h> int main() { printf("studentnum=%d\n", syscall(341,100)); return 0; }
运行程序,输出结果studentnum=100,查看dmesg,有success;则系统调用添加成功,调用该系统调用正确;
5.5;给出我这两次实验的patch文件,不过因为我编程需要,我在proc_dir_entry中添加了一个成员struct proc_dir_entry *owner;
diff -ruNa linux-2.6.38.2.org/arch/x86/include/asm/unistd_32.h linux-2.6.38.2/arch/x86/include/asm/unistd_32.h --- linux-2.6.38.2.org/arch/x86/include/asm/unistd_32.h 2011-04-12 08:25:50.384313140 -0700 +++ linux-2.6.38.2/arch/x86/include/asm/unistd_32.h 2011-04-12 08:28:59.612312392 -0700 @@ -347,9 +347,11 @@ #define __NR_fanotify_mark 339 #define __NR_prlimit64 340 +#define __NR_mycall 341 + #ifdef __KERNEL__ -#define NR_syscalls 341 +#define NR_syscalls 342 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff -ruNa linux-2.6.38.2.org/arch/x86/kernel/syscall_table_32.S linux-2.6.38.2/arch/x86/kernel/syscall_table_32.S --- linux-2.6.38.2.org/arch/x86/kernel/syscall_table_32.S 2011-04-12 08:25:50.580313137 -0700 +++ linux-2.6.38.2/arch/x86/kernel/syscall_table_32.S 2011-04-12 08:29:22.992312038 -0700 @@ -340,3 +340,4 @@ .long sys_fanotify_init .long sys_fanotify_mark .long sys_prlimit64 /* 340 */ + .long sys_mycall diff -ruNa linux-2.6.38.2.org/include/linux/proc_fs.h linux-2.6.38.2/include/linux/proc_fs.h --- linux-2.6.38.2.org/include/linux/proc_fs.h 2011-04-12 08:25:47.060313136 -0700 +++ linux-2.6.38.2/include/linux/proc_fs.h 2011-04-12 08:38:31.888315451 -0700 @@ -49,6 +49,7 @@ unsigned long count, void *data); struct proc_dir_entry { + struct proc_dir_entry *owner; unsigned int low_ino; unsigned short namelen; const char *name; diff -ruNa linux-2.6.38.2.org/include/linux/sched.h linux-2.6.38.2/include/linux/sched.h --- linux-2.6.38.2.org/include/linux/sched.h 2011-04-12 08:25:47.680313137 -0700 +++ linux-2.6.38.2/include/linux/sched.h 2011-04-12 08:34:24.872313536 -0700 @@ -1191,6 +1191,7 @@ }; struct task_struct { + unsigned int ctx; volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; atomic_t usage; diff -ruNa linux-2.6.38.2.org/kernel/fork.c linux-2.6.38.2/kernel/fork.c --- linux-2.6.38.2.org/kernel/fork.c 2011-04-12 08:25:47.780313137 -0700 +++ linux-2.6.38.2/kernel/fork.c 2011-04-12 08:35:05.188316355 -0700 @@ -1441,6 +1441,8 @@ nr = task_pid_vnr(p); + p->ctx=0; + if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); diff -ruNa linux-2.6.38.2.org/kernel/sched.c linux-2.6.38.2/kernel/sched.c --- linux-2.6.38.2.org/kernel/sched.c 2011-04-12 08:25:47.756313137 -0700 +++ linux-2.6.38.2/kernel/sched.c 2011-04-12 08:33:38.564317495 -0700 @@ -3996,6 +3996,8 @@ rq->curr = next; ++*switch_count; + next->ctx++; + context_switch(rq, prev, next); /* unlocks the rq */ /* * The context switch have flipped the stack from under us diff -ruNa linux-2.6.38.2.org/kernel/sys.c linux-2.6.38.2/kernel/sys.c --- linux-2.6.38.2.org/kernel/sys.c 2011-04-12 08:25:47.744313137 -0700 +++ linux-2.6.38.2/kernel/sys.c 2011-04-12 08:28:19.656312264 -0700 @@ -1762,6 +1762,13 @@ argv_free(info->argv); } + +asmlinkage int sys_mycall(int num) +{ + printk(KERN_INFO "success!"); + return num; +} + /** * orderly_poweroff - Trigger an orderly system poweroff * @force: force poweroff if command execution fails
,最后总结一下这两个实验:
1》模块编程,无须重新编译内核,一定要写Makefile,要有入口和出口函数;
2》系统调用,3个步骤正确,且必须重新编译内核
************对于,很多人在使用/proc/plist来列出当前进程信息的时候,可能出现显示列表不全的问题,可使用下面的程序(主要使用了seq_file接口)来解决该问题:
#include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> //proc_fs #include <linux/seq_file.h> //seq_file #include <linux/fs.h> //struct file,struct inode #include <linux/sched.h> //next_task() MODULE_AUTHOR("vampire"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("a test module utilise the seq_file mechanism"); static void *ps_seq_start(struct seq_file *s,loff_t *pos){ struct task_struct *task; seq_printf(s,"%s\t%s\t%s\t%s\t%s\t%s\n","pid","ppid","uid","gid","comm","ctx"); if(*pos>0) return NULL; else{ task=next_task(current); return task; } } static void *ps_seq_next(struct seq_file *s,void *v,loff_t *pos){ struct task_struct *task=(struct task_struct *)v; ++*pos; if(task->pid== current->pid){ return NULL; }else{ task=next_task(task); return task; } } static void ps_seq_stop(struct seq_file *s,void *v){} static int ps_seq_show(struct seq_file *s,void *v){ rwlock_t lock = RW_LOCK_UNLOCKED; struct task_struct *task=(struct task_struct *)v; read_lock(&lock); seq_printf(s,"%d\t%d\t%d\t%d\t%s\t%d\n",task->pid,task->parent->pid,task->uid,task->gid,task->comm,task->ctx); read_unlock(&lock); return 0; } static struct seq_operations ps_seq_ops = { .start = ps_seq_start, .next = ps_seq_next, .stop = ps_seq_stop, .show = ps_seq_show }; static int ps_open(struct inode *inode,struct file *file){ return seq_open(file,&ps_seq_ops); } static struct file_operations ps_file_ops = { .owner = THIS_MODULE, .open = ps_open, .read = seq_read, .llseek = seq_lseek, .release= seq_release }; static int __init ps_init(void){ struct proc_dir_entry *entry; entry = create_proc_entry("plist",0,NULL); if(entry) entry->proc_fops = &ps_file_ops; return 0; } static void __exit ps_exit(void){ remove_proc_entry("plist",NULL); } module_init(ps_init); module_exit(ps_exit);
评论
2 楼
yuanyu5237
2013-12-19
Michyo 写道
你好,我是用了您的第二段模块代码,但是为什么添加了模块后没有输出呢?
entry->proc_fops = &ps_file_ops; 这句话是已经执行了什么了嘛?还是还需要做些什么操作才可以有输出呢?
期待您的回答!
entry->proc_fops = &ps_file_ops; 这句话是已经执行了什么了嘛?还是还需要做些什么操作才可以有输出呢?
期待您的回答!
我的理解,加载模块后可以去/proc下查看相关信息,那句话只是把相关的函数指针指向真正定义的函数,当你查看信息的时候就会调用这些函数
1 楼
Michyo
2013-06-05
你好,我是用了您的第二段模块代码,但是为什么添加了模块后没有输出呢?
entry->proc_fops = &ps_file_ops; 这句话是已经执行了什么了嘛?还是还需要做些什么操作才可以有输出呢?
期待您的回答!
entry->proc_fops = &ps_file_ops; 这句话是已经执行了什么了嘛?还是还需要做些什么操作才可以有输出呢?
期待您的回答!
发表评论
-
hadoop及mahout安装
2012-10-02 12:29 4298环境:虚拟机vmware7+ubuntu12.04 1,先 ... -
shell常用小例子
2012-04-12 11:11 0分析日志时,将按小时存储的文件合并,文件名为小时数: ... -
小型网站上线全纪录
2012-04-07 14:19 1107一个小网站用java开发,struts2+jdbc结构,数据库 ... -
linux磁盘quota设置
2011-10-12 16:56 1284我用的是ubuntu10(虚拟机),已经默认安装了quo ... -
【转载】ubuntu 10.10下安装vmware player
2011-05-02 22:25 1167wget http://www.sputnick-area.n ... -
ubuntu10.10下编译linux内核,升级内核到2.6.38.2
2011-04-06 18:44 2645我的环境是在虚拟机中 ... -
ubuntu菜单面板被误删或右下角回收站丢失解决办法
2011-03-15 14:24 1265命令: 写道 gconftool -- ... -
linux下RAR解压方法
2010-11-20 12:06 3215我用的系统是ubuntu10.10; 因为常用到rar压缩文件 ... -
ubuntu和windows7双系统,ubuntu系统启动项丢失的解决方案
2010-11-04 18:56 7353先说一下我的电脑上,实际安装了3个系统,xp,win7,ubu ... -
XP下虚拟机安装Solaris,并使用secureCRT登录
2010-09-10 13:17 2287今天弄了一上午,先在x ...
相关推荐
linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6.8.1.tar.bz2linux-2.6....
linux-2.6.38.2.tar.part1
本手册针对Linux内核2.6.26.4版本,详细介绍了内核配置菜单的各项功能与参数,旨在帮助Linux用户和开发者更深入地理解并定制内核配置,以满足特定系统需求。手册由刘少侠于2008年10月12日编写,涵盖了内核配置的基础...
### 理解 Linux 内核 2.6.8.1 CPU 调度 #### 引言 本文档由原 SGI 工程师 Josh Aas 编写,旨在深入浅出地介绍 Linux 2.6.8.1 版本内核中的 CPU 调度机制。该文档提供了关于 Linux 内核源代码、进程和线程的基本...
Linux内核2.6.29.1是Linux操作系统的核心组成部分,它负责管理系统的硬件资源,提供基础服务供用户空间的应用程序使用。这个版本的内核发布于2009年,是Linux内核2.6系列的一个稳定更新。在这个版本中,开发者们对...
Linux内核是开源操作系统的核心,2.6.21.5是其历史版本之一,发布于2007年。这个版本的内核包含了大量关于操作系统设计和实现的知识点,对于学习操作系统原理、驱动开发、系统调用以及并发处理等方面具有重要的参考...
Linux 2.6.32.2 Mini2440是针对ARM架构的嵌入式开发板设计的一个轻量级操作系统内核版本。这个压缩包文件"linux-2.6.32.2-mini2440-20110413.tar.gz"包含了与2011年4月13日发布相关的源代码,适用于Mini2440开发板。...
Linux内核是操作系统的核心部分,负责管理系统的硬件资源、提供系统调用接口以及调度进程等。"linux-2.6.34.15.tar.gz" 是一个包含Linux内核源代码的压缩文件,适用于学习和研究Linux内核的设计与实现。这个版本的...
《Linux内核补丁:linux-2.6.22.6_jz2440.patch详解》 在开源的世界里,Linux内核是至关重要的组成部分,它为各种硬件平台提供了操作系统的基础。"linux-2.6.22.6_jz2440.patch" 是一个针对Linux内核特定版本的补丁...
Linux 2.6.17.9 内核文件系统调用详解资源提供了对 Linux 2.6.17.9 内核中文件 I/O 操作的详细介绍,包括主要的数据结构、宏定义和函数流程,并分别讲述了 open、create、close、read、write、lseek 等系统调用。
"编译Linux2.6内核并添加一个系统调用" Linux操作系统是自由软件,在广大爱好者的支持下,内核版本不断更新也不断增长。通过编译内核可以轻易地对它进行修改,使我们能够根据自己的要求度身定制一个更高效、更稳定...
[Linux内核源码].linux-2.6.16.18.tar.bz2.part3.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part3.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part3.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part3.rar
Linux 2.6.32.65 是一个重要的内核版本,它是Linux 2.6内核系列的一个稳定分支,特别被誉为“最终稳定”版本。这个版本在2009年发布,针对多种硬件平台提供了优化和支持,使得它成为了一个广泛应用于服务器、嵌入式...
linux-2.6.11.12内核源码,带有注释,如果想学习linux内核可以参考。
linux 2.6.32.21源码,官方版本。
Linux内核是操作系统的核心部分,负责管理系统的硬件资源,提供基础服务给其他软件,并执行操作系统的基本功能。在Linux-2.6.11.12版本的内核中,包含了多个关键领域的源代码和注释,这对于理解操作系统的工作原理...
[Linux内核源码].linux-2.6.16.18.tar.bz2.part2.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part2.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part2.rar [Linux内核源码].linux-2.6.16.18.tar.bz2.part2.rar
标题中的"linux-2.6.22.6_100ask24x0.patch.zip"揭示了这个文件是一个针对Linux内核2.6.22.6版本的补丁包,它专为100ask24x0硬件平台定制。100ask24x0可能是某个特定的嵌入式系统或开发板型号,这通常意味着补丁包含...
Linux内核是操作系统的核心部分,负责管理系统的硬件资源、调度进程、执行系统调用以及提供与应用程序的接口。在这个场景中,我们关注的是一个特定版本的Linux内核更新——"linux-2.6.35.7-20121027"。这个更新...