选择显示字体大小

理解linux的系统调用

现在,您或许正在查看设备驱动程序,并感到奇怪:“函数 foo_read() 是如何被调用的?”或者可能疑惑: “当我输入 cat /proc/cpuinfo 时,cpuinfo() 函数是如何被调用的?”内核完成引导后,控制流就从相对直观的“接下来调用哪个函数?”改变为取决于系统调用、异常和中断。

什么是系统调用?

字面上讲,系统调用(也称为“syscall”)就是一条类似于“add”或者“jump”的指令。从更高的层面上讲,系统调用是用户级程序要求操作系统为它做某些事情的途径。如果您正在编写程序,需要读取某个文件,那么要使用一个系统调用来要求操作系统为您读取那个文件。

系统调用详述

这里是系统调用的工作原理。首先,用户程序为系统调用设置参数。其中一个参数是系统调用编号(稍后对此进行详述)。注意,所有这些都是由库函数自动完成的,除非您是使用汇编编程。参数设置完成后,程序执行“系统调用”指令。这个指令会导致一个异常:产生一个事件,这个事件会致使处理器跳转到一个新的地址,并开始执行那里的代码。

新地址的指令会保存程序的状态,计算出应该调用哪个系统调用,调用内核中实现那个系统调用的函数,恢复用户程序状态,然后将控制权返还给用户程序。系统调用是设备驱动程序中定义的函数最终被调用的一种方式。

这就是系统调用如何工作的一个简短说明。接下来,我们将为那些对内核事实上如何完成感到好奇的这些人提供详尽的细节。不要担心您是否完全理解所有细节 —— 只需要记住这是内核中的函数最终被调用的一个途径 —— 没有任何神秘之处。您可以追踪控制流在内核中的全部历程 —— 有时会有些困难,但是您可以做得到。

系统调用示例:1

这里非常适合于开始根据理论展示一些代码。我们将研究 read() 系统调用的过程,首先从系统调用指令被执行的时候开始。使用 powerpc 体系结构作为代码体系结构相关部分的示例。在 powerpc 上,当执行一个系统调用时,处理器跳转到地址 0xc00。那个位置的代码是在文件 arch/ppc/kernel/head.s 中定义的。类似如下:

/* system call */        . = 0xc00systemcall:        exception_prolog        exc_xfer_ee_lite(0xc00, dosyscall)/* single step - not used on 601 */        exception(0xd00, singlestep, singlestepexception, exc_xfer_std)        exception(0xe00, trap_0e, unknownexception, exc_xfer_ee)
这段代码所做的事情是,保存一些状态,然后调用另一个名为 dosyscall 的函数。

exception_prolog 是一个宏,负责从用户空间到内核空间的切换,这需要保存用户进程的寄存器状态。使用此例程的地址和函数 dosyscall 的地址来调用 exc_xfer_ee_lite。最后,某些状态将会被保存,dosyscall 将会被调用。后面的两行在地址 0xd000xe00 保存两个异常向量。

exc_xfer_ee_lite 类似如下:

#define exc_xfer_ee_lite(n, hdlr)               exc_xfer_template(n, hdlr, n+1, copy_ee, transfer_to_handler,                           ret_from_except)


exc_xfer_template 是另一个宏,代码类似如下:

#define exc_xfer_template(n, hdlr, trap, copyee, tfer, ret)             li      r10,trap;                                               stw     r10,trap(r11);                                          li      r10,msr_kernel;                                         copyee(r10, r9);                                                bl      tfer;                                           i##n:                                                                   .long   hdlr;                                                   .long   ret
li 表示 立即加载(load immediate),即某个在编译时已知的常量保存在某个寄存器中。首先,trap 加载到寄存器 r10 中。在接下来的一行中,那个值存储在由 trap(r11) 给出的地址中。trap(r11) 以及接下来两行去做一些硬件相关的位操作。然后,我们调用 tfer 函数(transfer_to_handler 函数),它会处理更多内部事务并将控制转交给 hdlrdosyscall)。注意, transfer_to_handler 通过链接寄存器加载处理程序的地址,因此您看到的是 .long dosyscall,而不是 bl dosyscall

系统调用示例:2

现在我们来研究 dosyscall。它位于 arch/ppc/kernel/entry.s 文件中。这个函数最终使用系统调用编号将系统调用表的地址和索引加载到它。操作系统使用系统调用表将系统调用编号翻译为特定的系统调用。

系统调用表名为 sys_call_table,在 arch/ppc/kernel/misc.s 中定义。系统调用表包含有实现每个系统调用的函数的地址。例如,read() 系统调用函数名为 sys_readread() 系统调用编号是 3,所以 sys_read() 位于系统调用表的第四个条目中(因为系统调用起始编号为 0)。从地址 sys_call_table + (3 * word_size) 读取数据,得到 sys_read() 的地址。

dosyscall 找到正确的系统调用地址后,它将控制权转交给那个系统调用。我们来看定义 sys_read() 的位置,即 fs/read_write.c 文件。这个函数会找到关联到 fd 编号(传递给 read() 函数的)的文件结构体。那个结构体包含指向用来读取特定类型文件数据的函数的指针。进行一些检查后,它调用与文件相关的 read() 函数,来真正从文件中读取数据并返回。与文件相关的函数是在其他地方定义的 —— 比如套接字代码、文件系统代码,或者设备驱动程序代码。这是特定内核子系统最终与内核其他部分协作的一个方面。

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

就是这样!read() 调用就完成了!幸运的话,您会得到数据。

在关键的位置加入 printk,可以更深入地研究 syscalls。一定要限制这些 printk 的输出的数量。例如,如果向 sys_read() syscall 添加 printk,应该像这样去做:

static int mycount = 0;if (mycount < 10) {    printk ("sys_read called\n");    mycount++;}



  


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons