当前位置: 首页 > news >正文

上下文保存 中断_IA-32的中断和异常处理

在os的内容中,我们很多次说到中断和异常,不过都没有详细的介绍,这里会有一个详细的介绍。

1.什么是中断和异常(INTERRUPT AND EXCEPTION),它们在什么场景下产生?

你在图书馆看书,突然一个电话来了,说你家狗丢了,那么你肯定要去找狗。可能你很快找到了,回去继续看书,也有可能没有那么容易找到,你就不回去看书了。这个比如对应到计算机中,你是处理器,你家狗丢了这个通知就是中断和异常的信号,你去找狗就是中断和异常的处理。你回去继续看书,就是中断和异常处理完成后继续执行之前的任务,不能回去看书,就是一些中断和异常会导致用户程序被os kill。

每种类型的中断和异常,我们都会进行编号,称为vector number。处理器支持从0到255的编号,最多256种情况。其中前32个是cpu自己用的,剩下的交给开发者。下面的表6-1显示对应编号的具体中断和异常类型:

b60fcb396c7df1e8294d67c4b440bea3.png

5b849c223b157d70dd4d806c93e6c8c4.png

那么在计算机中,中断和异常在哪些情况下会产生呢?

1.中断:

1.外部的硬件产生(比如有一个网络I/O来了)。cpu有对应的引脚来接受中断信息,分别为INTR和NMI。从INTR通知的中断信号是可以屏蔽的,通过EFLAGS中的IF标志来控制。NMI的中断必须处理,并且NMI对应的中断号默认是2.

2.程序自己通过调用INT指令产生。比如INT 35 就表示强制执行35号中断的处理程序。

2.异常

处理器的异常有以下三个来源:

1.指令执行的时候产生的错误。对于每种错误处理器都会有相应的编号。异常通常被分为这三种不同的类型:faults,traps和aborts

2.使用INTO, INT 3, 和 BOUND命令产生。不过使用INT n指令来产生指令是有限制的。如果INT n指令指定的vertor number是处理器定义的异常。这种情况如果是硬件正常产生通常是会有错误代码的,但是如果是指令产生这种异常,处理器在处理的时候是不会将错误代码进行压栈的。这样在进行异常处理的时候,异常处理程序仍然会去对错误代码进行出栈操作,因为没有错误代码,所以pop的时候就会将eip设置为错误数据,这样返回的时候执行点就不是之前的了。

3.机器检查的异常。P6和Pentium系列的处理器提供了内部和外部的机器检查机制来检查内部芯片硬件的执行和总线事务。如果这种检查发现了错误,那么处理器会发起一个vector 18的机器检查异常并且返回一个错误代码。

上面说到异常会被分为faults,traps,aborts.这是根据这些异常产生的方式和异常处理后重新开始执行指令的地点来分类的。

  • Faults — 一个fault异常通常是可以修复的,并且如果被修复了,那么程序可以重新得到执行从而不受影响。对于fault,执行完异常对应的处理程序后,返回地址是产生fault的指令。
  • Traps — 一个trap异常是在运行一个trapping指令的时候立刻产生的。对应的返回地址是trapping指令后的那条指令。
  • Aborts—这种异常产生的时候一般是不会有详细的错误指令地址的,并且程序也不会得到重新执行,可以理解为发生了一个无法挽回的错误。

不可屏蔽的中断NMI (NONMASKABLE INTERRUPT)
NMI可以通过下面2种方式产生:

  • 外部的硬件通过NMI引脚产生
  • 处理器在系统总线上收到相应的NMI消息

不管是这2种中的哪一种,处理器都会立刻调用NMI中断对应的中断处理程序。并且在处理程序执行期间保证没有其他的中断产生,包括NMI中断。当然,这2种方式产生的NMI中断不会被EFLAGS中的IF标志位屏蔽。

还有一种方式,也就是通过INTR引脚产生可屏蔽中断,不过中断的vector number是2。这种模拟的方式并不是真正的NIM中断,所以在进行相应处理的时候,处理器对应的专门用来支持NMI中断的硬件并不会工作,
当NMI中断在处理的过程中,处理器会阻塞其他的NMI中断直到中断处理程序的iret调用完成(也就是说中断处理程序已经执行完成了)。所以可以看出NMI中断处理程序是不允许嵌套执行的。另外,如果iret指令执行的时候产生了一个错误,是不会影响NMI中断被打开的。

EFLAGS中的IF标记位可以用来开启或者屏蔽INTR引脚的中断,不过不会影响NMI中断的接受,处理器产生的异常也不会受到影响。可以分别使用STI(set interrupt-enable flag )和CLI (clear interrupt-enable flag) 来设置和清除IF标志位。下面的三种情况也会对IF标志位产生影响。

  • PUSHF指令会将EFLAGS中的内容保存到栈中,POPF会对应的将栈中的数据加载到EFLAGS中,这也许会改变IF的值。
  • 任务切换的时候,POPF和IRET会被调用,所以IF指令也许会被修改
  • 当一个中断处理程序是使用中断gate调用的时候,IF是自动被清除的,所以可屏蔽中断就都会被屏蔽了。

当我们在切换栈的时候,可能会使用如下的2个指令来完成操作:

MOV SS, AX
MOV ESP, StackTop

但是问题在于,如果第一条指令执行完成后,发生了中断或者异常,那么在中断或者异常的处理程序执行的过程中,对应的栈的地址空间就是异常的了。为了解决这个问题,处理器在修改ss寄存器的命令后禁止中断,debug异常,single-step trap ,直到下一条指令执行完毕。当然如果使用LSS命令来修改SS寄存器的值就不会出现这个问题了。

中断和异常的优先级
如果有多个中断或者异常被挂起,处理器会按照一个先后顺序来进行处理。下面的表6-2给出了各种异常和中断的优先级。

0d7b34b9c7f9f81d632ed5b6b3511976.png

上面表中的分类等级在各个架构中都是统一的,不过在各个分类中不同的中断或者异常的优先级各个架构就会不一样了。处理器会首先处理最高等级的异常或者中断。低等级别的异常会被丢掉,低等级别的中断会被挂起。当中断处理程序返回到程序或者任务产生异常或者中断的地方,被丢掉的异常会再次产生,中断描述符表IDT( INTERRUPT DESCRIPTOR TABLE )

接收到中断后,处理器应该怎么处理呢?首先每种类型的中断和异常对应的处理程序可以在IDT中找到。和GDT和LDT类型,IDT也是一个数组,其中的元素就是8byte大小的门描述符(gate descriptor)。你可以把IDT放在任何位置,然后将对应的线性地址基地址记载IDTR寄存器中就可以了,下面的图6-1展示了2者的关系和应用。

IDT中包含3中类型的门描述符:

1.任务门描述符 Task-gate descriptor

2.中断门描述符 Interrupt-gate descriptor

3.陷阱门描述符 Trap-gate descriptor

下面的图6-2显示了各种描述符的内容格式:

0f86d7d21f067c684956c4d5cff945c4.png

下面我们来看下具体的中断和异常处理的过程。

处理器对异常和中断处理程序的调用,类似于使用CALL指令调用一个过程或者任务一样。首先根据中断或者异常编号在IDT中找到对应的描述符。如果是trap-gate 或者Interrupt-gate,那么就类似于使用CALL命令调用一个过程。如果是task-gate,则会进行上下文切换,执行task-gate对应的任务,类似于CALL调用一个task gate。图6-3显示了这个过程:

3f7afd0bacb921407aefc77f040d755d.png

如果中断和异常处理过程的权限和目前代码的权限不同:

1.从当前任务的TSS中获取相应权限的栈信息,在新的栈上,处理器将被中断的过程的段选择子和栈指针信息入栈

2.处理器将当前过程的EFLAGS, CS, 和 EIP 寄存器的值入栈
3.如果有错误代码,那么也入栈

如果相同:

1.将EFLAGS, CS, 和 EIP 寄存器的值入栈

2.如果有错误代码也入栈

下面的图6-4显示了这2种不同情况:

3dbaa9d3edfde2b1dc27bb597a9d49ae.png

不管是通过interrupt gate还是trap gate来访问异常或者中断的处理程序,处理器都会在保存了EFLAGS 寄存器值后将TF标志位清空。清除 TF标志位可以防止指令调制影响中断的响应。 IRET指令会将TF的值重新恢复。

interrupt gate还是trap gate唯一区别在于对于IF标志位的使用。interrupt gate在调用的时候会清除IF标志位,但是trp gate不会。

如果异常或者中断的处理程序是task gate,那么在进行异常或者中断处理的时候会产生任务的切换,下面是使用任务来作为中断或者异常处理的优势:

  1. 被中断的过程或者任务的上下文会被自动保存
  2. 新的任务有新的栈可以使用,可以防止原有栈的问题导致系统出现故障
  3. 可以定义新的地址空间,做到任务的分离。

当然劣势也很明显,就是任务切换太耗费资源,所以效率很慢。

下面的图6-5是调用过程的图示。

70ba01f30a79add6a9d690972a50208f.png

相关文章:

  • 怎么查看cmake_module_path中都有哪些路径_数据小白如何理解路径分析?
  • JAVA基础:Java多语言编码问题解析
  • win10 外接usb摄像头_win10系统外接usb摄像头怎么打开
  • formatnumber js_js组件-js插件-jquery插件-数字或金额格式化
  • 搭建一个只在光盘或U盘上跑的小型LINUX系统
  • 浪潮服务器安装系统centos7_2288H V5 服务器安装centos7.4系统过程中无法启动图形界面安装...
  • ZT- 100年前的人蚁大战
  • mysql tokudb编译安装_mysql之Tokudb引擎安装
  • 领域驱动设计注释版已经出版
  • asp mysql分页_asp+mysql分页_MySQL
  • mysql limit 重复_mysql limit 翻页数据重复的问题
  • BPEL中的partnerlink和partnerlinktype
  • jdbc连接mysql的步骤_JDBC链接数据库的几个步骤
  • 介绍一种全新的哲学思想
  • linux mysql 导入数据库脚本_思维导图学 Linux Shell攻略之干货篇 mysql数据库脚本管理系统...
  • [Vue CLI 3] 配置解析之 css.extract
  • Android单元测试 - 几个重要问题
  • Apache Pulsar 2.1 重磅发布
  • C++类的相互关联
  • es6
  • FineReport中如何实现自动滚屏效果
  • Javascript弹出层-初探
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Koa2 之文件上传下载
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • python 装饰器(一)
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • windows下mongoDB的环境配置
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用SAX解析XML
  • 思维导图—你不知道的JavaScript中卷
  • 移动端 h5开发相关内容总结(三)
  • 用element的upload组件实现多图片上传和压缩
  • 再谈express与koa的对比
  • 《码出高效》学习笔记与书中错误记录
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (1) caustics\
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (独孤九剑)--文件系统
  • (多级缓存)多级缓存
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (转) 深度模型优化性能 调参
  • (转)EXC_BREAKPOINT僵尸错误
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • .NET框架设计—常被忽视的C#设计技巧
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...