【第6章】丰富中断处理程序

      前面的中断处理程序过于简单了,只有一句iretd,而且这个时钟中断处理程序也只能发生一次,因为没有通知8259A本次中断处理程序已结束。就算处理程序能反复执行,我们也不能看到结果,所以还要在中断处理程序中添加一点显示信息来使我们知道中断程序在运行,下面就来修改:

HW_Int_00:
    ;push    0;
    ;call    IRQ_Handler
    ;add        esp,4
    ;hlt
    mov al,20h
    out 20h,al
    inc byte [gs:0]

    
    iretd

   最好每前进一步就make一下,以便发现错误能及早发现,下面是结果:

      可以看到左上角的字符按照ASCII码的顺序在跳动,这时显示的是感叹号。

      由于在以后的时钟中断处理程序中我们想处理更多的问题,如进程调度等。那就免不了要使用寄存器了,那么在使用之前就必须把当前的寄存器的值保存到当前进程的PCB中,所以在中断程序刚刚开始的地方需要把各寄存器的值保存在当前的PCB中,由于TSS中的esp0字段刚好指向当前进程PCB的寄存器组的最高位置,所以使用就可以直接进行压栈操作了,在中断处理程序将要结束时就把PCB中的值再pop出去,下面修改一下代码:

HW_Int_00:
    ;push    0;
    ;call    IRQ_Handler
    ;add        esp,4
    ;hlt
    pushad
    push    ds
    push    es
    push    fs
    push    gs

    
    mov al,20h
    out 20h,al
    inc byte [gs:0]
    
    pop    gs
    pop    fs
    pop es
    pop    ds
    popad

    iretd

        如果是修改TSS中esp0的问题,如果我们有多个进程,需要在时钟中断处理程序中切换时,我们需要在中断处理程序中把esp0切到想要切换的那个进程的PCB的寄存器组的最高位置。现在的程序中只有一个进程在运行,所以这样做暂时是做无用功,那以后我们还是要实现多进程的,所以先这样做吧,免得以后忘记了,下面是修改:

HW_Int_00:
    ;push    0;
    ;call    IRQ_Handler
    ;add        esp,4
    ;hlt
    pushad
    push    ds
    push    es
    push    fs
    push    gs
    
    mov    al,20h
    out 20h,al
    inc byte [gs:0]
    
    lea  eax,[esp + 68]
    mov  dword [tss + 4],eax

    
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
    
    iretd

   还有一个重要的问题,就是在时钟中断处理程序中免不了要使用堆栈,而经过一番push之后esp指向的是当前进程PCB的寄存器组的最低位置,如果此时在中断处理程序中调用一个函数的话,就会殃及到上一个进程的PCB,造成混乱。所以我们必须把堆栈切换到内核堆栈,而在中断处理程序将返回时把esp0又重新切换到当前进程的PCB的寄存器组的最高位置处,还得把ds,es切换回在GDT下的描述符,下面就来修改:

HW_Int_00:
    ;push    0;
    ;call    IRQ_Handler
    ;add     esp,4
    ;hlt
    pushad
    push    ds
    push    es
    push    fs
    push    gs
    
    mov    dx,ss
    mov    ds,dx
    mov    es,dx
    mov    esp,Top_Of_Stack

    
    mov al,20h
    out 20h,al
    
    inc byte [gs:0]
    
    mov    esp,[p_Resume_PCB]
    
    lea eax,[esp + 68]
    mov    dword [tss + 4],eax
    
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
    
    iretd

      这样,我们的时钟中断处理程序稍微完善了一点,可以在中断程序中做我们想做的事情,如可以自由的调用一些函数而无需担心堆栈引起的问题,下面我们想在中断的过程中打印一些字符,下面来修改一下

extern Disp_Color_Str

...

[section .data]

Int_Msg:    db '*',0

...

HW_Int_00:
    ;push    0;
    ;call    IRQ_Handler
    ;add        esp,4
    ;hlt
    pushad
    push    ds
    push    es
    push    fs
    push    gs
   
    mov    dx,ss
    mov    ds,dx
    mov    es,dx
    mov    esp,Top_Of_Stack
   
    mov    al,20h
    out 20h,al
   
    inc byte [gs:0]
   
    mov    eax,0dh
    push    eax
    push    Int_Msg
    add    esp,8

   
    mov    esp,[p_Resume_PCB]
   
    lea eax,[esp + 68]
    mov    dword [tss + 4],eax
   
    pop    gs
    pop    fs
    pop    es
    pop    ds
    popad
   
    iretd

     编译链接,在VPC下的运行结果如图所示:

     

      在BOCHS下的运行结果如下:

         可见,两个虚拟机的速度有明显的差距啊。。

你可能感兴趣的:(【第6章】丰富中断处理程序)