首页 > 代码库 > 32位机内存管理机制(上)

32位机内存管理机制(上)

一直有看linux内核的冲动,内核有些部分是汇编编写的,无奈汇编不大懂,所以利用五一三天假期大概走了一边8086CPU架构的汇编,8086CPU还是16位的,我们现在都进入64位时代了,这两者之间有很大的区别,但是看看16位的CPU汇编还是很重要的,这有助于理解32位的80386CPU。这篇文章来分析下80386的内存管理的一些基础知识,包括实模式、保护模式和内存寻址等等。

1.实模式

处理器被复位或者加电的时候以实模式启动。这时候处理器中各寄存器以实模式的初始化值工作。

80386处理器在实模式下的存储器寻址方式和8086是一样的,由段寄存器的内容乘以 16当做基地址,加上段内的偏移地址形成最终的物理地址,这时候它的32位地址线只使用了低20位。

 在实模式下,80386处理器不能对内存进行分页管理,所以指令寻址的地址就是内存中实际的物理地址。在实模式下,所有的段都是可以读、写和执行的。

实模式下80386不支持优先级,所有的指令相当于工作在特权级(优先级0),所以它可以执行所有特权指令,包括读写控制寄存器CR0等。

实际上,80386就是通过在实模式下初始化控制寄存器,GDTR,LDTR,IDTR与TR等管理寄存器以及页表,然后再通过加载CR0使其中的保护模式使能位置位而进入保护模式的。

当然,实模式下不支持硬件上的多任务切换。实模式下的中断处理方式和8086处理器相同,也用中断向量表来定位中断服务程序地址。中断向量表的结构也和8086处理器一样:每4个字节组成一个中断向量,其中包括两个字节的段地址和两个字节的偏移地址。

从编程的角度看,除了可以访问80386新增的一些寄存器外,实模式的80386处理器和8086有什么进步呢?其实最大的好处是可以使用80386的32 位寄存器,用32位的寄存器进行编程可以使计算程序更加简捷,加快了执行速度。

比如在8086时代用16位寄存器来完成32位的乘法和除法时,要进行的步骤实在是太多了,现在用32位寄存器一条指令就可以完成。80386中增加的两个辅助段寄存器FS和GS在实模式下也可以使用,这样,同时可以访问的段达到了6个而不必考虑重新装入的问题。

最后,很多80386的新增指令也使一些原来不很方便的操作得以简化。

2.保护模式

当 80386工作在保护模式下的时候,它的所有功能都是可用的。这时80386所有的32根地址线都可供寻址,物理寻址空间高达4GB。在保护模式下,支持内存分页机制,提供了对虚拟内存的良好支持。虽然与8086可寻址的1 MB物理地址空间相比,80386可寻址的物理地址空间可谓很大,但实际的微机系统不可能安装如此大的物理内存。所以,为了运行大型程序和真正实现多任务,虚拟内存是一种必需的技术。

保护模式下80386支持多任务,可以依靠硬件仅在一条指令中实现任务切换。任务环境的保护工作是由处理器自动完成的。在保护模式下,80386处理器还支持优先级机制,不同的程序可以运行在不同的优先级上。优先级一共分0~3 共 4个级别,操作系统运行在最高的优先级0上,应用程序则运行在比较低的级别上。配合良好的检查机制后,既可以在任务间实现数据的安全共享也可以很好地隔离各个任务。

从实模式切换到保护模式是通过修改控制寄存器CR0的控制位PE(位0)来实现的。

在这之前还需要建立保护模式必需的一些数据表,如全局描述符表GDT和中断描述符表IDT等。

DOS操作系统运行于实模式下,而Windows操作系统运行于保护模式下。

3.80386内存寻址机制

Windows的内存管理和DOS的内存管理有很大的不同,在了解Windows的内存管理模式之前,需要对80386保护模式下内存分页机制有所了解。

为了做个对比,先来看实模式下的内存寻址方式:在实模式下,一个完整的地址由段地址和偏移地址两部分组成。

处理器换算时先将段地址乘以10h,得到段在物理内存中的起始地址,然后加上16位的偏移地址得到实际的物理地址。

现在我们谈回到80386处理器的工作模式:


当80386处理器工作在保护模式和虚拟8086模式的时候,可以使用全部32根地址线访问4 GB大的内存。段地址加偏移地址的计算方法显然无法覆盖这么大的范围。

但计算一下就可以发现,实际上和8086同样的限制已经不复存在,因为80386所有的通用寄存器都是32位的,2^32 =4G,所以用任何一个通用寄存器来间接寻址,不必分段就已经可以访问到所有的内存地址。

这是不是说,在保护模式下,段寄存器不在有用了呢?

答案是否定的!实际上段寄存器更有用了,虽然在寻址上不在有分段的限制问题,但在保护模式下,一个地址空间是否

可以被写入,可以被多少优先级的代码写入等涉及保护的问题就出来了

要解决这些问题,必须对地址空间定义一些安全属性。段寄存器这是就派上了用场,不妨将这些属性放在段寄存器中!

但是问题来了,涉及属性和保护模式下段的其他参数,要表示的信息太多了,要用64长的数据才能表示,我们把这64位的属性数据叫做段描述符。

80386的段寄存器仍然是16位的,无法放下保护模式下的64位的段描述符,如何解决这个新的问题呢?解决办法是把所有段的段描述符顺序放在内存中的指定位置,组成一个段描述符表,而段寄存器中的16位用来做索引信息,指定这个段的属性用段描述符表中的第几个描述符来表示,这时,段寄存器中的信息就不再是段地址了,而是段选择器,可以通过它在段描述符表中”选择“一个项目以得到段的全部信息。