页目录自映射详解
本文中的内容基于MIPS32架构,不同架构的页表设计可能有所不同。
页目录自映射的实质:采用一级页表,并将页表放置在kseg2
中以减少物理内存占用。
若虚拟地址空间为4GB,页面大小为4KB,则整个虚拟地址空间对应1M个页,若每个页表项为4B,则一共要占用4MB内存。
此时,可以将页表放置在kseg2
中,kseg2
将经过MMU进行地址翻译,未使用的页面无需分配物理内存,达到减少物理内存占用的目的。
例如,对于如下页表(注意,为了方便计算,页表起始地址需要对齐4M边界)
假设现在要将虚拟地址转化为物理地址,需要访问页表,但页表也在虚拟地址空间中,需要通过页表转化为物理地址,也就是说,我们需要第C 0C00
到第C 1000
个虚拟页的物理地址。
这个范围对应的页表项,显然也存在于页表中,具体地说,虚拟地址为:
C 0C00
-->C 0C00 * 4 + C0C0 0000 = C0F0 3000
C 1000
-->C 1000 * 4 + C0C0 0000 = C0F0 4000
显然,这个范围刚好对应一页。
要能获得页表项所在的物理地址,需要首先通过虚拟地址为C0F0 3000
到C0F0 4000
的页表项内容进行转化(实践中,需要提前将该虚拟地址范围的映射关系存储到TLB中,该4KB空间刚好对应一页,占用一个TLB条目,假设对应物理地址0000 8000--0000 9000
的物理页),这一页的内容称为页目录。
如下图:
从本质上,我们使用的是一级页表,只是将其放到了需要进行地址转换的区域。但「将一级页表放到需要进行地址转换的区域」的结果是,在页表中恰好有一页(在预设的页大小、虚拟地址空间大小下),对应了整个页表区域从虚拟地址到物理地址的映射,这一页称为页目录。
从上图可以看出,页表中页目录对应的页表项,其映射到的物理地址正是页目录这一页所在的物理地址,这正是「页目录自映射」这一名称的由来。
在进行地址转换时,过程如下(假设要进行转换的虚拟地址为0x1234 5678
,页表起始虚拟地址为0xC0C0 0000
,页目录所在的物理页地址为0x0000 8000
到0x0000 9000
,如上图):
- 取出虚拟页号(页大小为4KB,虚拟地址的第12到31位为虚拟页号):
0x12345678 >> 12 = 0x12345
- 按一级页表计算偏移量(假设每个页表项占用4字节):
0x12345 * 4 = 0x48D14
- 加上页表基地址,得到对应的页表项所在的虚拟地址:
0xC0C0 0000 + 0x48D14 = 0xC0C48D14
- 现在,又需要将该虚拟地址转换为物理地址,取出虚拟页号:
0xC0C48D14 >> 12 = 0xC0C48
- 按一级页表计算偏移量:
0xC0C48 * 4 = 0x303120
- 加上页表基地址,得到对应的页表项所在的虚拟地址:
0xC0C0 0000 + 0x303120 = 0xC0F0 3120
,注意,此步计算出的地址一定位于页目录中(页目录的虚拟地址范围:0xC0F0 3000
到0xC0F0 4000
) - 已知页目录的物理地址从
0x0000 8000
开始,计算偏移量可得对应的页表项存储物理地址:(0xC0F0 3120 - 0xC0F0 3000) + 0x0000 8000=0x0000 8120
- 从该物理地址读取页表项,可得到虚拟地址
0xC0C48D14
对应的物理地址,从该处读取页表项,可得到虚拟地址0x12345678
对应的物理地址,转换结束。
可以看出,虽然从本质上,使用的是一级页表,但由于页表本身位于需要进行地址转换的区域,仍然发生了两次地址转化,这相当于使用了二级页表。
事实上,页目录中的每一个页表项,正好相当于二级页表中的第一级页表的页表项。
例如,以上图中的第0xC 0C00
页为例,其是页目录中的第一个页表项,映射了虚拟 + 地址0xC0C0 0000
到0xC0C0 1000
,这个虚拟地址范围内存储了1K个页表项,映射的虚拟地址范围为4MB。相当于页目录中的一个页表项,最终对应4MB的虚拟内存空间。
事实上,对于上述地址转换过程,我们可以合并前几步:
- 第1到4步,
(((0x1234 5678 >> 12) * 4 + 0XC0C0 0000) >> 12 = 0x1234 5678 >> 22 + 0XC 0C00
,注意,0x1234 5678 >> 20
相当于取虚拟地址的高10位,与二级页表设计中第一级页表索引相同。
- 合并第4到7步,得到页内偏移,
(0x1234 5678 >> 22 + 0XC 0C00) * 4 + 0xC0C0 0000 - 0xC0F0 3000 = (0x1234 5678 >> 22) * 4 = 0x0000 0120
,可以看出,其中4 * 0XC 0C00 + 0XC0C0 0000 - 0XC0F0 3000
相互抵消,最终相当于根据一级页表索引计算出在一级页表内的偏移量。 - 加上页目录的物理地址,得到
0x0000 8000 + 0x0000 0120 = 0x0000 8120
,从该地址处可读取对应虚拟地址0xC0C48D14
的「二级页表」的物理地址。 - 由二级页表索引,即可获取到物理地址。