美文网首页
5系统调用system_call的处理过程

5系统调用system_call的处理过程

作者: 夏天的篮球 | 来源:发表于2017-03-26 23:04 被阅读0次

    安大大 + 原创作品转载请注明出处 + 《Linux操作系统分析》MOOC课程

    给MenuOS增加time和time-asm命令

    按照老师的方式在实验楼里git clone不能成功,就直接copy进去了test.c这个文件里的内容。test.c中新增加了Time和TimeAsm两个函数,以及main函数中新增加了两条语句。

    int Time(int argc, char *argv[])
    {
        time_t tt;
        struct tm *t;
        tt = time(NULL);
        t = localtime(&tt);
        printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
        return 0;
    }
    
    int TimeAsm(int argc, char *argv[])
    {
        time_t tt;
        struct tm *t;
        asm volatile(
            "mov $0,%%ebx\n\t"
            "mov $0xd,%%eax\n\t" 
            "int $0x80\n\t" 
            "mov %%eax,%0\n\t"  
            : "=m" (tt) 
        );
        t = localtime(&tt);
        printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
        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);//新增
        ExecuteMenu();
    }
    

    然后make rootfs 直接自动编译自动生成根文件系统,而且启动起来MenuOS。



    **help列表里新增加了time和time-asm命令**

    给MenuOS增加新的命令的方式(如增加time和time-asm):

    1. 在main函数中增加MenuConfig
    2. 增加对应的Time函数和TimeAsm函数
    3. make rootfs

    使用gdb跟踪系统调用内核函数sys_time

    **启动qemu** **打开gdb** **把带有符号表的debug版本3.18内核加载进来,然后连接到需要调试的MenuOS里** **b设置断点,c会执行到断点处停下来,list可以查看断点处附近的代码** **在这个文件夹下通过syscall_32.tbl文件查看13号系统调用time对应的内核处理函数** **13号系统调用time对应的内核处理函数是sys_time** **设置sys_time断点,执行time命令,程序执行到断点处** **list查看sys_time对应的代码**

    在gdb调试过程中,n表示next,s表示step,区别在于n会跳过函数,s会进入到函数里。如果这里一直按n单步执行会进入 schedule函数

    **单步执行会进入到get_seconds()函数里** **finish执行完当前的函数** **return i 获得的time的数值** 不知道为什么和老师的不一样,这里执行到了schedule函数

    sys_time返回后进入汇编代码处理gdb无法继续跟踪

    执行int 0x80之后执行system_call对应的代码

    system_call也可以设置断点,time返回 gdb进不去system_call,只能停在sys_time

    system_call 不是普通的函数,它是一段汇编代码,gdb还不能对其进行跟踪调试
    思考题:怎么让系统停在system_call的位置进行调试

    **在这个目录下entry_32.S** **system_call是这段汇编代码的起点,gdb还不能跟踪**

    系统调用在内核代码中的工作机制和初始化

    **xyz和sys_xyz是通过系统调用号联系起来的,int 0x80和system_call是通过中断向量匹配起来的**

    系统调用机制的初始化:

    \init\main.c start_kernel

    trap_init();
    

    \arch\x86\kernel\traps.c

    #ifdef CONFIG_X86_32
    //系统调用的中断向量和system_call汇编代码的入口
    //一旦执行int 0x80,CPU就跳转到system_call这个位置来执行
        set_system_trap_gate(SYSCALL_VECTOR, &system_call);
        set_bit(SYSCALL_VECTOR, used_vectors); 
    #endif
    

    系统调用的工作机制,一旦start_kernel初始化好之后,在代码中一旦出现int 0x80的指令,就会立即跳转到system_call这个位置。

    entry_32.S部分代码:
    //这段代码就是系统调用处理的过程,其它的中断过程也是与此类似
    //系统调用就是一个特殊的中断,也存在保护现场和回复现场
    ENTRY(system_call)//这是0x80之后的下一条指令
        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)//定义的系统调用的表,eax传递过来的就是系统调用号,在例子中就是调用的systime
    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//退出之前,syscall_exit_work 
        //进入到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//iret(宏),系统调用过程到这里结束
    

    当一个系统调用发生的时候,进入内核处理这个系统调用,由内核提供服务,当这个服务结束返回到用户态之前,即在系统调用返回之前,有可能发生进程调度(call schedule),进程调度的里边就会发生进程上下文的切换。
    把内核可以抽象成很多种不同的中断处理过程的集合。

    system_call到iret之间的处理过程流程图

    相关文章

      网友评论

          本文标题:5系统调用system_call的处理过程

          本文链接:https://www.haomeiwen.com/subject/bsklottx.html