OS_lab——中断与异常

2024-01-08 16:07:11
  1. 理解中断与异常的机制
  2. 调试?8259A?的编程基本例程
  3. 调试时钟中断例程
  4. 实现一个自定义的中断向量,功能可自由设想。

中断和异常

中断和异常都是程序执行过程中的强制性转移,转移到相应的处理程序。

中断通常因为硬件而发生,用来处理处理器外部的事件,?比如外围设备的请求。

异常通常在处理器执行指令过程中检测到错误时发生,比如除零, 页错误等

什么是中断

在实模式下,使用的是?BIOS?中断。BIOS?中断是由系统提供的使用?BIOS?的一组功能。中断存在中断向量表中。

在保护模式下,?BIOS?中断不能使用。原来的中断向量表被?IDT(中断描?述符表)?代替。

IDT

IDT?中的描述符有三种

? ??????中断门描述符(int?调用)

? ??????陷阱门描述符(call?调用)

? ??????任务门描述符(不常用,?Linux?根本没用)

IDT?的作用是将每一个中断向量和一个描述符对应起来。

中断产生有两种情况

? ???????硬件产生的外部中断

? ???????intn

intn?类型调用使用?IDT?寻找中断处理程序,类似调用门的使用

外部中断:?要建立硬件中断和中断向量号之间的对应关系

? ?????不可屏蔽中断(NMI?引脚接收,于?IF?是否被设置无关,对应中断向?量号为?2)

? ?????可屏蔽中断(INTR?接收,中断和向量号的关系由可编程中断控制器 8259 A?建立)

什么是异常

异常的三种类型

? ??????Fault:可更正的异常,?处理完返回到原指令

?? ? ? ?Trap :原指令执行后报告,处理完返回到之后的指令
?? ? ?? Abort :确认不了精确位置,不能继续运行
调试 8259 A
8259 A 工作原理

????????功能

????????? ?????根据优先级在同时发生的中断设备中选择应该处理的请求

????????? ?????通过对其寄存器的设置来屏蔽或打开相应中断?结构和工作原理

????????结构:两片级联的?8259A?与?CPU?相连,共挂十五个外设。

????????工作:

????????主?8259A?对应的端口地址是?20?h?和?21?h

????????从?8259A?对应的端口地址是 A0?h ?和?A1?h

????????设置?8259A:通过向相应的端口写入特定的?ICW

??????????? ? ? 往端口 20 h (主片)或 A0 h (从片)写入 ICW 1
??????????? ? ? 往端口 21 h (主片)或 A1 h (从片)写入 ICW 2
??????????? ? ? 往端口 21 h (主片)或 A1 h (从片)写入 ICW 3
?????????? ? ?? 往端口 21 h (主片)或 A1 h (从片)写入 ICW 4

?

ICW??格式

分析

ICW?1 ?触发模式,选择中断向量种类,选择?8259A?架构

ICW?2?决定对应哪个中断向量

ICW 3?决定了传进哪个外设中断

ICW 4??正常为?01?h

写入?ICW?2?时, IRQ 0~?IRQ 7?对应?20?h ~?27?h;同理?IRQ 8 ~?IRQ?15?对应?28?h?~?2?F?h

io_delay 函数:延迟函数,等待操作完成

314 ~?322?屏蔽了所有的外部中断,此时写入的是?OCW

使用?OCW?的两种情况

???????屏蔽或打开外部中断

? ??????发送?EOI?给?8259A?通知它中断处理结束

屏蔽或打开外部中断,只需往?8259A?写入?OCW?1?即可

OCW?1 被写入中断屏蔽寄存器(IMR)

发送?EOI 给?8259A 通过往?20 h ?或 A0 h?写?OCW 2 来实现的

mov ?al ????, ?20h

out?20h/A0h,?al

如何建立IDT,如何实现一个自定义的中断

建立?IDT

IDT?段

/*

255 个描述符完全相同

SpuriousHandler : 在屏幕右上角打印红色"!",然后死循环

*/

// SpuriousHandler?实现

//?加载IDTR

实现一个中断

/*

修改IDT ?--->?80h?中断单独列出来?---> 新增一个函数来处理中断?UserIntHandler??在末尾iretd?指令返回

*/

新增一个函数

UserIntHandler?实现

3.??时钟中断例程

pmtest9.asm?部分代码展示

时钟中断处理程序

_ClockHandler:

ClockHandler???equ _ClockHandler - $$

inc byte?[gs:((80 * 0?+ 70) *?2)]??;?屏幕第?0?行, 第?70?列。

mov al,?20h

out 20h, al????????????;?发送?EOI

iretd

打开时钟中断

;mov???al, 11111111b ??; 屏蔽主?8259?所有中断

mov al, 11111110b ??; 仅仅开启定时器中断

out 021h, al???; 主?8259, OCW1.

call???io_delay



mov al, 11111111b ??; 屏蔽从?8259?所有中断

out 0A1h, al???; 从?8259, OCW1.

call???io_delay

IDT?表的修改

LABEL_IDT:

; 门????????????????????????目标选择子,??????????偏移,?DCount,?属性

%rep?32

Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate

%endrep

.020h: Gate SelectorCode32, ClockHandler, 0, DA_386IGate

%rep 95

Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate

%endrep

.080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGate

IdtLen equ $ - LABEL_IDT

IdtPtr dw IdtLen - 1 ; 段界限

dd 0 ; 基地址



; END?of?[SECTION?.idt]

开中断

call??Init8259A



int 080h

sti

jmp $

代码调试调试

在时钟中断处理程序?ClockHandler?中插入?Magic?Break:

_ClockHandler:

ClockHandler???equ _ClockHandler - $$

xchg bx,?bx

inc byte?[gs:((80 * 0?+ 70) *?2)]??;?屏幕第?0?行, 第?70?列。

mov al,?20h

out 20h, al????????????;?发送?EOI

iretd

调试截图展示如下:

尽管没有使用?int?指令直接跳转,因为外中断的特性,程序进入了设置好的?02h?中断,将?int 80h?设置的字符进行变化。??实验结果展示如下:

4. ??自定义的中断向量

自定义中断功能

int?80h?中断

功能说明:初始化时间字符串"20yy/mm/dd hh:mm:ss"为当前时间,?并输出在屏幕上

int 20h?中断(时间中断)

功能说明:将屏幕上已输出的时间字符串更新为当前时间

部分代码展示

int?80h?中断

LABEL_DATA:
_szTime               db  "20yy/mm/dd hh:mm:ss", 0
szTime         equ _szTime            - $$
DataLen        equ $ - LABEL_DATA
; END of [SECTION .data1]
...

_UserIntHandler:
UserIntHandler equ _UserIntHandler - $$
    xor eax, eax

    xor ebx, ebx 
    xor esi, esi 
    xor edi, edi 
    mov esi, szTime ; 源数据偏移

    mov al,  9         ; 年
    out 70h, al
    in  al,  71h
    mov bl,  al        ; 十位
    shr bl, 4
    and al,  0fh       ; 个位
    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 2], ah  ; 赋值
    mov [esi + 3], al

    mov al,  8         ; 月
    out 70h, al
    in  al,  71h
    mov bl,  al        ; 十位
    shr bl, 4
    and al,  0fh       ; 个位
    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 5], ah  ; 赋值
    mov [esi + 6], al

    mov al,  7         ; 日
    out 70h, al
    in  al,  71h
    mov bl,  al        ; 十位
    shr bl, 4
    and al,  0fh       ; 个位
    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 8], ah  ; 赋值
    mov [esi + 9], al

    mov al, 4 ; 时 
    out 70h, al 
    in al, 71h 
    mov bl, al ; 十位 
    shr bl, 4 
    and al, 0fh ; 个位

    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 11], ah  ; 赋值
    mov [esi + 12], al

    mov al, 2         ; 分
    out 70h, al
    in  al,  71h
    mov bl,  al        ; 十位
    shr bl, 4
    and al,  0fh       ; 个位
    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 14], ah  ; 赋值
    mov [esi + 15], al

    mov al,  0         ; 秒
    out 70h, al
    in  al,  71h
    mov bl,  al        ; 十位
    shr bl, 4
    and al,  0fh       ; 个位
    mov ah,  bl
    add ax, 03030h    ; 转换为 ascii 码
    mov [esi + 17], ah  ; 赋值
    mov [esi + 18], al

    ; 下面显示一个字符串
    mov ah, 0Ch                ; 0000: 黑底    1100: 红字
    mov edi, (80 * 8 + 0) * 2  ; 目的数据偏移。屏幕第 8 行, 第 0 列。
    cld
.1:
    lodsb
    test   al, al
    jz     .2
    mov     [gs:edi], ax
    add    edi, 2
    jmp    .1
.2: ; 显示完毕

    iretd

int?20h?时间中断

_ClockHandler:

ClockHandler???equ _ClockHandler - $$

    xor eax, eax
    xor ebx, ebx



    mov al, ?9????????????????????; 年
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????;?十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov?[gs:((80 * 8 + 2) *?2)],?ah?;?更改屏幕显示
    mov?[gs:((80 * 8 +?3)?*?2)],?al

    mov al, ?8????????????????????;?月
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????;?十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov?[gs:((80 * 8 + 5)?*?2)], ah?;?更改屏幕显示
    mov?[gs:((80 * 8 +?6)?*?2)],?al

    mov al, ?7????????????????????;?日
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????; 十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov?[gs:((80 * 8 + 8) *?2)], ah?;?更改屏幕显示
    mov?[gs:((80 * 8 + 9)?*?2)],?al

    mov al, ?4 ????????????????????; 时
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????;?十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov [gs:((80 *?8 +?11)?*?2)],?ah;?更改屏幕显示
    mov?[gs:((80 * 8 +?12)?*?2)], al

    mov al,?2????????????????????;?分
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????;?十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov [gs:((80 *?8 +?14)?*?2)],?ah;?更改屏幕显示
    mov?[gs:((80 * 8 +?15)?*?2)], al

    mov al, ?0????????????????????; 秒
    out 70h, al
    in ?al, ?71h
    mov bl, ?al???????????????????;?十位
    shr?bl,?4
    and al, ?0fh ??????????????????; 个位
    mov ah, ?bl
    add ax,?03030h ???????????????; 转换为?ascii?码
    mov [gs:((80 *?8 +?17)?*?2)],?ah;?更改屏幕显示
    mov?[gs:((80 * 8 +?18)?*?2)], al

    mov al,?20h
    out 20h, al???????????????????;?发送?EOI

    iretd

中断调用

; 下面显示一个字符串
push???szPMMessage
call???DispStr
add????esp, 4

; 调用中断向量
int????080h
sti
jmp????$

实验结果展示

成功输出当前时间,?且不断进行更新。

=========================================================================

实验结果总结
  1. 什么是中断,什么是异常
  2. 8259A?的工作原理是怎样的?怎么给这些中断号的处理向量初始化值?
  3. 如何建立?IDT,如何实现一个自定义的中断
  4. 如何控制时钟中断,为什么时钟中断时候,没有看到?int?的指令?
  5. 简要解释一下?IOPL?的作用与基本机理

1. ??什么是中断,什么是异常?

中断包括外部中断和来自于指令?int?n?的中断(n?即向量号),其中外部中断又分为不可?屏蔽中断(NMI?引脚接收,于?IF?是否被设置无关,对应中断向量号为?2)和可屏蔽中断(INTR?接收, 中断和向量号的关系由可编程中断控制器 8259A ?建立)。中断是由硬件设备产生的,?从物理上说就是电信号,?它们通过中断控制器(8259A)发送给?CPU,接着?CPU 判断收到的?中断来自于哪个硬件设备(定义在内核中),最后由?CPU?发送给内核, 由内核处理中断。

异常包括?Fault?、Trap 和?Abort,分别对应出错、陷入和编程异常。出错保存的?EIP 指向?触发异常的那条指令,也就是说当从异常返回时, 出错会重新执行那条指令,如缺页异常就?是是一种出错,?所以当缺页异常处理完成之后,还会去尝试重新执行那条触发异常的指令;??陷入保存的?EIP 指向触发异常的那条指令的下一条指令,陷入不会重新执行因为异常的指令;?可编程中断可由编程者用 int ?指令来触发,和陷入类似,从此类异常返回时也是返回到触发?异常的下一条指令。

中断和异常的相同点在于: 最后都是由?CPU?发送给内核,?由内核去处理;处理程序的流?程设计上是相似的。两者的不同点在于:?产生源不相同, 异常是由?CPU 产生的,?而中断是由?硬件设备产生的; 中断是异步的,这意味着中断可能随时到来; 而异常是?CPU?产生的, 所以是时钟同步的; 当处理中断时, 处于中断上下文中;处理异常时, 处于进程上下文中。?

2. ??8259A?的工作原理是怎样的?怎么给这些中断号的处理向量初始化值?

8259A?的结构如下图所示, 它的功能是根据优先级在同时发生的中断设备中选择应该处?理的请求,并通过对其寄存器的设置来屏蔽或打开相应中断。

通过初始化编程向?8259A?写入相应的初始化命令?ICW,可以使芯片处于一个规定的基本?工作方式,?并在此方式下进行工作。8259A?的初始化命令字共有?4 个?ICW1-ICW4,进行初始?化时要求 ICW1-ICW4 ?按如下图所示的顺序写入。其中,?ICW1?触发模式,选择中断向量种?类,选择?8259A 架构;ICW2?决定对应哪个中断向量;ICW3?决定了传进哪个外设中断;?ICW4?正常为?01h。

当?8259A?开始工作时,一个外部中断请求信号会首先通过中断请求线?IRQ?传输到?IMR (中断屏蔽寄存器),IMR 根据所设定的?OCW1,决定是将其丢弃还是接受。使用?OCW?的两?种情况,一种是用于屏蔽或打开外部中断,另一种发送?EOI 给?8259A 通知它中断处理结束,?这里使用的是前者。

如果可以接受,则?8259A 将?IRR(中断请求暂存寄存器)中代表此?IRQ?的位置?1,以表?示此?IRQ 有中断请求信号,并同时向?CPU?的?INTR(中断请求)管脚发送一个信号,在等待?CPU?转到中断服务的过程中可能有其余的?IRQ?线送来中断请求,这些请求都会接受?IMR?的?挑选, 如果没有被屏蔽,?那么这些请求也会被放到?IRR ?中,也即 IRR?中代表它们的?IRQ?的?相应位会被置?1。当?CPU 执行完一条指令时后, 会检查一下?INTR 管脚是否有信号,如果发?现有信号, 就会转到中断服务, 此时,CPU 会立即向?8259A?芯片的?INTA(中断应答)?管脚?发送一个信号。当芯片收到此信号后,判优部件开始工作,它在?IRR?中,挑选优先级最高的?中断, 将中断请求送到?ISR(中断服务寄存器),也即将?ISR?中代表此?IRQ?的位置位,并将?IRR?中相应位置?0,表明此中断正在接受?CPU?的处理。同时,将它的编号写入中断向量寄存?器?IVR?的低三位(IVR?是由?ICW2?所指定的)。这时,CPU?还会送来第二个?INTA?信号,当?收到此信号后, 芯片将?IVR?中的内容, 也就是此中断的中断号送上通向?CPU?的数据线。

3. ??如何建立?IDT,如何实现一个自定义的中断?

1)将?IDT 放入一个单独的段中, 定义了?IDT 所对应的中断向量的偏移。

2)定义偏移定义

上图展现的是时钟中断处理程序。其功能为在时钟中断到来时,将[gs:((80 * 0?+ 70)*2]位?置的字符的值增?1。

3)调用中断,?开中断

4. ??如何控制时钟中断,?为什么时钟中断的时候没有看到?int 指令?

控制时钟中断的方法就是在?IDT 表中的中断向量号单独写出来,对应一个中断处理的函?数,在函数里定义时钟中断的处理过程, 比如此例中就单独定义了?020h?中断和?080h?中断:

没有看到?int?的原因是我们在?289?行进行了开中断,时钟中断是外部中断,?每次中断都?会通过?IRQ?中断请求线来请求中断, 不需要?int 调用。

5. ??简要解释一下?IOPL?的作用与基本机理

(1)IOPL?的作用

保护模式通过?IOPL?和?I/O?许可位图来限制用户进程进行的?I/O?操作。 IOPL?是?I/O?保护机制的?关键之一,位于寄存器?eflags?的第?12?、13?位。指令?in?、ins?、out?、outs?、cli?、sti?只有在?CPL??<=?IOPL?时才能执行。这些指令被称为?I/O?敏感指令(I/O Sensitive?Instructions)。如果低特权?级的指令试图访问这些?I/O?敏感指令将会导致常规保护错误(#GP)。

(2)IOPL?的运行机理

I/O?位图基址是一个以?TSS?的地址为基址的偏移,?指向的便是?I/O?许可位图。之所以叫做位?图,是因为它的每一位表示一个字节的端口地址是否可用。如果某一位为?0,则表示此位对?应的端口号可用,为?1?则不可用。由于每一个任务都可以有单独的?TSS,所以每一个任务可?以有它单独的?I/O?许可位图。

以教材例子演示:

由于?I/O?许可位图开始有?12?字节内容为?0FFh,即有?12×8=96?位被置为?1,所以从端口?00h?到?5Fh?共?96?个端口地址对此任务不可用。同理,接下来的?1?字节只有第?1?位(从?0?开始数)?是?0,表示这一位对应的端口(61h)可用。如果?I/O?位图基址大于或等于?TSS?段界限,就表示没有?I/O?许可位图, 如果?CPLIOPL,则所有?I/O?指令都会引起异常。 I/O?许可位?图的使用使得即便在同一特权级下不同的任务也可以有不同的?I/O?访问权限。

文章来源:https://blog.csdn.net/weixin_49816179/article/details/135456856
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。