分段

分段可以说是Intel的CPU一直保持着的一种机制,而分页只是保护模式下的一种内存管理策略。不过想开启分页机制,CPU就必须工作在保护模式,而工作在保护模式时候可以不开启分页。

首先是全局段描述符表:

img

结构体后的__attribute__((packed))是GCC的扩展,用来设置该结构体不进行字节对齐。

段描述符表定义:

img

GDTR定义:

img

段描述符表的部分以二进制位来表示的设置信息合并到了相应的字节里,这里按照位域去定义不是不可以,但是太过于臃肿了。

全局描述符表的定义以及设置一项描述符的函数实现:

img

img

初始化函数:

img

最后有一个加载全局描述附表的函数,这个函数用汇编来实现了。代码如下:

img

CPU在保护模式下分页未开启和分页开启的不同状态时,MMU组件处理地址的流程。

如果没有开启分页:

逻辑地址->段机制处理->线性地址=物理地址

如果开启分页:

逻辑地址->段机制处理->线性地址->页机制处理->物理地址

因为我们采用了平坦模式,所以给出的访问地址实际上已经是线性地址了(段基址为0),那么剩下的问题就是所谓的页机制处理了。

分页

在逻辑上把内存划分为定长的物理页,同时将一个程序执行时候的线性地址地址空间划分为逻辑页,在分页机制工作的前提下,给硬件提供一组数据结构来保存这种映射关系。也就是说,线性地址是连续的,但是其实际指向的物理地址就不见得是连续的了。

以32位的地址来说,分为3段来寻址,分别是地址的低12位,中间10位和高10位。高10位表示当前地址项在页目录中的偏移,最终偏移处指向对应的页表,中间10位是当前地址在该页表中的偏移,我们按照这个偏移就能查出来最终指向的物理页了,最低的12位表示当前地址在该物理页中的偏移。就这样,我们就实现了分级页表。

img