xv6页表
一级页表
地址64bit。虚拟地址使用low39位,物理地址使用low56位。
虚拟地址的low39中,高27位是index,用来索引页表中的具体"一行"页表项。一个页表项在物理内存中是4096Byte,offset用来索引具体一个Byte。
物理地址的low56中,高44位是物理页号(PPN),低12位等同于虚拟地址中的offset的12位。
这段地址翻译过程中,虚拟地址的27位用来在页表中索引一个页表项,找到页表项后,可以从中读到44位的PPN,直接对应了物理地址中的44位。然后使用虚拟地址的offset12位,来索引具体的一个Byte。
在这个一级页表设计中,存储页表所需要的物理空间是(2^27)*(64bit)=2^27*8B = 128*8MB= 1G
。那么系统中每一个进程都需要1G的物理空间来存储这张页表,以进行虚拟地址对物理地址的转换。
三级页表
在三级页表的设计中,虚拟地址的index被分为3级。最高的一级(9位)用来索引第一级页表,第一级页表在物理内存中存储的地址写在寄存器satp中。从第一级页表中索引到ppn后,可以直接找到第二级页表在物理内存中的位置,再用中间的9bit来索引第二级页表中的页表项。
例如,如果只为了映射一个物理地址时,这种三级页表的方式,只需要在物理内存中存储三张页表,分别对应这张图中的三张页表。因为每一级页表只要找到相应的ppn就行了,所以只需要这3级ppn被存储的页表。那么每张页表的物理空间占用为2^9*64bit=512*8B=4KB
,三张页表总共占用12KB。相比之前一级页表的设计,同样为了映射一个物理地址,此时一个进程只需要12KB,之前需要1G。
问题记录
Q1
无论几级页表,在页表中都有一个flag的表示,就是把每一个页表项的低10位用来表示flag。具体flag的含义可见【三级页表图】中的位表示。一般是读写权限、有效性等等。
Q2
三级页表设计中,后两级页表是通过ppn来索引的,那么offset呢?下面这段文字回答了这个问题,答案就是offset设置位0,因为三级页表中,一个页表是4KB,对应了一个页表项的大小,那么这时就不需要offset来索引具体的Byte了,直接从页表项的开头读就行。
Q3
课程中有这样一个例子:
第2行中..0
表示第一级页表中的pte索引是0,..
表示这是第一级。pte 0x000...0021fff801
表示这个pte的64bit所存储的数据。这其中包含了44bit的ppn和10bit的flag。pa 0x00...0087ffe000
表示的是对应的物理地址。因为物理地址是由44bit的ppn和12bit的offset组成。这里就可以验证一下,这个pa中的ppn和pte中的ppn是完全相同的。需要把pte右移10bit,然后转换成0b表示,pa右移12bit,然后转换成0b表示。是完全相同的
观察第1/2级页表项对应的pa,这些pa的最低12bit都是0x000,第一级页表项对应的pa中offset用来索引第二级页表的物理位置,第二级页表项对应的pa中offset用来索引第三级页表的物理位置。根据Q2中的分析,就知道这些offset为啥是0x000了。
接下来,这里用0x10000000
这个pa来右移12bit,得到了虚拟地址的27bit index。这个表述成立的原因是:
在xv6中,将部分物理地址映射到了相同的虚拟地址中。见下:
在memlayout.h中定义了物理地址
根据下图,物理地址直接映射到虚拟地址,所以uart0的虚拟地址也会是0x10000000
在看这个kvmmap的函数声明,第二个参数是va,第三个参数是pa。分别表示虚拟地址和物理地址。所以,虚拟地址uart0对应到物理地址uart0。并且UART0
被define成0x10000000
所以,uart0的虚拟地址和物理地址都是0x10000000了,这样之前把pa右移12bit得到27bit的index就成立了。