给出的地址中。TRAP(r11) 以及接下来两行去做一些硬件相关的位操作。然后,我们调用 tfer 函数(transfer_to_handler 函数),它会处理更多内部事务并将控制转交给 hdlr(DoSyscall)。注意, transfer_to_handler 通过链接寄存器加载处理程序的地址,因此您看到的是 .long DoSyscall,而不是 bl DoSyscall。
系统调用示例:2
现在我们来研究 DoSyscall。它位于 arch/ppc/kernel/entry.S 文件中。这个函数最终使用系统调用编号将系统调用表的地址和索引加载到它。操作系统使用系统调用表将系统调用编号翻译为特定的系统调用。
系统调用表名为 sys_call_table,在 arch/ppc/kernel/misc.S 中定义。系统调用表包含有实现每个系统调用的函数的地址。例如,read() 系统调用函数名为 sys_read。 read() 系统调用编号是 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++;
}
|
共2页: 上一页 [1] 2 下一页
|