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

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

     首先是把重复的代码合并掉,在初次进入进程之前的一系列pop等语句和时钟中断处理程序中的后半截的语句是雷同的,我们想把这些重复的代码合并在一起,先这样修改时钟中断处理系统:

HW_Int_00:
    pushad
    push    ds
    push    es
    push    fs
    push    gs
    mov    dx,ss
    mov    ds,dx
    mov    es,dx
    
    inc byte [gs:0]

    mov al,20h
    out 20h,al

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

    sti

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

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

reenter:
    dec dword [Is_Reenter]    
    
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
    
    iretd

      为什么要这样改啊?相信每个人刚开始看到这段代码都会很诧异,看到后面你就明白了。如果发生了重入,则压入.reenter标号,如果没有发生重入,则压入.restart标号,最后执行完Clock_Handler后一句ret就搞定了。我们的目的是什么,就是为了合并重复的代码咯,想达到某种目的,往往是要付出代价的。上面的修改不仅仅是修改了形式,内容上也有了少许变化,即使是中断重入了,也要调用Clock_Handler函数,我们来修改一下这个函数,让它在中断重入的时候打印一个感叹号后直接return,打印感叹号的目的是提醒我们此时发生中断重入

Code:
  1. void Clock_Handler()  
  2. {  
  3.     if(Is_Reenter != 0)  
  4.     {  
  5.         Disp_Color_Str("!",0xe);  
  6.         return;       
  7.     }  
  8.       
  9.     p_Resume_PCB++;  
  10.     if(p_Resume_PCB >= PCB_Tables + 2)  
  11.     {  
  12.         p_Resume_PCB = PCB_Tables;        
  13.     }  
  14. }  

      用到了Disp_Color_Str函数,需要包含proto.h头文件,MAKEFILE也别忘了加进来。

      编译链接,结果不变。

      接下来修改初次进入进程前的代码,我们要使这段代码跟时钟中断处理程序的后半段一样,直接复制过来就好,只是比原来多了一句:dec dword [Is_Reenter],为了保持一致,这就是代价,所以我们不得不改变Is_Reenter的初始值:

      在global.c中:

Code:
  1. u32 Is_Reenter = 0;  

   那么初次进入进程前的代码变为:

_test:
 ;jmp    100:0
 ;sti
 
restart:
    mov    esp,[p_Resume_PCB]
    lea    dword eax,[esp + 68]
    mov    [tss + 4],eax
    mov    ax,[esp + 68]
    lldt ax

reenter:
    dec dword [Is_Reenter]   
   
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
   
    iretd

  则时钟中断处理程序ret后面的代码就可以全部去掉了。

  编译运行结果不变,但我们的代码比起以前来更加简洁了。