初始化的时候会将0x80和system_call绑定起来
system_call伪代码
进程调度的时机对于分析很关键
系统调用机制的初始化
系统调用初始化从trap_init();开始
用到了set_system_trap_gate函数,其中涉及到了系统调用的中断向量和system_call汇编代码的入口,被声明成了一个函数,将其绑定起来
一旦执行0x80,cpy自动跳转到system_call来执行
系统调用机制初始化之后,则开始执行system_call
system_call的代码在entry_32.S文件中
从ENTRY(system_call)开始
系统调用其实是一个特殊点的中断,存在保护和恢复现场
SAVE_ALL来保护现场
sys_call_table传递来了系统调用号
syscall_after_call需要保存返回值
在退出之前还需要做syscall_exit_work
然后restore_all来恢复现场
简化后的汇编代码:
.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)
movl %eax, PT_EAX(%esp) ; store the return value
syscall exit:
testl $_TIF_ALLWORK_MASK, %ecx # current->work
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:
... ; deal with pending signals
END(work_pending)
进入system_call后
syscall_call查询系统调用对应的的处理函数
syscall_exit判断当前任务是否需要处理,需要处理的则跳转去处理
restore_all恢复现场
irq_return结束中断
syscall_exit_work处理任务跳转至work_pending
work_pending跳转至work_notifysig
work_resched需要重新调度的话在调度完成后跳转至restore_all返回系统调用
work_notifysig处理信号
流程图如下
总结:在中断处理过程中,首先要保存现场,然后接受中断并处理中断任务,处理任务结束后,恢复现场
在系统调用返回前,有可能发生进程调度call schedule
在当前进程有可能产生进程间通讯的信号则需要去处理
王潇洋
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000