分析system_call中断处理过程

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

一、实验内容

1、使用gdb跟踪分析一个系统调用内核函数,推荐在实验楼环境下完成实验;

2、根据本周所学知识分析系统调用的过程,从system_call开始到iret结束之间的整个过程,并画出简要准确的流程图。


二、实验过程

1、进入实验楼,打开命令窗口,输入如下命令

cd Linuxkernel
rm menu -rf
git clone http://github.com/mengning/menu.git
cd menu
然后打开test.c文件,在其中加入相应的代码,如下:

分析system_call中断处理过程_第1张图片

分析system_call中断处理过程_第2张图片

这样就将自己的系统调用命令加入到系统中了

然后输入如下命令:

make rootfs
启动系统,可以看到如下效果

分析system_call中断处理过程_第3张图片
输入help命令,我们可以看到自己定义的两个系统调用命令已添加到系统中,即多了getpid和getpid-asm两个命令。

用gdb跟踪分析一个系统调用内核函数这里不再赘述,可以参考前面写的文章跟踪分析Linux内核的启动过程。


2、分析system_call开始到iret结束之间的整个过程

system_call汇编伪代码如下:

.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)
对于宏SAVE_ALL来说,这条语句会保存当前线程的现场,然后是执行system_call,跳转到相应系统调用号所对应的服务例程当中,也就是在sys_call_table表中找到了相应的函数入口点,然后进入到系统调用表查找到系统调用服务程序的入口函数的地址,再进行跳转,这样便完成了对sys_call_table的进入。接下来伪代码马上就来到了syscall_exit,在执行完syscall_call后,马上接触并退出系统调用,但是这个退出的过程非常的复杂,从syscall_exit开始到irq_return的真实代码:

syscall_exit:  
    LOCKDEP_SYS_EXIT  
    DISABLE_INTERRUPTS(CLBR_ANY)
    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:  
    movl PT_EFLAGS(%esp), %eax  # mix EFLAGS, SS and CS 
    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
restore_nocheck:  
    RESTORE_REGS 4          # skip orig_eax/error_code  
irq_return:  
    INTERRUPT_RETURN
完成这些其余的工作之后,最终来到了irq_return,在这里使用宏 INTERRUPT_RETURN 实际上就是iret指令,恢复现场,最终完成了系统调用中断处理的返回。

从system_call到iret之间的整个过程可以用如下流程图表示:

分析system_call中断处理过程_第4张图片


三、总结

系统调用可以抽象成是很多种不同的中断处理过程的集合。




你可能感兴趣的:(linux)