文章目录

  • 01、中断和硬件中断
  • 02、中断控制器简介
  • 03、中断号、中断处理过程、中断向量表
  • 04、实时时钟、CMOS RAM和BCD编码
  • 05、实时时钟芯片的中断信号
  • 06、安装0x70号中断的处理过程
  • 07、启用更新周期结束中断
  • 08、用TEST指令等待更新周期结束
  • 09、读取BCD码的时间并显示在屏幕上
  • 10、用NOT指令反转时间分隔符的颜色
  • 11、用IRET指令从中断过程返回
  • 12、用停机指令HLT使处理器进入低功耗状态
  • 13、内部中断和软中断
  • 14、BIOS中断控制概述
  • 15、用BIOS功能调用接收并显示键盘输入
  • 16、原书第9章习题

上一节:19、硬盘和显卡的访问与控制
下一节:21、32位x86处理器编程架构

01、中断和硬件中断

非屏蔽中断NMI、可屏蔽中断INTR

02、中断控制器简介

使用8259A中断控制器芯片,其有自己的端口号,可以设置中断的优先级、屏蔽某些中断信号等等,中断引脚的优先级从高到低依次为主片IR0~~IR1、从片IR0~~IR7、主片的IR3~~IR7

8259A内部有一个中断屏蔽寄存器,对应引脚输入0表示允许中断进入、1表示禁止中断进入。

除了中断屏蔽寄存器,还有处理器内部的FLAGS标志寄存器中的IF标志位:IF0表示忽略中断信号、IF1表示接收中断信号,使用CLISTI设置标志位IF

03、中断号、中断处理过程、中断向量表

默认中断号为:

中断处理过程:在实模式下,保护现场,处理器知道了中断号,使用中断号访问中断向量表,从中取出中断处理程序的逻辑段地址和偏移地址,转到那里去执行中断处理程序,执行完之后返回。

中断向量表IVT:是BIOS在开机时创建。

使用Bochs虚拟机调式:中断向量表1000个字节,512个字,从地址0开始。
设置断点:b 0x7c00
查看IVTxp /512xh 0

04、实时时钟、CMOS RAM和BCD编码

实时时钟:提供基准时间,存储在CMOS RAM芯片中。
CMOS RAM64~256字节之间,日期和时间信息占据一小部分,剩余的用来保存整机的配置信息(硬件类型、工作参数、开机密码、辅助存储设备的启动顺序等等)。

索引端口0x700x74,指定偏移地址(索引号);
数据端口0x710x75,用来读取偏移地址处的内容。

二进制形式的十进制编码(BCD:Binary Coded Decimal
左边25的十进制,右边上为纯二进制编码,右边下为BCD编码。

05、实时时钟芯片的中断信号

RTC可产生3种中断信号:

1、PF(Periodic Interrupt)
可调节,最慢500ms发生一次、最快30.517us发生一次,使用下图修改。

分频器修改:这是基于32.768KHz时的设置。

其他频率参考MC146818芯片手册。

PF中断是否允许发生由寄存器B位6控制,0为不允许、1为允许。

若寄存器A位3~0选择了0000,则寄存器B的位6自动置0

2、UI(Update-ended Interrupt)
每隔一秒,RTC将更新CMOS RAM中的时间和日期,更新操作包括读取并增加日期和时间、检查数据是否超出范围并溢出、检查是否到了闹钟时间,设置相关寄存器的状态,最后更新之后的数据写回原来的位置。

这些步骤和过程叫做更新周期,在每个更新周期结束时,若允许,RTC将发出一个中断信号表示本次周期更新结束,就叫做更新周期结束中断。

更新周期时候会进行由寄存器B的位7控制:为0表示每秒都会产生、为1表示暂停更新周期并且此后不再产生更新周期。

更新周期结束中断时候产生取决于寄存器B的位4:为0表示不产生、为1比爱是允许在每个更新周期结束时产生中断。

更新周期是否开始由寄存器A的位7决定:此位是只读的,为0表示更新周期至少在488us内不会启动,即此时访问CMOS RAM中的时间是安全的;为1表示正处于更新周期,或者更新周期马上就要启动。

如果寄存器B的位7(SET位)为0,在分频电路正确配置的情况下,更新周期每秒发生一次,更新周期至少在寄存器B的位7(UIP位)置1之后的488us内开始,而且整个周期的完成时间不会多余1984us。

在更新周期进行的时候,和日期时间有关的存储单元0x00~0x09的这一部分会和外部总线脱离,为了防止因外部数据访问导致的数据冲突和破坏;
因此要安全的访问0x00~0x09这一部分数据,要避开更新周期,有两个可以选择的时机:

  • 1、当检测到更新结束中断发生时,有999ms时间用于读取有效的日期时间和数据。
  • 2、若检测到寄存器A的位7(UIP位)是0,意味着在更新周期开始之前滑油488us的时间用于读取有效的日期时间和数据。

3、AI(Alarm Interrupt)
寄存器B的位5(AIE位)控制闹钟中断信号是否会产生:为0表示不产生、为1表示产生。

中断类型的判断:读取寄存器C相关位进行判断。

  • 位7:为1表示有中断发生、为0表示没有;
  • 位7为1时再根据位4、5、6进一步判断是哪种中断发生;
  • 位6:为0表示没发生、为1表示发生;
  • 位5:为0表示没发生、为1表示发生;
  • 位4:为0表示没发生、为1表示发生;
  • 其中低4位始终保持为0,寄存器C是只读的,读操作将会导致所有位被清零

06、安装0x70号中断的处理过程

加载器程序使用c08_mbr.asm,加载器是一样的可通用,具体代码查看c09_1.asm

当处理器执行任何一条改变栈段寄存器SS的指令时,会在下一条指令执行前禁止中断,所以修改SP的指令需要紧跟在修改SS的指令后面。

访问中断向量表:因为IVT保存在物理地址为0处,所以程序中将地址0x0000当作段地址传给ES

07、启用更新周期结束中断

此小节代码如下,具体代码查看c09_1.asm

...cli                               ;防止改动期间发生新的0x70号中断push esmov ax,0x0000mov es,axmov word [es:bx],new_int_0x70    ;偏移地址。mov word [es:bx+2],cs            ;段地址pop esmov al,0x0b                       ;RTC寄存器Bor al,0x80                      ;阻断NMI out 0x70,almov al,0x12                     ;设置寄存器B,禁止周期性中断,开放更 out 0x71,al                     ;新结束后中断,BCD码,24小时制 mov al,0x0cout 0x70,al                     ;如果不清零,相应中断将不再产生in al,0x71                      ;读RTC寄存器C,复位未决的中断状态;没有屏蔽最高位的中断允许位,因为这是;最后一次设置RTC,利用这个机会打开非屏蔽中断NMIin al,0xa1                      ;读端口0xA1(默认)读8259从片的IMR寄存器 and al,0xfe                     ;清除bit 0(此位连接RTC)out 0xa1,al                     ;写回此寄存器 sti                             ;重新开放中断
...

阻断NMI信号原理:

寄存器B的各个位介含义:

代码中设置寄存器B的值为0x12,含义参考上图即可。

其中小时模式为12小时制时,其中时所在寄存器位7位0表示上午、为1表示下午。

8259从片的IMR寄存器,来设置中断屏蔽寄存器的相应位为0已开启以开启中断。

08、用TEST指令等待更新周期结束

此小节代码如下,具体代码查看c09_1.asm

....w0:                                    mov al,0x0a       ;阻断NMI。当然,通常是不必要的or al,0x80                          out 0x70,alin al,0x71       ;读寄存器Atest al,0x80  ;测试第7位UIP jnz .w0       ;以上代码对于更新周期结束中断来说 ;是不必要的
....

判断RTC是否处于更新周期,根据寄存器A的位7判断:0表示未开始,此时访问CMOS RAM中的日期时间是安全的、1表示正处于更新周期或者更新周期马上就要启动。

使用test指令判断某一位是0还是1,test指令的and指令类似,但是test指令执行之后不保存运算结果,影响标志位ZFSFPFAF未定义,OF=CF=0

RTC更新周期时序:

09、读取BCD码的时间并显示在屏幕上

此小节代码如下,具体代码查看c09_1.asm

...mov ax,0xb800mov es,axpop axcall bcd_to_asciimov bx,12*160 + 36*2               ;从屏幕上的12行36列开始显示;一个字符占2个字节mov [es:bx],ahmov [es:bx+2],al                   ;显示两位小时数字
....

时间的时分秒分别在CMOS RAM0、2、4位上:

10、用NOT指令反转时间分隔符的颜色

此小节代码如下,具体代码查看c09_1.asm

...mov al,':'mov [es:bx+4],al     ;显示分隔符':' mov byte [es:bx+4], ':'not byte [es:bx+5]       ;反转显示属性 pop axcall bcd_to_asciimov [es:bx+6],ahmov [es:bx+8],al       ;显示两位分钟数字mov al,':'mov [es:bx+10],al     ;显示分隔符':'not byte [es:bx+11]     ;反转显示属性pop axcall bcd_to_asciimov [es:bx+12],ahmov [es:bx+14],al      ;显示两位小时数字
...

not指令:这里程序运行时这个冒号(':')将会一秒改变一次。

11、用IRET指令从中断过程返回

此小节代码如下,具体代码查看c09_1.asm

...mov al,0x20       ;中断结束命令EOI(end of interrupt)out 0xa0,al     ;向从片发送 out 0x20,al      ;向主片发送 pop espop dxpop cxpop bxpop axiret
...

中断服务寄存器ISR:位为1表示正在响应对应的中断,一旦响应了该中断,8259A中断控制器芯片无法知道该中断何时结束,若不清除相应位,则下一次从该引脚来的中断将会得不到处理。

中断从主片来的则EOI指令只需要发给主片,要是从片来的则EOI指令。片和从片都需要发送。

IRET指令从中断处理程序返回。

12、用停机指令HLT使处理器进入低功耗状态

此小节代码如下,具体代码查看c09_1.asm
执行剩余程序:

...mov bx,done_msg                    ;显示安装完成信息 call put_stringmov bx,tips_msg                    ;显示提示信息call put_stringmov cx,0xb800mov ds,cxmov byte [12*160 + 33*2],'@'       ;屏幕第12行,35列.idle:hlt     ;使CPU进入低功耗状态,直到用中断唤醒not byte [12*160 + 33*2+1]         ;反转显示属性 jmp .idle
...

在虚拟机中运行:冒号一秒翻转一次、@为处理器停机之后被中断唤醒一次翻转一次

Virtual Box虚拟机设置:

Bochs虚拟机设置:

13、内部中断和软中断

内部中断:在处理执行指令时发生了错误或者故障引起的。

  • 比如除法指令除数为0、除法的结果溢出时产生0号中断(除法错中断)。
  • 比如遇到非法指令(指令的操作码未定义,或者指令超过了规定的长度)时产生6号中断。操作码未定义表示无法译码或执行。
  • 内部中断不受标志寄存器FLAGS的中断标志位IF的影响,处理器转到内一个中断的中断号,可以直接转到对应中断处理程序执行。

软中断:使用指令产生中断

int3:断点中断指令,供调试器使用故意设置的陷阱,又叫做陷阱终端,机器码是16进制的CC

调时程序可以单步执行指令,也允许设置断点,当程序执行到断电时停下,此时可以方便查看寄存器等内容。

断点就是某一条指令的起始地址,比如断点选在xor di,di,机器码是31FF处,当我们设置断点是,调试器将此条指令的机器码改为CC

当处理器执行到此条指令时,发现是机器码是CC即断点指令int3,从而转去执行断点中断处理程序,进入中断前依次压入标志寄存器FLAGSCSIP

中断处理程序是调试期提供的,任务是将断点处的处理器状态保存起来,包括标志寄存器、段寄存器以及通用寄存器的数值。同时中断处理过程会提供一个交互的界面,允许使用调试命令查看断点前的及机器状态。

在调试过程中接到继续执行的命令时,将恢复进入中断前指令的机器码,即将CC改回为31,然后修改栈中的返回地址,让此地址指向原来的那条指令即31FF

最后中断处理过程指向中断返回指令iret,重新返回到被中断的那一条指令继续向下执行。

注意:int3 != int 3

溢出中断指令into

处理器执行这条into指令时,若标志寄存器中的溢出标志OF为1,产生4号中断,否则不做任何操作。

14、BIOS中断控制概述

外部硬件中断是否能够被处理:

  • 要看中断控制器8259A是否允许中断信号到达处理器;
  • 即使中断信号到达处理器还要看标志寄存器中的中断标志位IF的状态;
  • 处理器响应中断的过程,包括向8259A发送中断响应信号;
  • 然后要求8259A芯片送来一个中断号。

内部中断、软中断不受IF位的影响。
处理器最主要的就是根据中断号找到中断处理过程,并执行这个过程。

8086系统中断可处理256种中断:
内部中断2%、外部硬件中断主要通过NMI引脚和8259A中断控制器芯片提供,占比7%,剩余的部分可由软件系统使用,占比91%

过程调用时,call指令必须指定目标位置的相对偏移量或绝对地址,在一个程序内部很方便,可以之间call 标号即可;

但是要想调用别人的代码,比如操作系统的功能,call指令就很麻烦。比如读取硬盘上的文件,因为操作系统有这样的功能,就不必自己造轮子,直接调用操作系统例程即可。但是操作系统不会给出例程的段地址和偏移地址,因为操作系统也是经常修改或者每次启动之后段地址和偏移地址都是变化的,导致例程的入口地址跟着变化。

因为有了软中断,操作系统可以使用软中断提供各种服务,每次操作系统加载完之后,将其提供的每一种服务功能做成中断处理过程,并指定以恶中断号,将服务例程地址填入中断向量表IVT中。这样程序即可使用软中断调用操作系统提供的例程了,不需要知道具体的地址,只需要一个中断号即可。

BIOS(中断功能)调用,在加载执行主引导扇区程序之前已经可以使用。BIOS提供了很多硬件服务,按照类型划分,比如键盘输入、磁盘读写、文本和图形的显示服务。每一种服务都有一个中断号,键盘服务使用的中断号为0x16,每一种服务又区分了很多功能,为了区分不同的功能,在发出软中断之前,使用ah来指定功能号。如下:

 mov ah, 0   ;0号功能表示从键盘读取字符存入寄存器AL中int 0x16  ;键盘服务;当中断服务例程返回之后,会监视键盘动作;将读取的按键字符ASCII编码存入寄存器AL中

功能号可参考配套资料中的BIOS功能调用表。

BIOS功能调用是在BIOS执行期间安装的,当主引导程序开始执行时即可使用,BIOS是如何建立起这一套功能调用的呢?又是如何知道访问硬件的呢?起始BIOS并不知道,很多功能调用并不是BIOS提供的,而是由我们访问的硬件自己提供的,是由外部设备接口自己建立的。

在上图中,右侧是一些外部设备接口,入板卡、显卡、硬盘控制器等等,这些接口都有自己的ROM,这些ROM中提供了自己的功能调用例程,以及本设备的初始化代码。按照规范,在这些ROM中前两个单元为55AA两个字节,第三个单元是长度(以512字节为单位的长度),从第4个单元一直响向后就是实际的功能调用例程的代码。

每一个外部设备的ROM都映射到内存地址0xC0000~~0xE0000中,如果设备存在则映射到分配给他的内存范围内。计算机启动期间会执行BIOSBIOS程序会以2K字节为单位搜索区域:0xC0000~~0xE0000,即搜索的是外部设备的ROM。若发现某个ROM的前两个字节为55AA,则表示此外社存在,BIOS会从相应的单元进入,执行设备的ROM代码。设备的ROM代码用来初始化设备本身并提供功能调用,将自己的功能调用地址填写到中断向量表中。各自填写完成之后返回到ROM BIOS,接着再搜索,再返回,直到所有的ROM都初始化完成,包括中断向量表建立完成。之后再加载执行主引导扇区程序,ROM BIOS就是这样的过程。

15、用BIOS功能调用接收并显示键盘输入

具体代码参考c09_2.asmc08_mbr.asm

显示字符使用BIOS0x10中断,0x0E号功能从键盘读取字符:


使用BIOS0x16中断,0x00号功能从键盘读取字符:

16、原书第9章习题


9.2题解:

  • 设置断点:b 0x7c00
  • c命令持续执行到断点处,中断向量表就初始化完成
  • xp /100xh 0显示位于0地址处的中断向量表
  • xp /2xh 0x70*4,每一个中断4占据个字节,即乘以4;即可显示0x70处的偏移地址(低位)和段地址(高位)。


    上一节:19、硬盘和显卡的访问与控制
    下一节:21、32位x86处理器编程架构

20、中断和动态时钟显示相关推荐

  1. 第9章 中断和动态时钟显示

    本章的第一个代码功能是在屏幕中间实时显示时间,其实现的思想是:cpu停机--->时间每秒更新一次,每一次更新都会引起0x70中断(0x70中断的内容已经被我们更改为显示当前时间)--->中 ...

  2. X86汇编语言从实模式到保护模式08:中断和动态时钟显示

    目录 1. 外部硬件中断 1.1 概述 1.2 外部硬件中断分类 1.2.1 概述 1.2.2 不可屏蔽中断 1.2.3 可屏蔽中断 1.3 中断控制器 1.3.1 引入中断控制器的原因 1.3.2 ...

  3. JavaScript实现动态时钟显示

    目录 动态时钟显示效果 代码实现 1.创建html文件(时钟显示.html) 2.设置html标签 3.设置html标签的CSS样式 4.设置JavaScript 1)创建函数和Date 2)获取da ...

  4. Html5的Canva绘制动态时钟显示当前时间!!!(附源码)

    前言 canvas设计一个显示当前时间的时钟 实现情况 思路 想让canvas绘制的东西动起来,最直接的办法就是不停的进行重绘,可能刚开始有些人会担心效率的问题,害怕代码过长冗余,可读性差的问题,实际 ...

  5. 蓝桥杯51单片机之数码管从点亮到动态时钟的实现【单片机开发初学者必掌握】

    文章目录 一.点亮数码管 二.八位数码管同时从0到F 三.显示学号(指定数字) 四.中断机制的引入 五.利用中断实现动态时钟 一.点亮数码管 首先看一下案例源码: #include <reg52 ...

  6. python数码管动态时钟壁纸_8个动态数码管时钟显示

    8 个动态数码管时钟显示 #include #define uint unsigned int #define uchar unsigned char uchar i,temp,aa,miao,fen ...

  7. .NET实时2D渲染入门·动态时钟

    前言 说来这是个我和我老婆的爱情故事. 从小以来"坦克大战"."魂斗罗"等游戏总令我魂牵梦绕.这些游戏的基础就是 2D实时渲染,以前没意识,直到后来找到了 Di ...

  8. canvas简单实现动态时钟

    使用到的知识: 1.     获取系统时间 2.     画图形,空心图形,实心图形,以及一些属性 3.     for循环 准备工作:添加一块画布1000*1000(随意),引用canvas.js ...

  9. 小案例:基于python的动态时钟,带十二时辰和经络养身

    一.前言 1.仅用来研究学习使用. 2.除正常显示时钟外,还可以实时显示当前对应的时辰,和经络养身提示. 3.适合辅助上班族来养生 二.效果如下: 三.源码如下: ''' 动态时钟附带十二时辰显示 ' ...

最新文章

  1. Nature综述——真菌的多样性:真菌的高通量测序及鉴定
  2. 爱了!安利一个相见恨晚的可视化学习网站
  3. Java解析HTML
  4. 【图像处理】——图像质量评价指标信噪比(PSNR)和结构相似性(SSIM)(含原理和Python代码)
  5. (12)python 的列表我从没想过会那么好用
  6. 设计模式笔记(15)---命令模式(行为型)
  7. nagios 飞信(fetion) 短信报警
  8. Luogu4114 Qtree1
  9. 阿里大于短信返回XML
  10. c语言 虚拟示波器软件下载,虚拟示波器
  11. Python 如何检测敏感词汇
  12. iOS 性能优化之列表流畅度优化
  13. “指付通”还是“支付痛”?-【软件和信息服务】2014.10
  14. (此文精辟)[汇编学习]献给汇编初学者-函数调用堆栈变化分析(转自黑客风云)
  15. 为什么走线选择50欧姆阻抗
  16. kubeadm安装的k8s集群证书有效期过期解决方案
  17. c#MVC文件(图片,word,excel,zip等)批量上传
  18. 《中国图书馆图书分类法》(第五版)详表(中图分类号查询表)
  19. 希捷 sshd 微型计算机,希捷2TB SSHD拆解/核心技术分析_希捷 Desktop 2TB 7200转 8GB混合硬盘_内存硬盘-中关村在线...
  20. JS - 自由变量与作用域链

热门文章

  1. Tomcat输出框乱码(鏈嶅姟鍣ㄥ湪[463]姣鍐呭垵濮嬪寲)
  2. jQuery菜鸟教程04
  3. 2021年量子计算机奖,2021美国科学天才奖出炉:高中生瓜分180万奖金
  4. 7-32 哥尼斯堡的“七桥问题” (25 分)(思路+详解+题目分析)两种做法任选其一
  5. 软件集成测试采用,集成测试的组成以及流程
  6. Monte-Carlo算法(基本原理,理论基础,应用实践)
  7. 如何画出美丽漂亮的三维立体图——Mathematica的快速上手
  8. 下载安装了zotero,为什么word没显示zotero的加载项
  9. python函数快查快用
  10. Java实现等额本金