SmlOS六-中断控制实现

  • 内容
  • 评论
  • 相关

设置处理函数

中断的来自于PIC,首先需要对PIC进行初始化。PIC是一个集成了8个中断信号到一个中断信号装置。

至于PIC的介绍,已经在系统启动前期处理章节做了介绍。

IDT函数表设置,也已经在GDT和IDT初始化中做了介绍。

其中有些序号是固定的:

中断序号 说明
IRQ0 时钟
IRQ1 键盘
IRQ2 接连int
IRQ3 串行口2
IRQ4 串行口1
IRQ5 并行口2
IRQ6 软盘
IRQ7 并行口1
IRQ8 实时钟
IRQ9 INTOAH
IRQ10 保留
IRQ11 保留
IRQ12 PS2鼠标
IRQ13 协处理器
IRQ14 硬盘
IRQ15 保留

中断功能的实现,需要满足以下几个条件。

  • 1.开启相应的IRQ。
  • 2.注册相应的IDT。
  • 3.实现相应的中断函数。

初始化PIC,开启IRQ

// 初始化PIC 
void Init_PIC(void)
{
    io_out8(PIC0_IMR,  0xff  ); //禁止主PIC所有中断 
    io_out8(PIC1_IMR,  0xff  ); //禁止从PIC所有中断 

    io_out8(PIC0_ICW1, 0x11  ); //需要ICW4, 多片级联, 边沿触发方式 
    io_out8(PIC0_ICW2, 0x20  ); //IRQ0-7由于INT 0x20~0x27接收 
    io_out8(PIC0_ICW3, 1 << 2); // PIC1由IRQ2连接 
    io_out8(PIC0_ICW4, 0x01  ); //普通全嵌套 非缓冲 非自动结束中断方式 

    io_out8(PIC1_ICW1, 0x11  ); //需要ICW4, 多片级联, 边沿触发方式 
    io_out8(PIC1_ICW2, 0x28  ); //IRQ8-15由于INT 0x28~0x2f接收 
    io_out8(PIC1_ICW3, 2     ); //PIC1由IRQ2连接 
    io_out8(PIC1_ICW4, 0x01  ); //普通全嵌套 非缓冲 非自动结束中断方式 

    io_out8(PIC0_IMR,  0xfb  ); //11111011 PIC1以外全部禁止 
    io_out8(PIC1_IMR,  0xff  ); //11111111 禁止从PIC所有中断 

    return;
}

在对中断设定进行更改时,如果再接收其他的中断会引起混乱,所以要屏蔽中断。

这里对PIC 的设定使用OUT指令实现,对于我们要开的中断而言,这里只开启了PIC1就够用了.


设置IDT

初始化PIC后,就能产生中断了

但是中断会调用哪个函数,则需要设置IDT了

请参考GDT和IDT初始化中IDT设置相关内容

具体代码:

//时钟中断
set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
//键盘中断
set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
//鼠标中断
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);

这里主要处理了:时钟中断(IRQ0),键盘中断(IRQ1),鼠标中断(IRQ12)


实现中断处理函数

中断函数需要保存现场,即保存相应寄存器内容,需要把相应寄存器值入栈在程序结束后在进行出栈操作。

在调用完c实现的处理后,再恢复寄存器的值。

以时钟中断为例:

_asm_inthandler20:  ; IRQ0  时钟
    PUSH    ES
    PUSH    DS
    PUSHAD                  ; 保存寄存器
    MOV     EAX,ESP
    PUSH    EAX
    MOV     AX,SS           ; 修改DS ES SS
    MOV     DS,AX
    MOV     ES,AX
    CALL    _inthandler20   ; 调用处理函数
    POP     EAX             ; 恢复各个寄存器的值
    POPAD
    POP     DS
    POP     ES
    IRETD

至于_inthandler20处理函数做了什么具体操作,将在后面章节进行介绍。