- 01、中断和异常概述
- 02、保护模式下中断和异常的向量分配
- 03、中断描述符表、中断门和陷阱门
- 04、本章程序介绍
- 05、创建并安装全部的256个中断门
- 06、为实时时钟中断创建和安装中断门
- 07、加载中断描述符表寄存器IDTR
- 08、重新设置8259A主片的中断向量
- 09、中断和异常发生时的特权级检查
- 10、中断和异常发生时的栈切换过程
- 11、在中断处理过程中实施任务切换(含NOP指令的介绍)
- 12、抢占式多任务的执行效果演示
协同式任务切换不一定要通过一个专门的接口例程进行,也可以用一般的例程进行。
用户任务通过调用门切换到内核的put_string例程执行,在内核任务返回用户任务之前可以进行任务切换,之后再通过retf返回用户任务执行。
- 硬件中断信号,NMI是不可屏蔽中断、INTR是来自硬件中断引脚的可屏蔽中断。随机产生,与处理器是异步的。
- 软件中断,INT n是在软件内部主动引发的中断。
- 处理异常中断(Exceptions),是处理器内部产生的中断,表示处理器执行时产生了错误的状况。比如当处理器执行一条非法指令或者因条件不具备指令不能正常执行时将会引发这种类型的中断。如div指令中除数是0的情况。
中断和异常。
按照异常的产生原因分类:
- 指令执行异常:处理器在执行指令时检测到程序的错误并由此而引发的异常。
- 程序调试异常:供调试器使用,由INTO、INT3主动发起。用来检查特定的机器状态是否出现。INTO检查标志寄存器的OF=1(溢出标志)则执行指令引发异常。INT3指令供调试器进行单步执行。
- 机器检查异常:和处理器架构有关,如在奔腾4、P6处理器家族上就实现了机器检查架构,用这种异常检测与硬件有关的总线错误、奇偶校验错误、高速缓存错误等等。
根据异常的性质和严重性分类:
- 故障(Faults):通常可以纠正,如缺页异常。中断程序返回的是当前指令。
- 陷阱(Traps):通常是在执行了截获陷阱条件的指令之后立即产生,通常用于调试INT3、INTO。中断程序返回的是当前指令的下一条指令。
- 终止(Aborts):通常标志最严重的错误,如硬件错误、系统表错误(如GDT、LDT数据不一致、无效、错误),这类异常一般无法精确的报告引起错误的指令的位置。发生时程序和错误都不可能重新启动,双重异常(当处理器发生异常时,在转入异常执行时有发生了另外一个异常)如中断向量号18,INT 0x18。
对于某些异常来说,处理器在转入异常处理程序之前,会在当前栈中压入一个称为错误代码的数值,这样可以帮助诊断异常产生的位置和原因。
02、保护模式下中断和异常的向量分配中断和异常的编号叫做中断向量。
其中错误代码是在中断发生时,在进入中断处理程序之前压在栈中的错误代码。
实模式下的中断向量表:
中断发生时,处理器要么自发产生一个中断向量、要么从软中断指令的操作数的到中断向量、或者从外部的中断控制器取得一个中断向量。将该向量作为索引访问中断向量表IVT,具体做法是将中断向量乘以4作为偏移量访问IVT,从中取得中断处理过程的段地址和偏移地址,并转到那里执行。
保护模式下:使用中断描述符表IDT(Interrupt Descriptor Table),保存和中断处理过程相关的描述符,包括中断门、陷阱门、任务门,门是特殊的描述符。
中断门描述符用来描述中断处理过程。
陷阱门描述符用来描述陷阱中断的处理过程。
任务门,32位处理器中支持,若IDT中描述的是一个任务门,则执行的是一个任务切换。在64位处理器中既不支持硬件任务切换、也不支持任务门。
实模式下的中断向量表IVT只能位于内存的最低端。保护模式下的中断描述符表IDT可以位于内存的任何位置。
IDT的第一个描述符即0号槽位也是有效的。
- 处理器用中断向量 乘以 8得到表内偏移量,联合IDTR内的IDT基地址去访问内存;
- 从中取得中断门或陷阱门描述符;
- 在描述符中有中断处理过程的代码段选择子和段内偏移量;
- 取决与代码段选择子的TI位,去GDT或LDT中取得目标代码段的描述符。
- 从目标代码段的描述符中取得目标代码段的段基地址;
- 将段基地址 和 偏移量相加得到中带处理过程的线性基地址,从而转移执行。
使用中断向量访问IDT时,中断向量超过IDT界限值时,就会产生常规保护异常#GP。
04、本章程序介绍引导程序:c13_mbr0.asm
- 1、取出GDT所在线性基地址
- 2、创建本程序相关描述符,接着使用cli指令关闭中断响应。
- 3、进入保护模式
- 4、加载内核代码到内存中
- 5、创建内核相关描述符
- 6、跳转执行内核
内核程序:c30_core0.asm
- 1、创建各个段的选择子常量和IDT线性地址;
- 2、内核头部段;
- 3、内核公共历例程段,除了之前创建的相关历程,本章增加了几个和中断相关的例程;
- 4、内核核心数据段,各种数据。
- 5、内核核心代码段,改变了内核入口点start的程序。
用户程序0:c30_app0.asm
- 其他不变,死循环打印字符,,,,,。
用户程序1:c30_app1.asm
- 其他不变,死循环打印字符cccccccccc。
在进入内核start之后,准备创建内核任务、用户任务并进行任务切换,在此之前需要主备好保护模式下的中断系统。
中断或异常发生时,并不是直接调用中断或异常处理程序,而是用中断向量先到中断描述符表中寻找对应的中断描述符,即中断门或陷阱门,之后从中断门或陷阱门中间接找到中断处理过程。意味着必须为这个通用的中断处理过程创建中断门或陷阱门,并安装在中断描述符表IDT中。
创建中断门代码如下:
。。。 ;前20个向量是处理器异常使用的 mov eax,general_exception_handler ;门代码在段内偏移地址 mov bx,sys_routine_seg_sel ;门代码所在段的选择子 mov cx,0x8e00 ;32位中断门,0特权级 call sys_routine_seg_sel:make_gate_descriptor 。。。
中断门属性值8E00:
创建好之后需要安装在中断描述符表IDT中,IDT现在还没有创建,创建IDT就是指定表的其实线性基地址,并从这个地址安装中断门和陷阱门就可以了。
目前系统内存布局:
依次安装中断门或陷阱门:前20个中断门指向通用处理过程general_exception_handler。
。。。 mov ebx,idt_linear_address ;中断描述符表的线性地址 xor esi,esi .idt0: mov [es:ebx+esi*8],eax ;基址变址寻址 mov [es:ebx+esi*8+4],edx inc esi cmp esi,19 ;安装前20个异常中断处理过程 jle .idt0 。。。
之后安装通过的中断门:后236个中断门都指向同一个中断处理程序general_interrupt_handler。
。。。 ;其余为保留或硬件使用的中断向量 mov eax,general_interrupt_handler ;门代码在段内偏移地址 mov bx,sys_routine_seg_sel ;门代码所在段的选择子 mov cx,0x8e00 ;32位中断门,0特权级 call sys_routine_seg_sel:make_gate_descriptor mov ebx,idt_linear_address ;中断描述符表的线性地址 .idt1: mov [es:ebx+esi*8],eax mov [es:ebx+esi*8+4],edx inc esi cmp esi,255 ;安装普通的中断处理过程 jle .idt1 。。。06、为实时时钟中断创建和安装中断门
使用实时时钟中断,默认中断号0x70,当发生0x70号中断时并不是执行一个通用的中断过程,而是执行它自己的中断处理过程rtm_0x70_interrupt_handle。
现在需要创建0x70号中断的中断门,并安装在中断描述符表中,以替换原先的通用中断门。
。。。 ;设置实时时钟中断处理过程 mov eax,rtm_0x70_interrupt_handle ;门代码在段内偏移地址 mov bx,sys_routine_seg_sel ;门代码所在段的选择子 mov cx,0x8e00 ;32位中断门,0特权级 call sys_routine_seg_sel:make_gate_descriptor mov ebx,idt_linear_address ;中断描述符表的线性地址 mov [es:ebx+0x70*8],eax mov [es:ebx+0x70*8+4],edx 。。。07、加载中断描述符表寄存器IDTR
接上一节,现在已经在中断描述符表中安装了256个中断门,除了0x70号中断,其他都指向默认中断或异常处理过程。
当中断发生时,处理器如何找到中断描述符表呢?处理器中有一个中断描述符表寄存去IDTR,保存着中断描述符表IDT的线性基地址以及长度。现在应该将IDT的基地址和界限值加载到IDTR中。
偏移为m的地方开辟出6个字节的空间。前2字节保存IDT的界限值、后4字节保存这IDT的线性基地址。执行此条指令时,处理器用段寄存器中的线性基地址 加上 指令中的偏移m 构成物理地址访问内存取出这6个字节。然后传送到处理器内部的IDTR寄存器中。该指令在实模式下也能执行。
开机时,IDTR中基地址被初始化为0x00000000,界限值被初始化为0xFFFF。lidt指令不影响任何标志位。代码如下:
。。。 ;准备开放中断 mov word [pidt],256*8-1 ;IDT的界限 mov dword [pidt+2],idt_linear_address lidt [pidt] ;加载中断描述符表寄存器IDTR 。。。08、重新设置8259A主片的中断向量 09、中断和异常发生时的特权级检查 10、中断和异常发生时的栈切换过程 11、在中断处理过程中实施任务切换(含NOP指令的介绍) 12、抢占式多任务的执行效果演示



