zoukankan      html  css  js  c++  java
  • system_call中断处理过程

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

    一.上周内容回顾

           计算机科学中有一句话,任何计算机相关问题都可以通过加一个中间层来解决。操作系统的系统调用是这样,system_call将api和系统函数连接起来,这样可以保证内核的安全,不会因为用户的失误操作而造成问题。操作系统为了安全,把一些重要的调用放在内核部分,这样只能通过触发系统调用来完成相应功能,这样可以保证内核的安全。

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

           这部分代码对我们来说理解整个操作系统的运行机制是非常重要的。因为杂过程中涉及到了进程调度的时机,系统调用的时机对我们理解操作系统的运行机制非常的重要,所以我们需要仔细的来分析一下system_call这个系统调用的过程。

       

          在xyz系统调用里面我们使用了int 0x80,在int 0x80中断向量对应着system_call,它是什么时候绑定起来的呢,是初始化的时候,初始化这个中断向量的时间,然后呢system_call的处理过程非常重要,这段汇编代码我们需要仔细的分析一下,在这个system_call调用的时候,哪里用到了sys_xyz,通过系统调用,通过中断向量来匹配起来的。那么在返回到用户态之前有一个返回时机,在我们调试的时候,你一直按n的话,从systime退出之后,下面会跟踪到schedule,我们先分析一下初始化,它从start_kernel里面有一个trap_init,trap_init里面有一个set_system_trap_gate(SYACALL_VECTOR(也就是系统调用的中断向量和system_call汇编代码的入口,这样一旦执行int 0x80,CPU 就自动跳转到system_call,这个位置来执行。

            在xyz系统调用里面我们使用了int 0x80,在int 0x80中断向量对应着system_call,它是什么时候绑定起来的呢,是初始化的时候,初始化这个中断向量的时间,然后呢system_call的处理过程非常重要,这段汇编代码我们需要仔细的分析一下,在这个system_call调用的时候,哪里用到了sys_xyz,通过系统调用,通过中断向量来匹配起来的。那么在返回到用户态之前有一个返回时机,在我们调试的时候,你一直按n的话,从systime退出之后,下面会跟踪到schedule,我们先分析一下初始化,它从start_kernel里面有一个trap_init,trap_init里面有一个set_system_trap_gate(SYACALL_VECTOR(也就是系统调用的中断向量和system_call汇编代码的入口,这样一旦执行int 0x80,CPU 就自动跳转到system_call,这个位置来执行。

     三.了解系统调用的基本代码

           这个代码实际上就是中断系统调用的处理过程,系统调用其实就是一个特殊一点的中断,存在保护现场和恢复现场的问题(比如save_all)同时我们要是仔细读这个代码的话,这个代码还相对比较复杂一点,这里有一个syscall_table(%eax,4)它是由系统调用的定义系统调用表,eax传递系统调用号,实际上,我们在这一条的时候在例子里面就是调用systime。syscall_after_all这个时候它就需要保存它的返回值,它在退出之前有一个syscall_exit_work,会检查当前进程是否需要执行 syscall_exit_work,如果需要处理,就会查看是否有进程信号或进程调度,若有进程信号或进程调度就再进行相应操作。

    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    #恢复现场
    
    irq_return:
        INTERRUPT_RETURN    #中断返回

     四.中断执行过程的流程图
        

    五.我的实验过程及截图

           本次实验选用 Linux 操作系统 2 号系统调用,fork 函数,通过对比嵌入式汇编编程和系统函数编程,深入理解和分析系统调用的过程。

           命令行如下:

    cd LinuxKernel
    rm menu -rf
    git clone https://github.com/mengning/menu.git
    cd menu
    make rootfs

          先打开实验楼里面的LinuxKernel,然后我们输入删除的操作,rm menu -rf,然后我们重新克隆一个,因为新版本的Menu已经把上次的两个系统调用,然后我们可以重新克隆一个,因为新版本的Menu已经提交到github里面。

           这个命令就是git clone https://github.com/mening/menu.git,进入到Menu,再ls一下,我们编译menu的过程可能比较繁琐,我们就使用脚本,我们直接输入make rootfs它就可以帮我们直接编译生成这个根文件系统,同时还自动帮我们启动起来这个我们按一个回车 没有任何信息就不输出,我们发现现在的命令也多了一些,我们还加了一些命令:
    fork。 修改的函数代码如下所示:   
    int menufork(int argc, char *argv[])
    {
        pid_t fpid;
        int count = 0;
        fpid = fork();
        if (fpid < 0)
            printf("error in fork!");
        else if (fpid == 0) {
            printf("i am the child process, my process id is %d
    ",getpid());
            count++;
        }
        else {
            printf("i am the parent process, my process id is %d
    ",getpid());
            count++;
        }
        printf("count: %d
    ",count);
        return 0;
    
    }
    
    int menuforkAsm(int argc, char *argv[])
    {
        pid_t fpid;
        int count = 0;
        asm volatile (
                "mov $0, %%ebx
    	"
                "mov $0x2, %%eax
    	"
                "int $0x80
    	"
                "mov %%eax, %0
    	"
                : "=m" (fpid)
                );
        if (fpid < 0)
            printf("error in fork!");
        else if (fpid == 0) {
            printf("i am the child process, my process id is %d
    ",getpid());
            count++;
        }
        else {
            printf("i am the parent process, my process id is %d
    ",getpid());
            count++;
        }
        printf("count: %d
    ",count);
        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);
    
        /*  add for menufork   */
        MenuConfig("menufork","menufork --fork a proc", menufork);
        MenuConfig("menufork-asm","menufork-asm --fork a proc(asm)",menuforkAsm);
    
    
        ExecuteMenu();
    }

    使用gdb进行调试:
    gdb
    file linux-3.18.6/vmlinux    加载调试用的符号表
    target remote:1234
    b start_kernel  设置断点
    c
    b sys_fork

     

          我们使用命令vi test.c,test.c这里面从main 函数开始读,发现我们这个里面其实只增加了两行代码:这两行对应的有两个函数,一个menuforkAsm还有menufork函数:只是我们需要增加这些东西就可以完成对MenuOS的修改,只是我们需要增加新的命令的话,需要按照下面的方式,MenuConfig增加,然后对应的函数增加。
          给MenuOS增加menufork和menuforkAsm命令
          1.更新Menu代码到最新版本
          2.在main函数中增加MenuConfig
          3.增加对应的menufork函数和menuforkAsm函数
          4.make roootfs
    六.总结
          本实验通过分析 Linux 内核系统调用源码,深入剖析了系统调用的全过程。通过 int 0x80 中断跳转到系统调用处理程序 system_call 函数处,执行相应的例程。但是,由于是代表的是用户进程,所以这个执行过程并不属于中断上下文,而是进程上下文。因此,系统调用执行过程中,可以访问用户进程的许多信息,也可以被更高优先级的进程抢占。    
           当系统调用完成后,把控制权交回到发起调用的用户进程前,内核又会有一次调度。如果发现有优先级更高的进程或当前进程的时间片用完,那么会选择优先级更高的进程或重新选择进程执行。
  • 相关阅读:
    Bootstrap标签(label)的使用
    Docker学习(二)
    linux 的tee命令
    解决 Docker pull 出现的net/http: TLS handshake timeout 的一个办法
    win 10 安装.msi 程序出现the error code is 2503
    Kbuntu16.04利用快捷键调用终端Konsole
    ubuntu上swift开发学习2
    ubuntu上swift开发学习1
    Linux中常用文件传输命令及使用方法
    Kbuntu16.04添加工作空间
  • 原文地址:https://www.cnblogs.com/20135124freedom/p/5326346.html
Copyright © 2011-2022 走看看