应用层至驱动层的调用情况
来源:互联网 发布:房源中介那个软件好 编辑:程序博客网 时间:2024/06/06 05:15
浅析linux中open系统调用
作者:吴老师,华清远见嵌入式学院讲师。
从2.6.19的linux内核开始,内核的系统调用使用函数syscall,其函数原型为:int syscall(int number, ...)其中number是系统调用号,number后面应顺序接上该系统调用的所有参数。以x86平台为例,系统调用号在内核源码中的路径是/arch/x86/include/asm/unistd_32.h头文件中定义。其中大部分以__NR_开头,比如open的系统调用号是5。
本文以字符设备的驱动为例,分析系统调用的执行过程,内核版本为2.6.35.
1、用户空间到内核的转换
系统调用需要一个从用户空间到内核空间的转换,不同平台转换的指令不同,这种特定的指令称作操作系统的陷入(operating system trap)。X86结构中使用软中断x080来实现。即汇编指令 int $0x80.通过软中断0x80 ,系统就会跳到一个预设的内核空间地址。它指向系统调用处理程序system_call,在arch/x86/kernel/entry_32.S 中以汇编语言编写,该过程主要有2个步骤。
(1)系统启动时,对INT 0x80进行一定的初始化。
使用汇编子程序setup_idt(linux/arch/i386/kernel/head.S)初始化idt表(中断描述符表),这时所有的入口函数偏移地址都被设为ignore_int ,如下图所示。
(2)设置中断描述符表
start_kernel函数中(init/main.c)调用trap_init()(arch/x86/kernel/trap.c)函数,设置中断描述符表。在trap_init()该函数里,实际上是通过调用函数set_system_trap_gate(SYSCALL_VECTOR, &system_call);来完成该项的设置的。其中的SYSCALL_VECTOR就是0x80,而system_call则是一个汇编子函数,它即是中断0x80的处理函数,主要完成两项工作:寄存器上下文的保存、跳转到系统调用处理函数。
2、系统调用函数的入口
syscall_call函数到系统调用服务例程:在上面执行软终端0x80时,系统调用号会被放入eax寄存器,system_call()函数读取eax寄存器获取当前系统调用的调用号。然后将其乘以4生成偏移地址,然后再以sys_call_table为基址。基址+偏移地址=>系统调用服务例程的地址。其中sys_call_table基址在文件arch/x86/kernel/syscall_table_32.S中定义。同时table表中每一项例程的地址占用4个字节,所以上面乘以4。
到这儿system_call()就到服务例程的地址了。然后另一个问题-参数传递需要解决。由于系统调用例程在定义时时用 asmlinkage 标记了的,所以编译器仅从堆栈中获取该函数的参数。在进入system_call函数前,用户应用会把参数存放到寄存器中,system_call函数执行时会首先把这些寄存器压入堆栈。这样对系统调用服务例程可以直接从堆栈照片能够获取参数。
3、系统调用函数的执行
open会最终执行sys_open函数:
里面调用do_sys_open()函数:
在上图的L884行中,获取未被使用的文件描述符,在do_filp_open()函数中打开文件。其函数调用过程如下:
sys_open -> do_sys_open -> do_filp_open ->do_last-> nameidata_to_filp -> __dentry_open
4、驱动代码file_operations的调用
在 __dentry_open函数中:
L685中 open = f->f_op->open;即调用chrdev_open。
在file: fs/char_dev.c中static int chrdev_open(struct inode *inode, struct file *filp)调用ret = filp->f_op->open(inode,filp);即为真正的file_operations中的open函数。
当然,在VFS层中对open函数的操作远不止上文描述的这么简单,会进行权限和打开方式的判断等。普通的驱动开发者很少涉及对这部分代码的修改,主要还是学习和欣赏Linux内核。
- 应用层至驱动层的调用情况
- 应用调用驱动层
- Android应用层调用驱动的全过程 精简版
- 应用层open如何调用驱动open函数的?
- 安卓应用层与底层驱动之间的调用
- Linux驱动层调用应用层程序--call_usermodehelper()
- Linux学习:应用层open调用驱动层open过程
- Android 应用层如何调用驱动节点
- 应用层到驱动层
- 应用层对i2c通用驱动接口与eeprom的i2c驱动接口从应用层到内核层调用区别和联系
- 从应用层的mmap到驱动层的mmap
- 驱动层和应用层的明确分工
- 驱动层与应用层通信的实现
- 驱动层和应用层的同步通信
- 在驱动层直接使用应用层的空间
- 应用层打开驱动层创建的符号链接
- 驱动和应用层的异步通信
- Android Jni层调用应用层(Java)的方法
- 浅谈HTTP中Get与Post的区别
- LeetCode3.1 @ Valid Palindrome 检验回文串 D2F5
- java中重载与重写的区别
- 反向代理与正向代理
- 数据库的规范
- 应用层至驱动层的调用情况
- 快速Android开发系列网络篇之Android-Async-Http
- AS3 库资源 很多非常有用的类库
- Java引用变量的类型
- MINA服务端+flash(AS)客户端+嵌入式socket服务端互联互通
- 设计模式学习笔记——桥梁模式
- ApplicationDomain与动态加载外部swf
- AS3的垃圾回收
- 如何在AS3中引用swf中的元件、图片等资源以及布局信息