目录
1. 外部硬件中断
1.1 概述
① 中断就是打断处理器当前的执行流程,去执行另外一些和当前工作不相干的指令,执行完成后,还可以返回到原来的程序流程继续执行
② 外部硬件中断提出的背景是外设比处理器慢很多,因此当一个程序需要等待外设的输入输出时,处理器可以先切换执行其他程序,当外设就位时,通过中断通知处理器
1.2 外部硬件中断分类
1.2.1 概述
① 外部硬件中断通过两个信号线进入处理器内部,分别为不可屏蔽中断NMI(Non Maskable Interrupt)和可屏蔽中断INTR
② 来自外部设备的中断很多,通过NMI和INTR两个信号线,可以区分两种不同性质的中断
③ 每种类型的中断都被统一编号,称作中断类型号、中断向量或者中断号,处理器据此采取适当的处理措施
1.2.2 不可屏蔽中断
① 关系到整个系统的安全性,在任何时刻都必须及时处理。比如内存访问电路发现校验错误,这意味着从内存读取的数据是错误的,后续运行的正确性已无法保障
③ 产生不可屏蔽中断的中断源一般通过与非门连接到NMI引脚,一旦有一个中断源生效,则可以触发处理器的NMI中断
1.2.3 可屏蔽中断
② 产生可屏蔽中断的中断源数量很多,一般通过中断控制器进行管理
1.3 中断控制器
1.3.1 引入中断控制器的原因
① 由于外部中断数量很多,不可能为每个中断源都提供一个到处理器的引脚。因此需要一个代理,来接受外部设备发出的中断信号
② 多个设备同时发出中断的概率也很高,因此该代理的任务还包括对他们进行仲裁,决定让哪一个中断源优先向处理器提出服务请求
1.3.2 8259A中断控制器
① Intel处理器允许256个中断,中断号范围为0 ~ 255
② 通过级联两片8259A,负责提供其中的15个,但中断号并不固定,而是允许软件根据自己的需要灵活设置中断号,以防止发生冲突
③ 中断控制器芯片有自己的端口号,可以使用in & out指令实现控制,其中就包括对各引脚中断号的设置
④ 对8259A中断号的设置,只能以芯片为单位,即只能设置IR0的中断号,之后依序增加。BIOS设置的默认中断号如下图所示,其中后文要使用的RTC中断号为0x70
说明1:由于可以通过软件控制8259A芯片,因此他又被称作可编程中断控制器(Programmable Interrupt Controller,PIC)
① 默认情况下,中断优先级和引脚相关,主片的IR0引脚优先级最高,IR7最低,从片也是如此。当然,需要注意从片是级联在主片的IR2引脚上的
① 在计算机内部,中断发生得非常频繁,当一个中断正在处理时,其他中断也会陆续到来。8259A芯片会记住他们,并按一定的策略决定先为谁服务
② 当一个中断事件正在处理时,如果来了一个优先级更高的中断,允许暂时中止当前的中断处理,先为优先级更高的中断服务,这称为中断嵌套
① 当中断发生时,如果从外部硬件到处理器之间的道路是畅通的,处理器在执行完当前指令后,会立即着手为硬件服务
② 处理器会首先响应中断(ACK),告诉8259A芯片准备着手处理该中断。接着,处理器会要求8259A芯片将中断号发送过来
1.4 如何屏蔽中断
1.4.1 中断控制器级屏蔽
① 在8259A芯片内部,有中断屏蔽寄存器(Interrupt Mask Register,IMR)
② IMR为8位,对应8个中断输入引脚,用于决定从该引脚来的中断信号是否能通过8259送往处理器
1.4.2 处理器级屏蔽
② 当中断寄存器中的中断标志位IF为0时,所有从INTR引脚进入的中断信号均被忽略掉;当中断标志位IF为1时,处理器可以接收和响应中断
1.5 实模式中断向量表
① 所谓中断处理,归根结底是要处理器执行一段与该中断有关的指令,称为中断处理程序
② 在实模式下,处理器将所有中断处理程序的入口点集中存放在内存中从物理地址0x00000开始,到0x003FF结束,共1KB的空间内,称为中断向量表(Interrupt Vector Table,IVT)
③ 每个中断在中断向量表中占2个字,分别是中断处理程序的偏移地址(低字)和段地址(高字)
④ 由于中断向量按顺序存放,所以通过中断号可以索引到对应的中断向量(将中断号 * 4)
① 在8086中,只有实模式,中断向量表的位置固定从物理地址0x00000开始
② 在80386中,引入了idtr寄存器,用于记录中断向量表 & 中断描述符表的起始地址,在实模式下,将其设置为从物理地址0x00000开始,这也实现了与8086的兼容
由于实模式下的中断向量表是BIOS设置的,因此需要在BIOS运行完成后查看中断向量表区域,我们在运行进入MBR时进行观察
① 很多中断的处理方式相同,所以中断处理程序的入口地址是相同的
② xp命令中的h,是以半字显示。由于80386是32位处理器,所以字为4B,半字为2B
③ 操作系统和用户程序可以根据自己的需要,修改中断向量表中的入口地址,使他指向自己的代码
1.6 中断处理过程
1.6.1 保护断点现场
① 将标志寄存器FLAGS压栈,然后清除标志寄存器的IF位和TF位
1.6.2 执行中断处理程序
① 处理器将拿到的中断号乘以4,得到该中断向量在中断向量表中的偏移地址
② 从中断向量表中依次取出中断处理程序的偏移地址和段地址,并分别传送到IP & CS,从来开始执行中断处理程序
1.6.3 返回断点继续执行
① 所有中断处理程序的最后一条指令必须是中断返回指令iret(interrupt return)
② iret指令将导致处理器依次从栈中弹出IP、CS和FLAGS的原始内容,于是返回断点继续执行
进入中断时,处理器将IF标志位清除,因此在中断处理过程中,处理器将不再响应可屏蔽中断。如果希望更高优先级的中断嵌套,可以在编写中断处理程序时,适时用sti指令打开中断
TF标志位为跟踪标志位,用于标识处理器是否允许单步中断,以进行程序调试。当TF = 0时,处理器处于正常状态;当TF = 1时,处理器处于单步状态,每执行一条指令就自动产生一次单步中断,处理器的debug功能依赖单步调试功能
这也是为什么进入中断后,必须将TF标志清除的原因。因为单步中断处理程序也是一系列指令,如果不清除TF标志,在执行中断处理程序的指令时又会触发单步中断,从而导致CPU永远执行单步中断处理程序的第1条指令
iret指令的本质是将当前栈中的3个元素按序弹出到IP、CS和FLAGS,因此中断处理程序需要在执行前后保持栈平衡,否则中断无法正确返回
NMI中断发生时,处理器不会从外部获得中断号,而是自动生成中断号2,其他处理过程与可屏蔽中断相同
2. RTC中断布署实例
2.1 RTC概述
① 在外围设备控制芯片ICH内部,集成了实时时钟电路(Real Time Clock,RTC)和两小块由CMOS材料制成的静态存储器(CMOS RAM)
② 实时时钟电路负责计时,而日期和时间的数值存储在CMOS RAM中
③ 由于使用主板上的电池供电,即使关闭计算机,RTC仍可计时。RTC为整台计算机提供一个基准时间,为所有需要时间的软件和硬件服务
④ 除了日期和时间的保存功能外,RTC芯片还可以提供闹钟和周期性中断的功能
⑤ RTC芯片由一个振荡频率为32.768KHz的晶振驱动,经过分频后,供RTC使用
2.2 CMOS RAM
2.2.1 CMOS RAM中的信息
① CMOS RAM通常有64 / 128 / 256B,其中日期和时间仅占用了很小一部分容量。如上图所示,CMOS RAM中前10B为日期和时间,之后为4个RTC功能寄存器
② CMOS RAM的其他空间中保存了整机的配置信息,比如各种硬件的类型和工作参数、开机密码和辅助存储设备的启动顺序等
2.2.2 如何访问CMOS RAM
① 0x70或0x74为索引端口,用来指定CMOS RAM内的单元
; 示例:读取日期
; 日期位于CMOS RAM中的0x07处
mov al, 0x07
out 0x70, al
in al, 0x71
说明:端口0x70的bit 7可用于屏蔽NMI中断(历史遗留用法)
2.3 RTC控制寄存器说明
2.3.1 寄存器A
2.3.2 寄存器B
② 更新周期结束中断(当寄存器B的SET为0且分频电路正确配置的情况下,每秒发生一次)
说明2:如果寄存器A的bit[3:0]为置为0b000,则PIE被自动置为0,即不允许中断
2.3.3 寄存器C(只读)
RTC电路可以产生3种中断,但是RTC到CPU的中断线只有一根,因此当CPU被触发RTC中断时,可以通过读取寄存器C来区分子中断源
说明2:寄存器C中的中断标志位均为读清,如果在RTC中断发生后不读取该寄存器清除中断标志,RTC看到中断未被处理,将不再产生中断信号
2.3.4 寄存器D
2.4 安装0x70号中断过程
2.4.1 设置段寄存器
如上一章笔记所述,从加载器跳转到用户程序之后,CS已经更新指向用户程序的代码段,因此此处只需要设置SS & DS
由于栈的设置涉及SS & SP两个寄存器,因此当Intel处理器执行任何一条改变栈段寄存器SS的指令时,会在下一条指令执行完成期间禁止中断,以避免栈设置过程被打断
因此在代码中,应该在修改段寄存器SS的指令之后,紧接着一条修改栈指针SP的指令
2.4.2 修改0x70中断向量
在实模式下,每个中断向量占用4B,其中低2B为中断处理程序偏移地址,高2B为中断处理程序段地址,且中断号从0开始。因此0x70 * 4,即可得到RTC中断在中断向量表中的offset
2.4.3 RTC & 中断控制器设置
需要在中断源、中断控制器、处理器这3个阶段分别使能中断,才能使得相应中断被响应
2.4.4 使处理器进入低功耗状态
hlt指令使处理器停止执行指令,并处于停机状态,这将降低处理器的功耗。处于停机状态的处理器可以被外部中断唤醒并恢复执行,而且会继续执行hlt后面的指令
此处使用not指令反转@字符的显示属性,用于观察中断触发的频率。其中,not指令格式如下,
not r/m
2.5 RTC中断处理程序分析
2.5.1 保护中断现场
2.5.2 读取RTC时间
将读取到的RTC时间值压栈保存,压栈时为秒分时,后续出站时正好是时分秒
test r/m, r/imm
test指令将两个操作数相与,并根据结果设置标志寄存器,但是运算结果被丢弃,不改变两个操作数的内容
2.5.3 读清中断标志
2.5.4 显示RTC时间
说明1:此处反转冒号字符的显示属性,是用于观察更新结束中断是否每秒发生一次
2.5.5 向8259发送EOI
当8259中断引脚上有一个或多个中断请求信号到来时,中断请求寄存器IRR中相应的比特位被置位
此时如果中断屏蔽寄存器IMR中对应的位被置位,则该中断被屏蔽,不会被送到优先级解析器中;如果中断没有被IMR屏蔽,则被送入中断优先级解析器
中断优先级解析器根据设置的规则选择优先级最高的中断请求,送往CPU
CPU会在执行完当前的一条指令后,向8259发送一个INTA(Interrupt Acknowledge)信号来响应中断
8259在接收到这个响应信号之后,就会将所选的最高优先级中断请求保存在正在服务寄存器ISR中
与此同时,中断请求寄存器IRR中的对应比特位被清除,表示该中断请求开始被处理
CPU向8259发送第2个INTA信号,用于通知8259送出中断号。在该脉冲信号期间,8259会将一个代表中断号的8位数据送到数据总线上供CPU读取
如果8259被设置为自动结束中断(AEOI,Automatic End Of Interrupt)方式,那么在第2个INTA信号的结尾处,正在服务寄存器ISR中的对应比特位将被清除
如果8259使用非自动结束方式,那么在中断服务程序结束时,程序需要向8259发送一个结束中断(EOI)命令以恢复ISR中的比特位。如果中断请求来自级联的8259从片,那么就需要向2个8259都发送EOI命令
此后,8259就会去判断下一个最高优先级的中断,并重复上述过程
https://blog.csdn.net/longintchar/article/details/79439466
2.5.6 中断返回
恢复中断现场,并使用iret指令恢复CS & IP,使执行流回到程序断点处
2.6 上机验证
在VirtualBox虚拟机上运行时,也需要做相应设置,时间值才能正确
从运行结果看,@字符的闪烁速度远快于冒号字符,说明把处理器从停机状态唤醒的不只是RTC的更新结束中断,还有其他中断
3. 内部中断与软中断
3.1 内部中断
3.1.1 内部中断含义
3.1.2 内部中断示例
① 当检测到div除数为0时,或者触发结果溢出时,将产生0号中断
3.1.3 内部中断特性
内部中断不受IF标志位影响,也不需要中断识别总线周期,他们是中断类型固定的,可以立即转入相应的处理过程
3.2 软中断
软中断是由int指令引起的中断处理,这类中断也不需要中断识别总线周期,中断号在指令中给出。int指令格式如下,
int3 ;断点中断指令,机器码为0xCC
int imm8 ;中断号范围为0 ~ 255
into ; 溢出中断指令
int3指令一般用于断点调试,所谓断点就是某条指令的起始地址。使用int3指令实现调试的步骤如下,
① 当需要设置断点时,将断点处指定的第1个字节改为0xCC,并保存原字节
② 当处理器执行到int3时,即发生3号中断,转去执行中断处理程序。我们可以在中断处理程序中,先将所有相关寄存器和内存单元压栈,之后就可以分别取出予以显示,他们就是中断前的现场内容
③ 恢复断点处指令的第1个字节,并恢复栈,最后调用iret指令返回
当处理器执行这条指令时,如果OF标志为1,则产生4号中断;否则,这条指令什么都不做
3.3 BIOS中断
3.3.1 使用中断提供服务的好处
① 如果以过程的形式提供服务,那么无论使用jmp指令还是call指令,都需要知道过程所在的段地址和偏移地址。但是操作系统提供的功能以及自身的部署是变动的,因此无法确保服务的位置不变
② 使用中断提供服务,则不需要知道目标程序的入口地址。每次操作系统加载完成后,部署好中断向量,用户即可使用相关服务
3.3.2 BIOS中断的部署
BIOS中断是软中断的一种,之所以称为BIOS中断,是因为这些中断是在计算机上电之后,由BIOS程序建立的。也就是说,这些中断功能在加载和执行主引导扇区之前就已经可以使用了
系统BIOS本身会为一些简单的外设提供初始化代码和功能调用代码,并填写中断向量表
有些外设接口卡(e.g. 网卡、显卡)都有自己的ROM,类似于BIOS,这些ROM中提供了他自己的功能调用例程,以及本设备的初始化代码。按照规范,布局如下,
外设接口卡的ROM被映射到地址空间中,在计算机启动期间,系统BIOS会以2KB为单位搜索内存地址0xC0000 ~ 0xE0000的区域,当发现某个区域以0x55AA开头时,就表示该区域包含有效的ROM代码
之后对该区域做累加和检查,看结果是否和第3个单元相符,如果相符,就从第4个单元进入执行。此时处理器执行的是硬件自带的程序指令,这些执行初始化外部设备的相关寄存器和工作状态,并填写相关的中断向量表,使他们指向自带的中断处理程序
3.3.3 BIOS中断使用示例
http://www.ablmcc.edu.hk/~scy/CIT/8086_bios_and_dos_interrupts.htm
说明:课程源码中,最后调用int 0x10/0x0e中断时设置BL寄存器是没有必要的,因为可以设置显示属性的中断是int 0x10/0x09