【第6章】模仿MINIX的中断处理【二】

来源:互联网 发布:linux文件权限修改 编辑:程序博客网 时间:2024/05/29 14:35

     好了,完成了上面的工作,下一步的工作的什么呢,MINIX还把当前进程的寄存器组压栈的工作,以及判断是否发生中断重入的工作,还有切换内核栈的工作都放到了一个函数当中,并且在时钟中断处理程序的开始处调用了这个函数,那么必定在当前进程的PCB中压入的调用函数指令的下一条指令的相对偏移地址,那么PCB中又多了一个字段,就是这个相对偏移地址,那么我们就修改一下PCB的定义:

Code:
  1. typedef struct s_stack_frame  
  2. {  
  3.     u32 gs;  
  4.     u32 fs;  
  5.     u32 es;  
  6.     u32 ds;  
  7.     u32 edi;  
  8.     u32 esi;  
  9.     u32 ebp;  
  10.     u32 kernel_esp;  
  11.     u32 ebx;  
  12.     u32 edx;  
  13.     u32 ecx;  
  14.     u32 eax;  
  15.     u32 retaddr;  
  16.     u32 eip;  
  17.     u32 cs;  
  18.     u32 eflags;  
  19.     u32 esp;  
  20.     u32 ss;  
  21. }Stack_Frame;  

   那么下面就来修改时钟中断处理程序:

HW_Int_00:
    call    Save
   
    mov     al,20h
    out     20h,al
   
    sti

    mov     eax,0dh
    push    eax
    push    Int_Msg
    call    Disp_Color_Str
    add     esp,8
   
    call    Clock_Handler

    cli
   
    ret

 ...

 Save:
    pushad
    push     ds
    push     es
    push     fs
    push     gs
    mov      dx,ss
    mov      ds,dx
    mov      es,dx
   
    mov      eax,esp

    inc      dword [Is_Reenter]
    cmp      dword [Is_Reenter],0
    jne      .1
   
    mov      esp,Top_Of_Stack
    push     restart
    jmp      [eax + 48]
   
.1:
    push     reenter   
   
jmp      [eax + 48]

     我们看到,添加了一个Save函数,一般的函数最后都会有个ret指令跳回到调用处的下一条指令处继续执行。但是这里用的是jmp,这是由于返回地址在PCB中保存的,而在时钟中断处理程序中切换到了内核栈,ret找不到返回地址,况且如果发生中断重入的话,返回地址保存在内核栈中。那就很混乱了,所以我们要以一种统一的方法来解决,先把esp送eax,再由eax找到返回地址,最后直接跳转过去。

     编译运行,哪。。哪尼,出错了,哦哦,原来是在PCB中新添加的那个字段搞的鬼,修改一下:

restart:
    mov    esp,[p_Resume_PCB]
    lea    dword eax,[esp + 72]
    mov    [tss + 4],eax
    mov    ax,[esp + 72]
    lldt ax

reenter:
    dec dword [Is_Reenter]    
    
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
    
    add    esp,4
    
    iretd

      好了,搞定了Save函数,让我们再来进一步修改中断处理程序。我们不想让时钟中断打断时钟中断,就是要去开中断之前屏蔽掉时钟中断,关中断之后开启时钟中断,来修改一下:

HW_Int_00:
    call    Save
   
    mov al,20h
    out 20h,al
 
    in    al,21h
    or    al,1
    out   21h,al

   
    sti

    mov    eax,0dh
    push   eax
    push   Int_Msg
    call   Disp_Color_Str
    add    esp,8
   
    call   Clock_Handler

    cli
   
    in     al,21h
    and    al,0feh
    out    21h,al

   
    ret

     编译运行,依旧的画面。