分析system_call中断处理过程

上一次使用C函数和嵌入式汇编完成getpid系统调用,本次把上次写的系统调用代码加入MenuOS中,执行并跟踪这个系统调用的执行的过程。

这里将上次的代码再贴上来,

#include<stdio.h>
#include<unistd.h>
int main(){
pid_t pid,pidasm;
pid=getpid();
printf("use getpid(): current process pid is %d\n",pid);
asm volatile(
"mov $0,%%ebx\n\t"
"mov $0x14,%%eax\n\t"
"int $0x80\n\t"
"mov %%eax,%0\n\t"
:"=m"(pidasm)
);
printf("use asm : current process pid-asm is %d\n",pidasm);
}
在MenuOS中加入getpid系统调用

在test.c中加入自己的系统调用代码如下

这里写图片描述

编译运行后,选择getpid-asm选项,正确显示如下

这里写图片描述

系统调用代码分析

关键性代码如下, 这里是详细的代码

ENTRY(system_call)
    RING0_INT_FRAME            # can't unwind into user space anyway
    ASM_CLAC
    pushl_cfi %eax            # save orig_eax
    SAVE_ALL        #保存现场
    GET_THREAD_INFO(%ebp)
                    # system call tracing in operation / emulation
    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    jnz syscall_trace_entry
    cmpl $(NR_syscalls), %eax
    jae syscall_badsys
syscall_call:
    call *sys_call_table(,%eax,4)    #根据系统调用号调用对应的系统调用处理程序
syscall_after_call:
    movl %eax,PT_EAX(%esp)        # store the return value
syscall_exit:
    LOCKDEP_SYS_EXIT
    DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                    # setting need_resched or sigpending
                    # between sampling and the iret
    TRACE_IRQS_OFF
    movl TI_flags(%ebp), %ecx
    testl $_TIF_ALLWORK_MASK, %ecx    # current->work
    jne syscall_exit_work    #进行进程调度或者处理信号

restore_all:
    TRACE_IRQS_IRET   #恢复现场
restore_all_notrace:
#ifdef CONFIG_X86_ESPFIX32
    movl PT_EFLAGS(%esp), %eax    # mix EFLAGS, SS and CS
    # Warning: PT_OLDSS(%esp) contains the wrong/random values if we
    # are returning to the kernel.
    # See comments in process.c:copy_thread() for details.
    movb PT_OLDSS(%esp), %ah
    movb PT_CS(%esp), %al
    andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
    cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
    CFI_REMEMBER_STATE
    je ldt_ss            # returning to user-space with LDT SS
#endif
restore_nocheck:
    RESTORE_REGS 4            # skip orig_eax/error_code
irq_return:      #中断返回
    INTERRUPT_RETURN

已经在代码中关键位置的作用做了注释。

  • 当用户态进程发出int $0x80指令时,cpu切换到内核态并开始从地址system_call处开始执行指令。System_call()函数首先把系统调用号和这个异常处理程序可以用到的所有cpu寄存器保存到相应的内核栈中,通过一个宏指令SAVE_ALL实现的。

  • 然后会调用sys_call_table,通过eax寄存器的值查找系统调用表,找到几号系统调用,然后调用相应的系统调用。

  • 当系统调用完成时,内核会检测一些情况,比如进程的切换或者信号发生什么的。如果发生了这些情况,内核会转向syscall_exit_work中执行,在syscall_exit_work中先通过work_pending判断是信号处理还是进程调度。

  • 最后一步是恢复现场,通过iret的方式,把之前压在栈中的寄存器的值全部弹出。到这里就表示完成了整个系统调度了。

总结

根据对系统调用流程的分析,画了一个system_call的处理流程图如下

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值