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处理函数做了什么具体操作,将在后面章节进行介绍。
发表评论
要发表评论,您必须先登录。