八叶一刀·无仞剑

万物流转,无中生有,有归于无

导航

分析system_call中断处理过程

Posted on 2015-04-05 21:49  闪之剑圣  阅读(417)  评论(0编辑  收藏  举报

朱宇轲 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

本次作业将继续上次的实验,用gdb追踪系统mkdir执行系统调用的过程,并分析system_call的中断处理过程。

首先应当将上次写的代码载入menu中,重新装载menu:

之后打开test.c文件,在其中加入上次写的调用mkdir函数的定义。

执行make rootfs,从而打开menu镜像,我们发现mkdir就装载进menu的命令中了:

然后我们用gdb在sys_mkdir处设置断点。

如果继续进行单步调试的话,可能会进入汇编语言部分,此时就无法看到代码执行的细节了。所以说,用常规的gdb方法是不能对具体的内核代码进行调试的。如果想去对这部分进行调试,有兴趣的可以进一步查阅资料去了解一下。

system_call的代码还是比较复杂的,所幸老师在课上为我们对它的代码进行了简化,本博客将围绕这个代码来进行分析。

.macro INTERRUPT_RETURN
	iret
.endm
.macro SAVE_ALL
	...
.endm
.macro RESTORE_INT_REGS
	...
.endm
ENTRY(system_call)
	SAVE_ALL
syscall_call:
	call *sys_call_table(,%eax,4)
	movl %eax,PT_EAX(%esp)
syscall_exit:
	testl $TIF_ALLOWORK_MASK,%ecx
	jne syscall_exit_work
restore_all:
	RESTORE_INT_REGS
irq_return:
	INTERRUPT_RETURN
ENDPROC(system_call)
syscall_exit_work:
	testl $_TIF_WORK_SYSCALL_EXIT,%ecx
	jz work_pending
END(syscall_exit_work)
work_pending:
	testb $_TIF_NEED_RESCHED,%cl
	jz work_notifysig
work_resched:
	call schedule
	jz restore_all
work_notifysig:
	...
END(work_pending)

  代码从ENTRY(system_call)处正式进入程序。此时实际上已经触发了中断,首先通过SAVE_ALL将进程和中断上下文存储起来;之后,通过调用sys_call_table(,%eax,4)执行具体的系统调用(在这里是sys_mkdir),并在系统调用执行结束后将返回值存储到esp中。

  之后,需要检测是否需要进入syscall_exit_work。如果不需要的话,就通过RESTORE_INIT_REGS将之前存储的上下文重新载入,并调用iret结束中断,返回之前的进程。

  syscall_exit_work执行了一些进程调度、消息传递的工作,如果进行了进程切换,可能要继续触发新的中断,执行新的系统调用。

  system_call的流程图简图如图所示(边上的圆框表示具体的执行代码):

  

总结:

  本文对system_call的执行流程进行了初步的分析。通过阅读代码得知:在中断处理的过程中,需要保存之前程序的上下文,并执行相关的系统调用。此时若执行进程调度和切换,则可能触发新的中断,并保存当前的环境,如此层层堆叠,直到回到最初调用的程序中。