1.重新组织文件结构,精简代码
分割源文件
作者首先将源文件bootpack.c分割为几个部分:
graphic.c 关于描画的处理
dsctbl.c 关于GDT,IDT的处理
bootpack.c 其他处理
三个源文件编译分别生成目标文件以后连接生成bootpack.bim文件,剩下的过程和以前一样。
对应的Makefile内容也发生了变化。
运行后和之前一样。
整理Makefile文件
作者在这一步里对Makefile文件进行了进一步的简化书写:
像这种步骤相同的,作者用一般规则简化书写。
个人觉得掌握不了也没有关系,比较作者提供给我们了Makefile文件,我们的学习重心还是在操作系统本身。
整理头文件
在各个源文件中有对函数的重复声明,为了进一步精简,将这些重复的部分归纳起来组合形成一个源文件bootpack.h
这样只要在源文件前面添加:#include "bootpack.h"
就能将这些声明或者定义一同编译。
再次运行,显示结果没有什么变化,但是整个文件组织的结构合理了很多。
2.GDT和IDT的初始化
第五天最后讲到IDT和GDT的初始化,我们将其和第六天合到一起来讲解。
完成鼠标指针的绘画,想做的第一件事就是让鼠标指针移动起来,为了让它运动起来,我们需要完成对中断的设置,以便当外接设备变化时,处理这些信号。
GDT和IDT都是与cpu相关的设定。
GDT
GDT是 global desgriptor table 的简写,意思是局段号记录表,用于储存关于分段的信息,包括 段的大小是多少,段的起始地址是在哪里,段的管理属性。
每8个字节(64位)的数据记录这三个信息,书中告诉我们段号可以用0~8191之间的数,那么储存这些段的信息需要8192×8=65536(64KB) ,这64KB数据被写到内存中,就是GDT。
这些数据被整齐的排列在内存中的某个地方,然后将内存的起始地址和有效设定个数放在cpu内被称作GDTR的特殊寄存器中。
在第五天haribote02i中bootpack.c可以看到
SEGMENT_DESGRIPTOR中用了8字节存储信息。
GDT被存放在0x00270000地方。
循环设置GDT初值
IDT
IDT是interrupt descriptor table的简写,意思是中断记录表,用于处理外部状况或者内部状况发生变化。
各个设备发生变化时就会产生中断,中断发生后,cpu就会去处理中断,当处理完成后再继续执行任务。为了使用鼠标,我们就需要设置中断。
IDT记录了0~255的中断号码与调用函数的对应关系。
用GATE_DESCRIPTOR存放IDT信息。
load_gdtr函数
这个函数用来设置GDTR寄存器的值,GDTR是一个较为特殊的寄存器,为48位,不能使用常规的mov指令赋值。只能听过从某个内存地址开始连续读取6个字节。
在第六天中打开nasfunc.nas查看这个函数的原型。
和此相同还有一个load_idtr函数和load_gdtr函数原理相同。
set_segmdesc函数
在dsctbl.c中可以看到:
这个函数用来将段的信息归结成为8个字节写入内存当中,为了写入这些信息,还使用了SEGMENT_DESCPIPTOR结构体。
首先是地址,这里用了base这个变量,而base中又分为low mid high三段,加起来一共32个字节。
其次是段上限,它表示一个段能有多少给个字节,也就是段的大小,段上限使用20位,分为limit_low和limit_high,在limit_high的高4位里存放着段属性。
段属性有16位,其中有4位存放在limit_high中,在这个函数里也就是参数ar,ar的低8位在书中讲解如下:
3.初始化PIC
PIC 是programmable interrupt controller的简写,意思是可编程中断控制器,PIC监视着输入管脚的中断信号,如果有中断信号进来,便将唯一的输出管脚设置为ON,并通知给cpu.
一开始管脚为8个,IBM将其扩展到15个以处理更多的中断信号,他们认为电脑会有8个以上外部设备。
了解了硬件结构,我们就能正确的设定PIC
我们在haribote3d中打开int.c
IMR是中断屏蔽寄存器,如果某一位的值是1,那么该位对应的IRQ中断信号会被屏蔽,cpu就不会处理。
ICW是初始化控制数据,ICW有4个,ICW用于设定PIC主从关系,在这里设定为00000100,也就是PIC2和从PIC连接,ICW1和ICW4有别的用处,因此我们只能设置ICW2。
书中简单提了下PIC如果指挥cpu执行中断:
这次是使用INT 0x20~0x2f接收IQR 0 ~15
3.中断处理程序
接下来就是写得到中断后我们的处理程序,在haribote03e的int.c中可以看到:
这里有两个用于INT 0x2c和 INT 0x21的中断程序。
这些中断处理完成后,无法使用RET返回原来的地方,需要用IRETD指令返回。在nasfunc.nas中可以看到:
书中这样讲解这段程序,
这样我们就能返回原来的地方。
然后将这段程序注册到IDT中,
这样当发生中断的时候,cpu就会去调用asm_inthandler函数。
2*8参数描述的是这个函数属于哪个段。即段号为2
那么号码为2的段是什么样呢?
说明了对这个段的设定,但是我不是很懂…
最后在bootpack中添加io_sti( ),这样接收外部中断后,执行STI指令,IF中断标志变为1。表示接收信号。
在HairMain最后,修改了PIC的IMR以便于接收信号。
我们make run运行一下:
对键盘按键中断进行了响应。
但是目前还不能对鼠标中断进行响应。
今天的内容就是这样,收工!