Win32基础知识4
让编程改变世界
Change the world by program
80386的内存分页机制
在实模式下寻址的时候,“段寄存器+偏移地址”经过转换计算以后得到的地址是“物理地址”,也就是在物理内存中的实际地址。
而保护模式下,“段选择器+偏移地址”转换后的地址被称为“线性地址”而不是“物理地址”。那么,线性地址就是物理地址吗?
答案可能是“是”,也可能是“不是”,这取决于80386的内存分页机制是否被使用。
为什么会有内存分页机制?!
我们来回顾一下:在单任务的DOS系统中,一个应用程序可以使用所有的空闲内存。
程序退出后,操作系统回收所有的碎片内存并且合并成一个大块内存继续供下一个程序使用。
内存合并过程中的一个极端情况是当系统中有多个TSR程序时,早装入内存的TSR被卸载后,后装入的TSR会留在内存的中间部位,把空闲内存隔成两个区域。
这时应用程序使用的最大内存块只能是这两块内存中较大的一块,无法将它们合并使用。
对于一个多任务的操作系统,内存的碎片化是不能容忍的。否则,经过一段时间后,即使空闲内存的总和很大,也可能出现任何一片内存都小到无法装入执行程序的地步。
所以多任务操作系统中碎片内存的合并是个很重要的问题。
80386处理器的分页机制可以很好地解决这个问题。
80386处理器把4 KB大小的一块内存当做一“页”内存,每页物理内存可以根据“页目录”和“页表”,随意映射到不同的线性地址上。
这样,就可以将物理地址不连续的内存的映射连到一起,在线性地址上视为连续。
在80386处理器中,除了和CR3寄存器(指定当前页目录的地址)相关的指令使用的是物理地址外,其他所有指令都是用线性地址寻址的。
名词扫盲:
CR3 用于保存页目录表页面的物理地址,因此被称为PDBR。
由于目录是页对齐的,所以仅高20位有效,低12 位保留供更加高级的处理器使用。
向CR3中装入一个新值时,低12位必须为0,从 CR3中取值时,低12位被忽略。
还有,是否启用内存分页机制是由80386处理器新增的CR0寄存器中的位31(PG位)决定的。
如果PG=0,则分页机制不启用,这时所有指令寻址的地址(线性地址)就是系统中实际的物理地址;
当PG=1的时候,80386处理器进入内存分页管理模式,所有的线性地址要经过页表的映射才得到最后的物理地址。废话不多说,先上美图!!
[caption id="attachment_662" align="aligncenter" width="476"]
80386的内存分页机制[/caption]
一个xxxx:yyyyyyyy格式的虚拟地址,经过上节课所示的段地址转换步骤后得到32位的线性地址zzzzzzzz(步骤①)。
当禁用分页机制时,线性地址就是物理地址,处理器直接从物理内存存取数据(步骤②);
当启用分页机制时,得到线性地址的方法还是一样(步骤1'),但是还要根据页目录和页表指定的映射关系把地址映射到物理内存的真正位置上(步骤3')。
然后,CPU以映射后的物理地址在物理内存中存取数据。这个过程对于指令来说是透明的。
内存分页管理只能在保护模式下才可以实现,实模式不支持分页机制。
但不管在哪种模式下,所有寻址指令使用的都是线性地址,程序不用关心数据最后究竟存放在物理内存的哪个地方。
页表规定的不仅是地址的映射,同时还规定了页的访问属性,如是否可写、可读和可执行等。
比如把代码所在的内存页设置为可读与可执行,那么权限不够的代码向它写数据就会引发保护异常。利用这个机制可以在硬件层次上支持虚拟内存的实现。
页表可以指定一个页面并不真正映射到物理内存中。这样,访问这个页的指令会引发页异常错误。这时,处理器会自动转移到页异常处理程序中去。
操作系统可以在异常处理程序中将硬盘上的虚拟内存读到内存中并修改页表重新映射,然后重新执行引发异常的指令。
这样指令可以正常执行下去。请看图!
[caption id="attachment_663" align="aligncenter" width="478"]
80386的内存分页机制[/caption]
[buy]
获得所有教学视频、课件、源代码等资源打包 [/buy]
[Downlink href='http://urlxf.qq.com/?jUJrQba']视频下载[/Downlink]