操作系统实验第六天:分割编译与中断处理

内容1:分割源文件
由于bootpack.c的代码过于长,长达近300行,于是决定分割一下源文件,决定按下图分割:
在这里插入图片描述

如果比如graphic也想使用naskfunc.nas的函数,就必须写上“void io_out8(int port,int data);”这种函数声明。因为编译器在编译graphic.c时根本不知道bootpack.c的存在。
还有修改一下Makefile,流程如下:
在这里插入图片描述

内容2:整理Makefile
整理完的Makefile文件如下:
在这里插入图片描述

发现增加源文件后,使得Makefile文件也大了许多,而且这种雷同的编译规则看的很烦。
于是归纳Makefile,修改如下;
在这里插入图片描述

Makefile中可以用一般规则的地方我们都换成一般规则,程序就精简到了92行。
内容3:整理头文件
在各个源文件中都要重复声明“void io_out8(int port,int data);”还是很多,所以继续在这一部分下点功夫。
首先将重复部分全部去掉,归纳起来放在bootpack.h的文件中。内容部分如下:
在这里插入图片描述

这个文件中不仅仅罗列出了函数的定义,还在注释中写明了函数的定义在哪一个源文件。
在编译graphic.c的时候,我们要让编译器读这个头文件,所以在graphic.c的前面加上一行
#include “bootpack.h”
编译器见到样的语句,就会将该行替换成”graphic.c”中。同样道理,在”dsctblc.c”和”bootpack.c”中也是一样。这样的文件,就叫做头文件。就像之前调用sprintf函数时要加上#include <stdio.h>一样。双引号表示该头文件与源文件位于同一个文件夹,而尖括号则表示该头文件在编译器所提供的头文件中。
最后又使得源文件有所缩短。
内容4:意犹未尽
Naskfunc.nas的_load_gdtr如下:
在这里插入图片描述

这个函数用来将指令的段上限(limit)和地址值赋值给名为GDTR的48位寄存器。并不能用我们常用的MOV指令来赋值。给它赋值的时候,唯一的办法就是指定一个内存地址,从指定的地址读取6个字节(也就是48位),然后赋值给GDTR寄存器。完成这一任务的指令,就是LGDT.
该寄存器低16位(即内存的最初2个字节)是段上限,它等于“GDT的有效字节数-1”。剩下的高32位(即剩余的4个字节),代表GDT的开始地址。
在最初执行这个函数的时候,DWORD[ESP+4]里存放的是段上限,DWORD[ESP+8]里存放的是地址。具体到实际的数值,就是0x0000ffff和0x00270000。把他们按字节写出来的话,就成了[FF FF 00 00 00 00 27 00],希望把它排列成[FF FF 00 00 27 00]的形式,所以就先用“MOV AX,[ESP+4]”读取最初的0xffff,然后再写到[ESP+6]里。这样,结果就成了[FF FF FF FF 00 00 27 00],如果从[ESP+6]里。如果从[ESP+6]开始读6字节的话,正好是我们想要的结果。
naskfunc.nas的_load_idtr设置IDTR的值,因为IDTR与GDTR结构体基本上是一样的,程序也非常相似。
dsctbl.c节选
在这里插入图片描述

这个函数是按照CPU的规格要求,将段的信息归结成8个字节写入内存的。这8个字节填入的内容如下:
1.段的大小
2.段的起始地址
3.段的管理属性(禁止写入,禁止执行,系统专用等)

关于结构体,首先看一下段的地址。地址当然是用32位来表示。这个地址在CPU世界的语言里,被称为段的基址。所以这里使用了base这样一个变量名。在这个结构体里base又分为low,mid,high 3段,合起来正好32位。所以,这里只要按顺序分别填入相应的数值就行了。
程序中使用了移位运算符和AND运算符往各个字节里填入相应的数值。分三段是为了与80286时代的程序兼容。
下面再说一下段上限。它表示一个段有多少个字节。
段上限最大是4GB,也就是一个32位的数值,如果直接放进去,这个数值本身就要占用4个字节,再加上基址,就需要8个字节,这就把整个结构体占满了。
所以段上限只能使用20位。这样的话,段上限最多也只能指定到1MB。所以在段的属性中设置了标志位,叫做Gbit。这个标志位是1的时候,limit的单位不解释成byte,而是页。
一页是4KB,4k*1m=4G,这样这个问题就解决了。
最后再来说一下12位的段属性。
段属性在程序中用access_right或ar来表示。因为12位段属性中的高4位放在limit-high的高4位,所以程序有意把ar当作如下16位来处理。
在这里插入图片描述

ar的高4位被称为“扩展访问权”。为什么这么说呢?因为这高4位的访问属性在80286的时代还不存在,到386之后才可以使用。由GD00构成,其中G是指刚才所说的Gbit,D是指段的模式,1是32,0是16。所以除了运行80286程序以外,通常都使用D=1.
ar的低8位从80286时代就已经有了,简单介绍如下:
在这里插入图片描述

CPU到底是处于系统模式还是应用模式,取决于执行中的应用程序是位于访问权为0x9a的段,还是位于访问权为0xfa的段。
内容5:初始化PIC
为了达到鼠标移动的目的,必须使用中断,也就必须将GDT和IDT准确无误的的初始化。
PIC,意思是“可编程中断控制器”,是将8个中断信号集合成一个中断信号的装置。它监视着输入管脚的8个中断信号,只要有一个中断信号进来,就将唯一的输出管脚信号变成ON,并通知CPU。后来中断信号又被设计成了15个,并为此增设了两个PIC。
在这里插入图片描述

上图为线路的连接。
与CPU直接相连的PIC称为主PIC,另一个称为从PIC。主PIC负责处理第0到第7号中断,另一个处理8-15.
从PIC通过第二号IRQ与主PIC相连。
在这里插入图片描述

以上是PIC的初始化程序。
关于PIC的寄存器,首先,都是8位寄存器。
IMR:中断屏蔽寄存器。8位分别对应了8路IRQ信号。如果某一位的值是1,则该位的IRQ信号被屏蔽,PIC就忽视该路信号。这是为了防止正在对中断设定进行更改时,如果再接受别的中断会引起混乱,同时,也防止静电干扰引起没有链接任何设备的IRQ的反应。
ICW:初始化控制数据,有4个,分别编号为1-4,共4个字节数据。ICW1和ICW4与PIC主板配线方式、中断信号的电气特性有关,所以不再详细说明。电脑上设定的是上述程序的固定值,不会设定其他值。ICW3是有关主-从连接的设定,对主PIC而言,第几号IRQ与从PIC相连,是用8位来设定的。如果把这些位全设为1,那么主PIC就能驱动8个从PIC(那样的话,最大就可能有64个IRQ),但我们所用的电脑并不是这样,所以就设定为00000100。另外,该从PIC和主PIC的第几号相连,用3位来设定。

内容6:中断处理程序的制作
在这里插入图片描述

上面是用于INT 0x21的中断处理程序(handler),即中断发生时所要调用的程序。可以看到,这个函数显示一条信息,然后保持在待机状态,鼠标的程序也几乎一样,只是显示信息不同。但是这样并不能运行,因为中断处理完成后不能执行return指令,必须执行IRETD指令(不能用C语言写),所以要借助汇编。
在这里插入图片描述

左边是关于键盘的汇编程序。鼠标也是一样,就只说一个就可以。
EXTERN指令表示call调用的函数来自该文件外;中断处理完成后不能执行return,而是要执行IRETD。C语言会默认认为ES、DS、SS指向同一个段,所以三者的值必须保持相等
IRETD表示将程序控制权从异常或中断处理程序返回异常、外部中断或软件生成的中断所中断的程序或过程
在这里插入图片描述

关于栈,左边为push,右为pop.
在这里插入图片描述

乘以8是因为低三位表示的是别的意思,在这里低三位必须为0,所以乘以8来实现低三位为0;当然也可以写成2<<3的形式,左移3位右边补0。
AR_INTGATE32表示将IDT属性设定为0x008e,表示这是用于中断处理的有效设定。
在这里插入图片描述

程序有以上语句说明这个段正好覆盖了整个bootpack.hrb
运行结果如下:
刚运行时:
在这里插入图片描述

按下键盘之后:
在这里插入图片描述

可以看到可以正确响应键盘的变化。
二、遇到的问题及解决方法
问题1:
关于这些变量在8个字节中的对应位置和长度
在这里插入图片描述

答:
limit_low:0-15
base_low:16-31
base_mid:32-39
ar_low:40-47
ar_high:48-51
limit_high:52-55
base_high:56-63
三、创新点
创新点1
修改bootpack.c和int.c文件有关于刚开始显示的内容和中断之后的内容如下:
部分一:
在这里插入图片描述

部分二:
在这里插入图片描述

修改这两部分的内容,就可以更改中断前后的图案设计。
创新点2:
使得键盘只相应一个按键,而不是所有按键
在这里插入图片描述

这样修改之后,只有按下A才有反应,而不是所有按键都可以。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值