《30天自制操作系统》学习笔记(六)

来源:互联网 发布:如何用java做网站 编辑:程序博客网 时间:2024/04/30 01:01
IDT学习心得
(一)什么是中断?
    通常被定义为一个事件,该事件改变处理器执行的指令顺序。例如通过键盘输入、点击鼠标等

(二)为什么要引入中断?
    因为CPU的处理速度远高于外围硬件设备的响应速度,为了提高CPU的利用率,所以引入了中断机制。当某个设备发生变化时便会产生中断,CPU就暂时停止正在处理的事务,并做好接下来能够继续处理的准备,转而执行中断程序。中断执行完以后,在调用事先设定好的函数,返回处理中的任务。这样CPu可以不用一直查询外围硬件设备的状态,而将精力放在处理任务上。

(三)由中断机制引出的问题--当发生中断时,如何告诉CPU该做些什么?
    通过中断描述,中断描述符包括了中断门描述符、陷阱门描述符和任务门描述符任务门描述符在有的系统中没有用到


(四)中断描述符如何存储?
    与GDT类似,中断描述符也是在内存中连续存储,形成了一个中断描述符表(Interruptor Descriptor Table,IDT),所以要想正确使用中断,必须正确设置GDT和IDT。

(五)CPU如何查找IDT?
    与GDT的原理一样,利用了一个叫IDTR的寄存器(注意此处是寄存器,不是内存了,需要和IDT区别对待)。GDTR中高32位表示GDT在内存中的基地址,低16位表示表界限,所以就明确的给出了GDT在内存中的存储信息。

(六)中断描述符如何实现功能?
    通过中断门描述符的结构图可知,其中存储了16位的段选择符(Segment Selector),CPU根据这个段选择符,从GDT中选择相应的段描述符(Segment Descriptor),并执行相应的代码。如下图。
(七)中断向量又是什么?
其实每一种中断(异常)都会对应一个中断向量号,具体有哪些中断向量,可以看下表:
向量号助记符描述类型出错码源0#DE除法错Fault无DIV和IDIV指令1#DB调试异常Fault/Trap无任何代码和数据的访问2—非屏蔽中断Interrupt无非屏蔽外部中断3#BP调试断点Trap无指令INT 34#OF溢出Trap无指令INTO5#BR越界Fault无指令BOUND6#UD无效(未定义)操作码Fault无指令UD2或无效指令7#NM设备不可用(无数学协处理器)Fault无浮点或WAIT/FWAIT指令8#DF双重错误Abort有(0)所有能产生异常或NMI或INTR
的指令9

协处理器段越界(保留)Fault无浮点指令(386后不再处理此
异常)10#TS无效TSSFault有任务切换或访问TSS时11#NP段不存在Fault有加载段寄存器或访问系统段时12#SS堆栈段错误Fault有堆栈操作或加载SS时13#GP常规保护错误Fault有内存或其他保护检验14#PF页错误Fault有内存访问15—Intel保留,未使用



16#MFx87FPU浮点错(数学错)Fault无x87FPU浮点指令或WAIT/FWAIT指令17#AC对齐检验Fault有(0)内存中的数据访问(486开始支持)18#MCMachine CheckAbort无错误码(若有的话)和源依赖于
具体模式(奔腾CPU开始支持)19#XFSIMD浮点异常Fault无SSE和SSE2浮点指令(奔腾三
开始支持)20~31—Inter保留,未使用



32~255—用户定义中断Interrupt

外部中断或int n指令

上表中除了两个Interrupt(中断)外,其他还有三种Fault、Trap、Abort异常。我们这里讨论的中断主要是用户定义中断,这种中断产生的原因有两种:一是外部中断,就是由硬件产生的中断;另一种是由指令int n产生的中断。

外部中断的情况则复杂一些,因为需要建立硬件中断和向量号之间的对应关系。外部中断的简单示意图如下:


(八)如何将中断向量与中断描述联系起来

1.通过对8259A的配置,可将IRQ0~IRQ7对应到中断向量20h~27h,同样地IRQ8~IRQ15可对应到中断向量28h~2Fh。书中给出的代码如下:

void init_pic(void)
/* PIC初始化 */
{
    io_out8(PIC0_IMR,  0xff  ); /* 禁止所有中断,主片 */
    io_out8(PIC1_IMR,  0xff  ); /* 禁止所有中断,从片*/
    //主片设置
    io_out8(PIC0_ICW1, 0x11  ); /* 沿边触发模式 */
    io_out8(PIC0_ICW2, 0x20  ); /* IRQ0-7由INT20-27接收*/
    io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2连接*/
    io_out8(PIC0_ICW4, 0x01  ); /*无缓冲区模式*/
    //从片设置
    io_out8(PIC1_ICW1, 0x11  ); 
    io_out8(PIC1_ICW2, 0x28  ); /* IRQ8-15由INT28-2f接收 */
    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 禁止所有中断*/

    return;
}

2.制作中断处理程序

3.注册到IDT中
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
    gd->offset_low   = offset & 0xffff;
    gd->selector     = selector;
    gd->dw_count     = (ar >> 8) & 0xff;
    gd->access_right = ar & 0xff;
    gd->offset_high  = (offset >> 16) & 0xffff;
    return;
}
struct GATE_DESCRIPTOR *gd--表示要注册的IDT位置
int offset--偏移(这个偏移是在代码段中的偏移)
int selector--对应的段描述符的选择子

4.调用
例如set_getdesc(idt+0x21,(int)asm_inthandler21,2*8,AR_INTGATE32)

0 0
原创粉丝点击