帮建网站,python编写简单网页,wordpress用户页,华为仓颉编程语言补充#xff1a;事件不仅包含中断和异常#xff0c;还包含系统调用#xff0c;这个属于用户主动请求的事件。 上一节#xff0c;只有一个溢出异常#xff0c;那么#xff0c;如果很多异常、中断呢#xff1f;#xff08;中断向量表#xff09;
另外#xff0c;之前0…补充事件不仅包含中断和异常还包含系统调用这个属于用户主动请求的事件。 上一节只有一个溢出异常那么如果很多异常、中断呢中断向量表
另外之前0号地址只能存储两条指令如果需要更多指令怎么办地址的位置以及对应程序大小应该更灵活
注意中断服务程序包含保存现场调用处理方法主体恢复现场
我们在遇到中断之后需要执行的步骤我们简化一下
CPU做一些硬件处理工作识别中断源关中断当前指令或下一条指令地址压栈FLAGS寄存器压栈找到处理中断的程序地址这里的程序是中断服务程序执行中断服务程序包含保护现场执行处理程序这个才是主体部分恢复现场返回原程序继续执行原有程序
在不同的时代中断的处理都是这个过程只不过每个过程具体的执行发生了变化且越来越复杂我们依次看一下。
1 时代1UNIVAC时代仅有固定地址中断处理
在最初的计算机时代只有很少的内部中断和外部中断。 内个时候的中断服务程序是固定的地址并且程序的大小也相对受限。
例如出现了算数溢出那么就会跳转到地址0执行中断服务程序。 不仅如此这个时候的中断服务程序几乎是
固定地址固定大小
因此灵活性很差不过由于很少所以还好。
到了后来中断越来越多因此就有了中断向量表下面看看8086时代吧。
2 时代28086时代实模式 中断向量表
这个时代中断已经较多了管理中断的方式也更加灵活了。 8086采用的是实模式也就是说进入CPU指令中的地址就是实际的物理地址。
在8086的1MB内存中有专门的中断向量表区从地址0开始的1K字节它用于存放中断服务程序的地址也就是存放CS:IP。
每对CS:IP占用4个字节因此1KB的空间最多可以支持256种中断。 CS:IPCS在前IP在后因此CS在高地址IP在低地址又因为是小端模式因此IP的高字节是高位低字节是低位CS同理。
这样一来实际的中断服务程序的位置是根据这些CS:IP的值确定的而它们在内存中是可以修改的因此
中断服务程序的位置可变程序的大小可改
并且这些中断服务程序的位置是任意的只要能够与中断向量表对应上即可。
同时不同的中断服务程序位置没有关联放哪里都行。在实模式的8086之下只需要CS:IP就可以确定实际内存的位置。 在这个时代中断服务程序的位置了大小更加灵活变成了间接获取因为加了一个中断向量表。 注意这个时候有5种类型的中断并不是5个中断这个时候涉及到的内部中断有4个外部中断有1个而这个外部中断是8259A芯片发出的该芯片外面可以连接很多个外设。 我们来看看这个时代中断处理的示意图。 3 时代380386时代保护模式 中断向量表
这个时代就有点复杂了引入了保护模式同时增加了一些中断类型这也是Linux 0.11内核对应的CPU。
圈住的部分是80386支持的中断类型int0 ~ int16其中int15未定义可以在手册中查到。
3.1 保护模式下的寻址方式
首先保护模式下依然是CS:EIP的形式但是由于EIP已经足够寻址4GB因此CS不再作为位数扩展的功能了它的功能发生了改变。 在保护模式下段寄存器依然是16位它们变成了段选择子寄存器先从最简方式描述地址的生成方法
通过段选择子寄存器找到8字节大小的段描述符根据段描述符的内容获取段基址32位段基址和EIP组合应该就是相加吧基址 偏移地址得到地址注意 目前可以知到这个地址是给CPU看的它应该是虚拟地址现在先不管先当成通过这个地址就能够访问到内存的指定位置。
是不是比实模式复杂多了下面进一步展开细节。
通过段选择子寄存器此后均以CS举例说明怎么找到对应的段描述符
计算机启动进入实模式填好GDT设置好GDT的初始地址放入GDTR寄存器中 在保护模式下 CS GDTR获取对应的描述符0~8191这样我们就获取了代码段的描述符了。
接下来我们看看这个描述符
这个描述符有8192个也就是2^13而一个描述符有2^3 8个字节因此一共占用了2^16个内存单元也就是64KBCS寄存器是16位的这是它能够访问的极限这样通过GDTR基址 CS偏移的方式能够访问到每一个描述符表。再看每一个描述符的结构 它有8个字节的大小其中有四个字节是段基址就是这个段基址与EIP组合形成最终的要访问内存的虚拟地址。其他的自己还涉及到权限以及界限先不管是干啥的。
段描述符的内容是什么怎么获取段基址
上面已经说明了。
3.2 保护模式下的中断操作
上面一小节经历了一系列复杂过程终于说明了保护模式下如何寻址真的很复杂啊……下面说明一下中断操作过程。其实最主要说明的还是找中断服务程序位置这个过程。 在保护模式下也有一个IDTR中断描述符表寄存器还有一个IDT中断描述符。
这个IDT同样是支持256种类型的中断的每个描述符表项占8个字节因此一共占用2KB。
IDTR提供的是IDT的基址然后CPU获取中断号之后根据中断号 * 8 IDTR定位对应的描述符。
对于中断描述符
字节0167四个字节对应的是32位地址也就是EIP的值字节23对应的是CS的值有了CS:EIP就可以通过上一小节的方式找到对应的地址从而找到中断服务程序入口地址 这个过程其实与CS:IP类似只不过麻烦了点
折腾了这么一大圈终于找到中断服务程序了……
3.3 小结
这个太复杂了我们简单总结一下吧。
首先保护模式下的寻址方式更复杂了引入了全局描述符表虽然依然是CS:EIP但是其计算方式更加复杂了。
其次保护模式下的中断处理更复杂了
以前固定位置的中断向量表变成了任意位置的中断描述符表IDT通过IDTR和中断类型号计算得到中断描述符再通过中断描述符的内容获取CS:EIP再获取对应中断服务程序的入口地址
我们可以看到模式越来越复杂间接程度越来越高设置的自由度提高安全性也提高了。 思想太固定死板怎么办加个固定的中转站通过改变中转站来实现灵活地分配目标
这几个时代的发展过程可以说中转站越来越多越来越复杂灵活度越来越高。
小结
本篇内容贯彻的是中断处理的找中断服务程序的过程。
可以看到
UNIVAC时代非常直接地找到地址8086时代提供了固定位置中断向量表间接地找到CS:IP寻址方式是直接的80386时代提供了任意位置的中断描述符表间接地获取CS:EIP寻址方式也是间接的需要通过全局描述符表GDT获取段基址从而获取内存地址
不管怎样时代的发展使得根据中断类型号找到中断服务程序这个过程越来越复杂灵活度也越来越高。
后面会介绍中断处理的其他过程最后结合Linux 0.11内核源代码使得软硬件对应上。