分析system_call中断处理过程

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


本次的作业希望我们能够讲自己的系统调用放入menuOS中,用GDB进行观察,并分析一下系统调用中一段关键代码做了那些工作。我们首先向menuOS中加入自己的系统调用。这里我加入的是getpid调用,如下图所示。



我们尝试debug一下


我们看到我们可以跟踪到系统函数sys_getpid,但是往下gdb就无法跟踪到后面的汇编代码中去了。

那么我们来简单分析一下从system_call开始到iret结束之间的整个过程。这段代码是系统调用在内核态执行的很重要的一段代码,内核在set_system_trap_gate(SYSCALL_VECTOR, &system_call)中绑定了system_call和中断向量SYSCALL_VECTOR以后,一但我们执行int 0x80系统就会立即跳转到systemcall的位置(entry_32.S)。这中间我们经历了上下文环境的保存,系统调用服务程序的执行,现场的恢复,以及从内核态回到用户态的一系列过程。iret这条命令实际上是上下文切换的最后一条命令,完成后我们也就从内核态回到了用户态。


.macro INTERRUPT_RETURN 
    iret
.endm
.macro SAVE_ALL  
    ...
.macro RESTORE_INT_REGS  #宏定义
    ...
.endm
 
ENTRY(system_call)    #开始
    SAVE_ALL
syscall_call:
    call *sys_call_table(,%eax,4)<span style="white-space:pre">	</span>#根据系统调用号来查找处理程序
    movl %eax, PT_EAX(%esp)  ; store the return value
syscall exit:
    testl $_TIF_ALLWORK_MASK, %ecx  是否由需要处理的工作
    jne syscall_exit_work    
restore_all:                       #保存现场
    RESTORE_INT_REGS
irq_return:<span style="white-space:pre">			</span>   #返回
    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:     #处理挂起的信号
    ...                  ; deal with pending signals
END(work_pending)

由于这段代码有些复杂,所以我们从 孟老师提供的简化伪代码入手分析,内核执行int 0x80后系统跳转到system_call入口,首先系统进行保存现场的工作(包括将用户态进程的各寄存器保存在内核堆栈上),之后系统执行sys_call_table,该函数通过系统调用号来查找实际的系统调用函数,当该函数返回时,系统保存其返回值,然后到syscall_exit_work,这里会有一个判断,即此时系统是否还有没有完成的额外工作,如果有的话,首先进入work_pending,这里是检查是否有等待调度的进程,因为这里是内核设置的进程调度的一个时机。该段程序循环调度需要调度的进程,如果已经没有需要调度的进程,紧接着需要检查是否有挂起的信号(比如进程间通信的一些信号)等待处理。处理完毕后,本次系统调用也就接近了尾声,此时恢复上下文,然后将CPU控制权交给用户态。至此该段代码执行完毕。我们总结成一张流程图的话,应该如下图所示。




通过上面的分析我们可以得出,系统调用实际上是一种特殊的中断。和一般的中断一样,它需要进行现场的保存,用户态到内核态的切换,现场的恢复,内核态到用户态的切换这么几个步骤。

但和一般的中断相比,系统调用又有所不同。这个中断不是由硬件触发的(如键盘按键),而是由封装在C库中的系统调用函数通过调用int 0x80进入的。这个指令是一条陷入指令,它是我们正在执行的代码引起的,而不是外界与当前代码无关的中断源引起的。

这次的分析就到这里,希望对读者有所帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值