虚拟地址如何映射到物理地址
虚拟地址)被不同的进程映射到的物理地址是不同的,那么大家知道虚拟地址如何映射到物理地址吗?下面跟着小编来一起了解下虚拟地址映射到物理地址吧。
虚拟地址映射到物理地址方法
这里只谈分页管理的机制,也是目前最重要的内存管理机制。
最初的设计想法:
结构图如下:
页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移。
页表项的结构:
各个位的含义:
P--位0是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。如果P=0,那么除表示表项无效外,其余位可供程序自由使用,如图4-18b所示。例如,操作系统可以使用这些位来保存已存储在磁盘上的页面的序号。
R/W--位1是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
由于页表占用内存空间太大(1M个元素*4B大小=4MB,也可以这么看:每个进程的虚拟地址空间=4G,页面大小=4K,所以共有1M个页,需要1M个页表项,又因为每个页表项=4B,所以页表大小=4M),为了减少内存占用量,因此设计了层次化的分页结构:页目录表+页表。
层次化的设计想法:
因为4GB的虚拟内存共有1M=220=1048576个4K大小的页面。
我们将这些页面分成210=1024份,即从页表1到页表1024,由页目录表管理;
每一份(每一页表)有210=1024个页,由每一个页表管理,页在页表中是随机的,哪个页位于哪个页表中是没有规律的;
结构图如下:
每个任务都有这样的层次化的分页结构,即每个任务都有自己的页目录表和页表。
从硬件角度来分析:
在处理器中有个控制寄存器CR3,存放着当前任务页目录的物理地址,故又叫做页目录基址寄存器(Page Directory Base Register,PDBR),每个任务都存放了自己的页目录物理地址,当任务切换时,处理器切换到新任务开始执行,更新CR3寄存器的内容,以指向新任务的页目录位置;
相应的,页目录又指向了一个个的页表,每个页表又根据任务的页表项指向了相应的页。其中注意的是,页目录和页表也是普通的页,混迹于全部的物理页中,它们和普通页的不同之处仅仅在于功能不一样,当任务撤销之后, 它们和任务所占用的普通页一样会被回收, 并分配给其他任务(如下图所示)。
下面内容转自《分页机制》,写的很清楚。
地址变换的具体过程
对于Intel处理器来说, 有关分页, 最简单和最基本的机制就是这些; CR3寄存器给出了页目录的物理地址; 页目录给出了所有页表的物理地址, 而每个页表给出了它所包含的页的物理地址. 好了, 该清楚的都清楚了, 唯一还不明白的, 应该是如何用这种层次性的分页结构把线性地址转换成物理地址? 这里举个例子, 某任务加载后, 在4GB虚拟地址空间创建了一个段, 起始地址为0x00800000, 段界限为0x5000, 字节粒度. 当前任务执行时, 段寄存器DS指向该段. 又假设执行了下面一条指令
mov edx, [0x1050]
此时, 段部件会输出线性地址0x00801050. 在没有开启分页机制时, 这就是要访问的物理地址. 但现在开启了分页机制, 所以这是一个下虚拟地址, 要经过页部件转换, 才能得到物理地址.
如下图所示, 处理器的页部件专门负责线性地址到物理地址的转换工作. 它首先将段部件送来的32位线性地址分为3段, 分别是高10位, 中间10位, 低12位. 高10位是页目录的索引, 中间10位是页表的索引, 低12位则作为页内偏移量来用.
当前任务页目录的物理地址在处理器的CR3寄存器中, 假设它的内容为0x00005000. 段管理部件输出的线性地址是0x00801050, 其二进制的形式如图中给出. 高10位是十六进制的0x002, 它是页目录表内的索引,处理器将它乘以4(因为每个目录项4字节), 作为偏移量访问页目录. 最终处理器从物理地址00005008处取得页表的物理地址0x08001000.
线性地址的中间10位为0x001, 处理器用它作为页表索引取得页的物理地址. 将该值乘以4, 作为偏移量访问页表. 最终, 处理器又从物理地址08001004处取得页的物理地址, 这就是我们一直努力寻找的那个页.
页的物理地址是0x0000c000, 而线性地址的低12位是数据所在的页内偏移量. 故处理器将它们相加, 得到物理地址0x0000C050, 这就是线性地址0x00801050所对应的物理地址, 要访问的数据就在这里.
注意, 这种变换不是无缘无故的, 而是事先安排好的. 当任务加载时, 操作系统先创建虚拟的段, 并根据段地址的高20位决定它要用到哪些页目录项和页表项. 然后, 寻找空闲的页, 将原本应该写入段中的数据写到一个或者多个页中, 并将页的物理地址填写到相对应的页表项中. 只有这样做了, 当程序运行的时候, 才能以相反的顺序进行地址变换, 并找到正确的数据.
页目录项, 页表项, CR3和打开分页
页目录项和页表项
页目录和页表中分别存放为页目录项和页表项, 它们的格式如下:
可以看出, 在页目录和页表中, 只保存了页表或者页物理地址的高20位. 原因很简单, 页表或者页的物理地址, 都要求必须是4KB对齐的, 以便于放在一个页内, 故其低12位全是0. 在这种情况下, 可以只关心其高20位, 低12位安排其他用途.
P 是存在位, 为1时, 表示页表或者页位于内存中. 否则, 表示页表或者页不在内存中, 必须先予以创建, 或者从磁盘调入内存后方可使用.
RW 是读/写位. 为0时表示这样的页只能读取, 为1时可读可写
US 是用户/管理位. 为1时, 允许所有特权级别的程序访问; 为0时, 只允许特权级别为0, 1和2的程序访问.
PWT(Page-level Write-Through) 是页级通写位, 和高速缓存有关. "通写"是处理器高速缓存的一种工作方式, 这一位用来间接决定是否采用此种方式来改善页面的访问效率.
PCD(Page-level Cache Disable)是页级高速缓存禁止位, 用来间接决定该表项所指向的那个页是否使用高速缓存策略.
A 是访问位. 该位由处理器固件设置, 用来指示此表项所指向的页是否被访问过.
D(Dirty) 是脏位. 该位由处理器固件设置, 用来指示此表项所指向的页是否写过数据