30天自制操作系统:第六天 分割编译与中断处理

1 分割源文件(harib03a)

有过编程经验的小伙伴知道:如果很多程序代码都放在一个程序中,对于它的阅读、管理都是较麻烦的,所以这里开始介绍将源文件 bootpack.c 文件分割成几部分。

优点
  1. 按照处理内容进行分类,将来修改时更容易找到地方。
  2. Makefile文件写得好,只需要编译修改过的文件,可以提高make的速度。
  3. 单个源文件都不长,多个小文件比一个大文件好处理。
缺点
  1. 源文件数量增加
  2. 分类不当修改时不容易找到地方

分割后的源文件:
在这里插入图片描述
对应源文件修改后还需要整理Makefile:
在这里插入图片描述

2 整理Makefile(harib03b)

修改之前的Makefile:
在这里插入图片描述
使用一般规则可以将上面6个独立的文件生成规则归纳成以下两个一般规则:
在这里插入图片描述
一般规则中出现的“$*”符号,可以查阅:
Makefile自动化变量

make.exe会首先寻找普通的生成规则,如果没找到,就尝试用一般规则。所以,即使一般规则和普通生成规则有冲突,也不会有问题。这时候,普通生成规则的优先级更高。比如虽然某个文件的拓展名也是.c,但是想用单独的规则来编译它,也没问题。

3 整理头文件(harib03c)

继续整理源文件,现在的文件大小如下:
在这里插入图片描述
源文件中含有重复的函数声明“void io_out8(int port, int data);”等,可以通过统一放在一个头文件bootpack.h中:
在这里插入图片描述
头文件中包含了各个文件的函数声明,这样在源文件中就只要包含头文件就可以了:

#include "bootpack.h"

疑问:在包含头文件的时候使用的 < >" " 有什么区别?

双引号(" ")表示该头文件与源文件位于同一个文件夹中,而尖括号(< >)则表示该头文件位于编译器所提供的文件夹里。

这里面用了很多 #define 语句,把用到的地址都只写在了bootpack.h文件里,这么做的好处是因为,如果以后想要变更地址的话,只修改bootpack.h一个文件就行了。

4 意犹未尽

该小节是对昨天的程序代码做解释。
首先说明一下naskfunc.nasload_gdtr
在这里插入图片描述
这个函数用来指定的段上限(limit)和地址值赋值给名为GDTR的48位寄存器。这是一个很特别的48位寄存器,并不能像我们常用的MOV指令来赋值。给它赋值的方式:指定一个内存地址,从指定的地址读取6个字节(6 * 8 = 48位),然后赋值给GDTR寄存器。完成这一任务的指令,就是LGDT

该寄存器的低16位(内存的最初两个字节)是段上限,在最初执行的这个函数的时候,DWORD[ESP + 4]里存放的是段上限(即参数limit,调用函数的时候会按照从左到右压入参数,然后再压入返回地址,因此此时SP指向了返回地址4字节,往后移动4字节就是limit参数)
在这里插入图片描述

DWORD[ESP + 8]存放的是地址,我们打个比方,用实际的数字来说明代码在做什么。

比如我们传入0x0000ffff以及0x00270000,将它们写出来就是:
在这里插入图片描述
MOV AX, [ESP + 4] :将limit参数的值放在寄存器AX中(两字节,16位);
MOV [ESP + 6], AX:对[ESP + 6]内存处赋值,下图展现了赋值过程
在这里插入图片描述
LGDT [ESP + 6]:将以[ESP + 6]地址起始的6个字节总计48位写入到 GDTR这个48位寄存器中。在这里插入图片描述
上图为书中作者对此的解释,笔者认为这里数据有点问题,注意第一个红框处:[ FF FF 00 00 00 27 00 ],笔者认为应该是[ FF FF 00 00 00 00 27 00 ], 这里还有待研究。

set_segmdesc函数

在这里插入图片描述
函数是按照CPU的规格要求,将段的信息归结成8位写入内存的,这8个字节分别是:

  • 段的大小
  • 段的起始地址
  • 段的管理属性(禁止写入、禁止执行,系统专用等)

为了写入这些信息,我们准备了 struct SEGMENT_DESCRIPTOR 结构体。

struct SEGMENT_DESCRIPTOR {
	short limit_low, base_low;
	char base_mid, access_right;
	char limit_high, base_high;
};

在这里插入图片描述

首先看一下段的地址,称为段的基址,所以命名为了base,在结构体中base又被分为了low(2字节),mid(1字节),high(1字节)3个部分,合起来4字节(32位),所以这里按顺序填入数值就行了。

为什么要分为三段呢?
主要是为了与80286时代的程序兼容,有了这样的规格,80286用的操作系统,也可以不用修改就在386以后的CPU上运行。

说一下段上限,表示一个段有多少个字节,这里有个问题:段的表示有32位,那么最大可以表达2 ^ 32 = 4GB,这个数值本身就要占用4个字节,再加上基址(base),一共就要8个字节,这样一来,就没有地方保存段的管理属性信息了,这可不行。

因此段上限只能使用20位,这样的话,段上限最大也只能指定到1MB为止,明明有4GB,却只能用其中的1MB,这。。。不太合理对吧,所以英特尔的叔叔们想了一个办法,在段的属性里设了一个标志位,叫做Gbit。这个标志位为1的时候,limit的单位不解释为字节(byte),而是解释为页(page)。页是什么?在电脑的CPU里,一页指4KB。

这样一来,4KB * 1MB = 4GB,所以可以指定4GB的段。

这20位的段上限分别写到limit_low和limit_high里,一共3字节,即24位,但实际上我们接着要把段属性写入limit_high的高4位,所以最后段上限还是只有20。


最后这12位的段属性,又称为“段的访问权属性”,在程序中用变量名access_rightar来表示。因为12位段属性中的高4位放在limit_high的高四位里,所以程序有意把ar当作如下的16位构成来处理:
xxxx0000xxxxxxxx(其中x是0或1)

ar的高四位被称为“扩展访问权”,为什么这么说呢,因为这高四位的访问属性在80286的时代还不存在,到386以后才可以使用。这4位是由“GD00”构成的,G是指刚才所说的G bit,D是指段的模式,1是指32位模式,0是指16位模式。这里出现的16位模式主要只用于运行80286的程序,不能用于调用BIOS。所以,除了运行80286程序以外,通常都使用D = 1的模式。

以下内容为作者简要介绍ar的低八位。

在这里插入图片描述
在这里插入图片描述

5 初始化PIC(harib03d)

在这里插入图片描述
PIC指的是“programmable interrupt controller”的缩写,意思是“可编程中断控制器”。PIC与中断的关系可是很密切的,它到底是什么,在设计上,CPU单独只能处理一个中断,这不够用,所以IBM的大叔们在设计电脑时,就在主板上增设了几个辅助芯片。现如今它们已经被集成在了一个芯片组里了。

PIC是将8个中断信号(Interrupt Request,缩写为IRQ)集合成一个中断信号的装置, PIC监视着输入管脚的8个中断信号,只要有一个中断信号进来,就将为一个的输出管脚信号变成ON,并通知给CPU。IBM的大叔们想通过增加PIC来处理更多的中断信号,他们认为电脑会有8个以上的外部设备,所以就把中断信号设计成了15个,并为此增设了2个PIC。

PIC的线路连接:
在这里插入图片描述
有关PIC寄存器的简要介绍:
在这里插入图片描述
在这里插入图片描述

6 中断处理程序的制作(harib03e)

这里的内容较为


在这里插入图片描述
后续暂时没有过多理解,先不放上了,等待后续。。。

感受

今天的课依旧非常的多,所以没有过多的时间放在书上,最多是将书先看了一遍然后再照着书理顺一下自己的思路,毕竟是第二次看,有些地方可能会理解的更好一点,笔者借助这种方式加深自己对原书的理解,就这样稳扎稳打吧,虽然学得慢一些。
不知不觉,明天就周六了,嗯,没课,可以放开心去学习OS了,Over~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值