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

来源:互联网 发布:java log4j 输出级别 编辑:程序博客网 时间:2024/06/05 19:42

     在MINIX中,中断处理程序是用宏来定义的,那么我们就来学习一下他的做法:

extern IRQ_Table

...

%macro    HW_INT_MASTER    1
    call  Save
   
    mov   al,20h
    out   20h,al
 
    in    al,21h
    or    al,(1 << %1)
    out   21h,al

   
    sti

    mov     eax,0dh
    push    eax
    push    Int_Msg
    call    Disp_Color_Str
    add     esp,8
   
    call    [IRQ_Table + (%1 * 4)]

    cli
   
    in      al,21h
    and     al,~(1 << %1)
    out     21h,al

   
    ret
%endmacro

%macro      HW_INT_SLAVE    1
    push    %1;
    call    IRQ_Handler
    add     esp,4
    hlt
%endmacro
   
HW_Int_00:
    HW_INT_MASTER        0
HW_Int_01:
    HW_INT_MASTER        1
HW_Int_02:
    HW_INT_MASTER        2
HW_Int_03:
    HW_INT_MASTER        3
HW_Int_04:
    HW_INT_MASTER        4
HW_Int_05:
    HW_INT_MASTER        5
HW_Int_06:
    HW_INT_MASTER        6
HW_Int_07:
    HW_INT_MASTER        7
HW_Int_08:
    HW_INT_SLAVE         8
HW_Int_09:
    HW_INT_SLAVE         9
HW_Int_10:
    HW_INT_SLAVE         10
HW_Int_11:
    HW_INT_SLAVE         11
HW_Int_12:
    HW_INT_SLAVE         12
HW_Int_13:
    HW_INT_SLAVE         13
HW_Int_14:
    HW_INT_SLAVE         14
HW_Int_15:
    HW_INT_SLAVE         15

     我们看到,多了一个IRQ_Table,这是函数指针数组,用来放置外中断的处理函数指针,它的类型是IRQ_Handler,在type.h中声明:

Code:
  1. typedef void (*IRQ_Handler)(u32);  

      IRQ_Table分别在global.h和global.c中声明和定义:

Code:
  1. extern IRQ_Handler IRQ_Table[];  /* in global.h */  
Code:
  1. IRQ_Handler IRQ_Table[IRQ_NUM];  /* in global.c */  

      IRQ_NUM在protect.h中定义:

Code:
  1. #define IRQ_NUM                 16  

   那么接下来就来填充IRQ_Table,除了时钟中断外都填充为IRQ_Handler函数指针,哦,该死,发现重名了,那么把函数名改成Spurious_IRQ吧,此函数在i8259.c中:

Code:
  1. void Spurious_IRQ(u32 irq_no)  
  2. {  
  3.     Disp_Color_Str("IRQ_NO:",0xd);  
  4.     Disp_Int(irq_no);  
  5.     Disp_Color_Str("/n",0xd);  
  6. }  

   相应的,在proto.h中也得改改:

Code:
  1. void Spurious_IRQ(u32 irq_no);  

       又发现了一个BUG,即Spurious_IRQ和Clock_Handler函数的类型不同,那么就把Clock_Handler改为:

Code:
  1. void Clock_Handler(u32 irq_no)  
  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. }  

     同样别忘了在proto.h中修改一下:

Code:
  1. void Clock_Handler(u32 irq_no);  

      下面就来填充这个数组吧,在Init_8259A函数中填充吧,先都填充为Spurious_IRQ,等会再填充特定的入口函数:

Code:
  1. int i;  
  2. for(i = 0 ; i < IRQ_NUM ; i++)  
  3.     {  
  4.         IRQ_Table[i] = Spurious_IRQ;  
  5.     }   

       需要包含一些头文件

Code:
  1. #include "protect.h"  
  2. #include "proc.h"  
  3. #include "global.h"  

        别忘了在HW_INT_SLAVE宏中把IRQ_Handler改为Spurious_IRQ,同时把extern IRQ_Handler改为Spurious_IRQ。

   接下来是完成在IRQ_Table中填充特定的入口函数的功能了,先在i8259.c中写成一个函数:

Code:
  1. void Put_IRQ_Handler(u32 irq_no,IRQ_Handler handler)  
  2. {  
  3.     Disable_IRQ(irq_no);  
  4.     IRQ_Table[irq_no] = handler;  
  5. }  

   Disable_IRQ和等会要写的Enable_IRQ是用汇编来写的,放在kliba.asm中,目的是屏蔽和激活一个指定的中断:

global Disable_IRQ

global Enable_IRQ

...

;Disable_IRQ==========================================================
Disable_IRQ:
    push       ebp
    mov        ebp,esp
   
    push       eax
    push       ecx
    pushf
   
    mov        ecx,[ebp + 8]
    cli
   
    mov        ah,1
    rol        ah,cl
    cmp        cl,8
    jae        disable_8
   
disable_0:
    in         al,21h
    test       al,ah
    jnz        dis_already
    or         al,ah
    out        0a0h,al
   
    popf
    pop        ecx
    pop        eax
    pop        ebp
    ret
   
disable_8:
    in         al,0a1h
    test       al,ah
    jnz        dis_already
    or         al,ah
    out        0a1h,al
   
    popf
    pop        ecx
    pop        eax
    pop        ebp
    ret
   
dis_already:
    popf
    pop        ecx
    pop        eax
    pop        ebp
    ret
;end of Disable_IRQ===================================================

;Enable_IRQ===========================================================
Enable_IRQ:
    push       ebp
    mov        ebp,esp
   
    push       eax
    push       ecx
    pushf
   
    mov        ecx,[ebp + 8]
    cli
    mov        ah,1
    not        ah
    rol        ah,cl
    cmp        cl,8
    jae        enable_8
   
enable_0:
    in         al,21h
    and        al,ah
    out        21h,al
   
    popf
    pop        ecx
    pop        eax
    pop        ebp
    ret
   
enable_8:
    in         al,0a1h
    and        al,ah
    out        21h,al
   
    popf   
    pop        ecx
    pop        eax
    pop        ebp
    ret
;end of Enable_IRQ====================================================

   别忘了在proto.h添加相关函数的声明:

Code:
  1. void Put_IRQ_Handler(u32 irq_no,IRQ_Handler handler);  
  2. void Disable_IRQ(u32 irq_no);  
  3. void Enable(u32 irq_no);  

   最后在第一个进程开始执行前用Put_IRQ_Handler初始化一下,就在Init_PCB中初始化吧:

Code:
  1. Put_IRQ_Handler(0,Clock_Handler);  
  2. Enable_IRQ(0);  

   既然在这里已经激活了时钟中断,那么在Init_8259A函数中就应该屏蔽所有中断:

 Out_Byte(0x21,0xff);

   OK,到此为止所有的代码都已经修改添加完毕,编译运行,画面依然如故,但是我们的程序已经有了良好的扩展性,虽然还很幼稚,很多东西如进程优先级,进程间调度等都没有考虑到。虽然看起来很简单,但要想一口气从头写到尾,还是不太可能的。今天到此为止,休息,休息。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 石灰粉进入眼睛怎么办 幼儿误吃粉笔怎么办? 吃了粉笔应该怎么办 小孩吃了颜料怎么办 小宝宝吃了纸怎么办 孩子不认真听讲怎么办 监控手机软件离线状态怎么办 云课堂忘记密码怎么办 广州办培训机构怎么办 一师一优课账号忘了怎么办 云相册空间不足怎么办 三星云空间不足怎么办 三星储存空间不足怎么办 宁阳县教育局强制补课怎么办 沉迷网络该怎么办英语 29岁沉迷游戏怎么办 学乐云登录不上怎么办 魔方学院无法识别怎么办 路由器卫士忘记密码怎么办 邮箱号忘记密码怎么办 水卡没钱了怎么办 旅行青蛙换手机怎么办 软件尚未受信任怎么办 百度搜不到的怎么办 百度中搜不到怎么办 山寨云网络异常怎么办 手机太重了怎么办 百度云网页版打不开怎么办 微鲸电视打不开怎么办 手机一直没信号怎么办 孩子作业效率低怎么办 员工做事效率低怎么办 吉他和弦转换慢怎么办 耳机低音轰头怎么办? 全民k歌太占内存怎么办 qq音乐登录失效怎么办 电视猫自动升级怎么办 酷狗账号注销怎么办 电脑监控老是坏怎么办 qq音乐qq登不上怎么办? 繁星工会解约不同意怎么办?