分析system_call中断处理过程

原创作品转载请注明出处 

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000



系统调用分派表 (dispatch table)存放在
sys_call_table 数组

186.macro SAVE_ALL
187	cld
188	PUSH_GS
189	pushl_cfi %fs
190	/*CFI_REL_OFFSET fs, 0;*/
191	pushl_cfi %es
192	/*CFI_REL_OFFSET es, 0;*/
193	pushl_cfi %ds
194	/*CFI_REL_OFFSET ds, 0;*/
195	pushl_cfi %eax
196	CFI_REL_OFFSET eax, 0
197	pushl_cfi %ebp
198	CFI_REL_OFFSET ebp, 0
199	pushl_cfi %edi
200	CFI_REL_OFFSET edi, 0
201	pushl_cfi %esi
202	CFI_REL_OFFSET esi, 0
203	pushl_cfi %edx
204	CFI_REL_OFFSET edx, 0
205	pushl_cfi %ecx
206	CFI_REL_OFFSET ecx, 0
207	pushl_cfi %ebx
208	CFI_REL_OFFSET ebx, 0
209	movl $(__USER_DS), %edx
210	movl %edx, %ds
211	movl %edx, %es
212	movl $(__KERNEL_PERCPU), %edx
213	movl %edx, %fs
214	SET_KERNEL_GS %edx
215.endm

SAVE_ALL 先保存用户模式的寄存器和堆栈信息,然后切换到内核模式
system_call函数根据用户传来的 系统调用号 ,在系统调用表里找到对应的系统调用再执行

//2个参数
#define _syscall2(type,name,type1,arg1,type2,arg2) 
//3个参数
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) 
//4个参数
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)  
//5个参数 
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)  
//6个参数
#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) 


int $0x80通过软中断开触发系统调用,当发生调用时,函数中的name会被系统系统调用名所代替。
然后调用前面所讲的system_call。
这个过程里包含了系统调用的初始化,系统调用的初始化原代码在 arch/i386/kernel/traps.c
838#ifdef CONFIG_X86_32
839	set_system_trap_gate(SYSCALL_VECTOR, &system_call);
840	set_bit(SYSCALL_VECTOR, used_vectors);
841#endif
设置系统调用的中断向量(陷阱门)

/ linux-3.18.6 / arch / x86 / kernel / entry_32.S 的代码在系统调用发生时的处理流程
	# system call handler stub
490ENTRY(system_call)
491	RING0_INT_FRAME			# can't unwind into user space anyway
492	ASM_CLAC
493	pushl_cfi %eax			# save orig_eax
494	SAVE_ALL
495	GET_THREAD_INFO(%ebp)
496					# system call tracing in operation / emulation
497	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
498	jnz syscall_trace_entry
499	cmpl $(NR_syscalls), %eax
500	jae syscall_badsys
501syscall_call:
502	call *sys_call_table(,%eax,4)
503syscall_after_call:
504	movl %eax,PT_EAX(%esp)		# store the return value

......
</pre><pre name="code" class="cpp">532irq_return:
533	INTERRUPT_RETURN
</pre><pre name="code" class="cpp">......
588ENDPROC(system_call)

简要的流程如下 :


每当用户执行int 0x80时,系统进行中断处理,把控制权交给内核的system_call。


整个系统调用的过程可以总结如下:
1. 执行用户程序(如:fork) 
2. 根据glibc中的函数实现,取得系统调用号并执行int $0x80产生中断。
3. 进行地址空间的转换和堆栈的切换,执行SAVE_ALL。(进行内核模式)
4. 进行中断处理,根据系统调用表调用内核函数。
5. 执行内核函数。
6. 执行RESTORE_ALL并返回用户模式

解了系统调用的实现及调用过程,我们可以根据自己的需要来对内核的系统调用作修改或添加。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值