Linux内核分析-系统中断在内核中的实现

分析system_call中断处理过程

在MenuOS中添加上周所运用到的系统调用

即在Linuxkernel/menu/test.c文件中,添加代码如下:

    int Mkdir()
    {
        const  char *ch = "test"; //创建的文件夹名称
        mode_t mode = 0700;        //创建的文件夹的权限
        int flag = 0;        //是否创建成功新的文件夹的标识符
        flag = mkdir(ch,mode);    //调用mkdir
        if(flag==0)                //flag=0则创建成功,否则失败
        {
             printf("succeed");
        }
        else
            printf("error");
        return 0;
    }
    int MkdirAsm()
    {
         char *ch="test-asm"; //创建文件夹的名称
        mode_t mode=S_IRWXU;  //创建新的文件夹的权限
        int flag=0;            //标识符
        asm volatile(
                "mov $0x27,%%eax\n\t"    //系统调用号赋给eax寄存器
                "mov %1,%%ebx\n\t"        //将文件夹的名称赋给ebx寄存器
                "mov %2,%%ecx\n\t"        //将文件夹的权限赋给ecx寄存器
                "int $0x80\n\t"            //开启中断,执行mkdir系统调用
                "mov %%eax,%0\n\t"        //将返回值赋给flag
                :"=m"(flag)                //输出变量flag
                :"d"(ch),"D"(mode)        //输入变量ch与mode
                );
        if(flag==0)            //flag=0则创建成功,否则失败
            printf("succeed");
        else
            printf("error");
        return 0;
    }

    int main()
    {
        PrintMenuOS();
        SetPrompt("MenuOS>>");
        MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL);
        MenuConfig("quit","Quit from XXX",Quit);
    MenuConfig("mkdir","Make up a new director",Mkdir);
        MenuConfig("Mkdirasm","Make up a new director by asm",MkdirAsm);
        ExecuteMenu();
      }
  • make rootfs即可完成功能的添加

gdb单步调试系统调用mkdir

  • 设置断点:
    设置断点

  • 在MenuOS界面输入mkdir,则发现停在了system_mkdir该函数处:
    输入mkdir出现调试界面

  • 进行单步调试,发现其步骤大约为读取pathname(所需要创建文件夹的名称),配置权限,完成创建:
    单步调试的结果

  • 同理输入命令mkdirasm,完成单步调试,与mkdir一样的结果(因为都是调用系统调用mkdir)

  • 输入c,将程序进行完,则出现最终结果:
    运行结果

system_call到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)
    
  • 流程图如下:
    流程图

  • SAVE_ALL宏可以在栈中保存中断处理程序可能会使用的所有CPU寄存器,以此起到保护现场的作用

  • 根据sys_call_table查找所需要的中断程序的中断号,从而执行system_call

  • 系统调用完成后,则执行iret结束该操作。

posted @ 2016-03-27 15:59  20135212池彬宁  阅读(416)  评论(0编辑  收藏  举报