Linux内核分析 实验五:分析system_call中断处理过程

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


一. 实验过程:
这次实验,首先删掉之前的menu, 重新下载;再将上周的代码加到test.c中,作为单独的函数,并在main函数中写下调用命令。编译运行成功。修改代码的部分如下所示:

int OpenTXT(int argc, char *argv[]){
    int fd=-1;
    fd = open("LICENSE",O_RDONLY);
    
    if (fd != -1){
        printf("Open file, successful.\n");
    }
    else{
        printf("Open file, failed\n");
    }
    return 0;
}


int OpenTXTAsm(int argc, char *argv[]){
    int fd=-1;
    int res;
    asm volatile(
        "mov $0x5,%%eax\n\t"
        "int $0x80\n\t"
        "mov %%eax,%0\n\t"
        : "=m" (fd)
        : "b"("LICENSE"), "c"(O_RDONLY)
     );
     if (fd != -1){
         printf("Open file, successful.\n");
     } else{
         printf("Open file, failed\n");
     }
    return 0;
}


int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
    MenuConfig("quit","Quit from MenuOS",Quit);
    MenuConfig("time","Show System Time",Time);
    MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
    MenuConfig("openTXT","Open LICENSE",OpenTXT);
    MenuConfig("openTXT-asm","Open LICENSE(asm)",OpenTXTAsm); 
    ExecuteMenu();
}



然后用kernel调试,设置断点在start_kernel,进入程序后,设置断点在调用的sys_open这里。

然后就可以依次观察运行的每一步了,这里只截图出刚进入断点时候的样子。




二. 实验分析:
在Linux系统中应用程序发起系统调用后,使用int $0x80或sysenter汇编指令将CPU切换到内核态,然后开始从地址system_call处执行命令。一直到Linux系统中系统调用处理过程的最后一条汇编指令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)
    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)

源代码如下:

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

这里通过图示来简单表示过程。



三.总结
1、用户态进程调用int 0x80(或system_call),中断进程,保护现场,让CPU停止当前工作转为执行系统内核中预设的一些任务,然后进入才能进入内核态;调用结束后又会恢复现场回到内核态。
2、中断后会对调用的任务进行各种检查,并进行调度,完成调用后,再进行检查,才能执行iret返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值