PA4 异常中断与 IO
PA4-1 异常和中断的响应
异常和中断的的处理:
第一阶段:硬件
1、保护断点和程序状态:把 EFLAGS、CS、EIP 的值 push 进栈
2、关中断:外部中断需要关中断,即清空 IF 位,内部异常则不需要。
3、识别异常和中断事件并转到相应的处理程序执行:根据指令或硬件给的异常和中断的类型号,查询中断描述符表,找到对应的处理程序的地址并跳转执行。
此处的中断描述符表与之前 PA3 的段表、页表类似。
第二阶段:软件(操作系统)
1、保护现场:执行 pusha 指令,保存所有寄存器的值
2、处理异常或中断
3、处理结束,使用 popa 恢复现场
4、通过 iret 恢复断点和程序状态,并返回原程序继续执行
两种响应
- 内部异常
以int 0x**
的形式执行,程序遇到这条指令时就会进行上述两个阶段的处理。
- 外部中断
使用专门的引脚,每执行完一条指令后都去检查引脚是否有中断事件,如果有,就会进行上述两个阶段的处理。
本节任务
1、实现 lidt、cli、sti、int、pusha、popa、iret 指令。
2、实现 raise_intr 函数,根据异常中断类型号完成第一阶段硬件处理的模拟。
PA4-2 外设与 IO
向一台完整的计算机设备迈出最后一步!
IO 的两种方式
- 端口映射模拟
IA-32 共定义了 65536 个 8 位的 IO 端口,CPU 通过专门的 IO 指令 in 和 out 来对一个端口进行读和写。
通过对某一特定端口的读写,完成 CPU 和某些特定外设之间的数据交换。
比如本实验中的串口、硬盘、键盘灯设备。
- 内存映射模拟
将一部分物理内存映射到 IO 设备空间中,使得 CPU 可以通过普通的访存指令来访问设备。
具体的例子是 VGA 内部的显存,映射到某一确定的物理地址空间,CPU 修改该物理地址空间,相当于修改显存内容。
本节任务
本节主要用于理解外部设备与 cpu 的数据传输,大部分功能已完成。
1、实现 in、out 指令。
2、实现串口打印函数。
3、修改 loader,改为从硬盘读取用户程序。
4、完成显存的恒等映射(映射:即一些页表)
PA4-3 可选任务:游戏移植
从 PA1 的 PA4,我们一步步地实现并完善了这个虚拟机框架。
最后一步,我们可以在这个虚拟机框架里运行游戏了。
-
打字小游戏
-
仙剑奇侠传
-
彩蛋
本节任务
重写 SDL 库的 API,主要有以下几个内容:
1、时钟相关
- 返回当前时间的函数
- 延迟若干毫秒时间的函数
可以使用记录了时钟中断次数的变量实现上面两个函数
2、键盘相关
- 记录按键状态的函数
- 寻找上一个释放的按键的函数
3、显示相关
4、简易文件系统
- fs_open()
- fs_read()
- fs_lseek()
- fs_close()
很遗憾,我的 PA 之旅停留在最后的打字小游戏。
程序运行了很久,画面中才显示出打字小游戏的界面,左上角写着“1 FPS”,第一行一个字母“Q”就卡在那里,不再下落。
PA 完结的最后
这是我这学期的 PA 实验的第四篇文章,也是最后一篇。
开始只是记录了一些实验中写的函数,后来则是概括性的总结实验内容。
一个学期,整个 PA 之旅走下来,遇到过数不清的 bug。
在 3-2 时,缺页。不管怎么改都缺页。用了一些“不好的技巧”避开了缺页的问题,坚持通过了 3-2。
在 4-1 时,段错误。不管怎么改都段错误,问了好多人,都没遇到我这个问题。在不断地修改的过程中,居然成功地解决并理解了之前 3-2 遇到的问题。而这个段错误,也因为发现一个低级错误而告终。
我一路挺到最后的游戏,面对仙剑奇侠传却放弃了。
我现在在码字,这个 12 点截止,我注定无法去完成这个游戏的移植了。
但这个 PA 之旅,我依旧收获不少。
每一次运行程序,都会有贴心的教诲(大致是下面的意思):
1、程序绝不会错误执行,如果有问题,一定是代码写的不对。
2、没有执行过的程序永远是错的。
最后,用 PA 手册开篇的一个醒目的标志结尾:
“Don’t panic.”