首 页文章中心

Linux学习网

您的位置Linux学习网 > Linux综合 > 文章内容

Liunx用户和内核空间之间的通信实现

作者:佚名  来源:不详  发布时间:2007-12-21 16:43:00

系统调用

用户空间和内核空间之间的通信实现

● 与系统调用相关的数据结构和函数

系统调用函数名以“sys_”开头,后面是该系统调用的名字,由此构成了221个形似sys_name()的函数名。include/asm-i386/unistd.h中为每一个系统调用规定了惟一的编号,假设用name来表示系统调用的名称,那么系统调用号与系统调用响应函数的关系是:以系统调用号__NR_name作为下标,可找出系统调用表sys_call_table中对应表项的内容,它也就是该系统调用的响应函数sys_name的入口地址。

● 系统调用具体执行流程

当执行一个系统调用时,处理器跳转到地址 0xc00。

参考代码:

arch/ppc/kernel/head.S /* System call */. = 0xc00SystemCall:EXCEPTION_PROLOG/* EXCEPTION_PROLOG 是一个宏,负责从用户空间到内核空间的切换,并需要保存用户进程的寄存器状态*/stw r3,ORIG_GPR3(r21)li r20,MSR_KERNELrlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */bl transfer_to_handler.long DoSyscall .long ret_from_except

有关DoSyscall,它在文件arch/ppc/kernel/entry.S 中定义。这个函数最终使用系统调用编号将系统调用表的地址和索引加载,操作系统使用系统调用表将系统调用编号翻译为特定的系统调用。

系统调用表名为 sys_call_table,在 arch/ppc/kernel/misc.S 中定义。系统调用表包含有实现每个系统调用的函数的地址。

_GLOBAL(sys_call_table).long sys_ni_syscall /* 0 old "setup()" system call */long sys_getegid /* 50 */.long sys_acct.long sys_umount /* recycled never used phys() */.long sys_ni_syscall /* old lock syscall holder */.long sys_ioctl /* 54 */.long sys_fcntl /* 55 */

当DoSyscall 找到正确的系统调用地址后,它将调用指定的系统调用函数。如要做系统ioctl调用,对应的系统调用号为54,它将调用函数sys_ioctl()。下面具体会说明sys_ioctl()的调用过程。

当函数调用完毕之后,返回到 DoSyscall(),它将控制权切换给 ret_from_except(在 arch/ppc/kernel/entry.S 中定义)。它会去检查那些在切换回用户空间之前需要完成的任务。如果没有需要做的事情,那么就通过 restore 函数恢复用户进程的状态,并将控制权交还给用户程序。

● ioctl系统调用的整个流程

sys_ioctl()是整个ioctl系统调用过程中的最顶级函数,它需要对输入的参数进行预处理,检查参数的合法性,然后调用底层的处理函数作更进一步的处理。

分析函数sys_ioctl(),参考代码:

fs/ioctl.casmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg){ struct file * filp;unsigned int flag;int on, error = -EBADF;filp = fget(fd); /*通过传入的参数文件句柄fd来获得需要操作的文件(或者设备)的指针,后面做了具体的说明*/if (!filp)goto out;error = 0;TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_IOCTL,fd,cmd,NULL);lock_kernel();switch (cmd) { /*不同的传入命令字参数cmd的处理*/case FIOCLEX:set_close_on_exec(fd, 1);break;case FIONCLEX:set_close_on_exec(fd, 0);break;case FIONBIO:if ((error = get_user(on, (int *)arg)) != 0)break;flag = O_NONBLOCK;#ifdef __sparc__/* SunOS compatibility item. */if(O_NONBLOCK != O_NDELAY)flag |= O_NDELAY;#endifif (on)filp->f_flags |= flag;elsefilp->f_flags &= ~flag;break;case FIOASYNC:if ((error = get_user(on, (int *)arg)) != 0)break;flag = on ? FASYNC : 0;/* Did FASYNC state change ? */if ((flag ^ filp->f_flags) & FASYNC) {if (filp->f_op && filp->f_op->fasync)error = filp->f_op->fasync(fd, filp, on);else error = -ENOTTY;}if (error != 0)break;if (on)filp->f_flags |= FASYNC;elsefilp->f_flags &= ~FASYNC;break;default: /*如果传入的命令字参数cmd不符合上述情况,则需要调用更底层的ioctl处理函数error = -ENOTTY;/*下面根据情况调用ioctl处理函数*/if (S_ISREG(filp->f_dentry->d_inode->i_mode))error = file_ioctl(filp, cmd, arg); /*执行关于文件的ioctl的一般操作*/else if (filp->f_op && filp->f_op->ioctl)/*如果filp本身是一个设备,则执行filp->f_op->ioctl()函数,对设备进行ioctl函数操作,该指针在初始化时就已经指向了设备函数接口中的ioctl函数,因此在设备初始化时,只要向内核提交了file_operations{}结构或block_device_operations{},其中的ioctl函数就会被调用到*/error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);}unlock_kernel();fput(filp);out:return error;}
收藏本页到: 365Key | del.icio.us | | 添加到雅虎收藏+
  • 网站帮助 - 广告合作 - 网站地图