c-在ARMv8a中这个简单的分页是如何工作的



根据ARM手册:

在4kB颗粒的情况下,硬件可以使用4级查找过程48位地址每级有9个地址位已翻译(即,每个512个条目(,最后12位在直接来自原件的4kB内选择一个字节住址

虚拟地址索引的比特[47:39]进入512条目L0表。这些表条目中的每一个都跨越512GB的范围,并指向L1桌子在512条目L1表中,位[38:30]用作索引选择一个条目,每个条目指向1GB块或L2表。

Bits[29:21]索引到512个条目的L2表中,并且每个条目指向2MB块或下一个表级别。在最后一级,bits[20:12]索引进入512条目的L2表,并且每个条目指向4kB块

这对我来说是100%有意义的。L0、L1、L2表和到达物理地址的最终偏移量。

但是,请查看以下代码:https://github.com/bztsrc/raspi3-tutorial/blob/abaf5a5b2bc1a9fdfe5a9d8191c061671555da3d/10_virtualmemory/mmu.c#L66,在此解释:

因为我们选择4k作为页面大小,并且一个翻译条目是8字节,这意味着我们在每页上有512个条目。因此indeces0..511属于第一页,512..1023属于第二页,依此类推。换句话说,分页[0]的地址等于_end(首先页面(,并且分页[512]等于_end+PAGESIZE(第二页面(。

看起来它正在设置手册中提到的L0、L1和L2。因此,前512个条目是L0表的条目,513-1024个条目是L1,1025-1536个条目是L2表。

然而,在代码中,它开始这样做:

paging[4*512+511]=(unsigned long)((unsigned char*)&_end+5*PAGESIZE) |   // physical address
PT_PAGE |     // we have area in it mapped by pages
PT_AF |       // accessed flag
PT_KERNEL |   // privileged
PT_ISH |      // inner shareable
PT_MEM;       // normal memory

索引4*512+511 = 2559远远超过了我想象的L2表。我想我误解了一些非常错误的东西!

paging[0]paging[511]是否应该跨越第一个表(L0(,然后paging[512]paging[2013]是否应该跨越第二个表(L1(,paging[1024]paging[2559]是否应该跨越最后一个表(L2(?

r<<21r*PAGESIZE是什么意思?

有两个表,由TTBR0和TTBR1指向。

第一个,TTBR0,直接指向&分页[0],并形成L0、L1、L2页面继承:

Paging[0] points at &paging[512*2]
Paging[512*2] points at &paging[512*3]
Paging[512*3..512*3+511] contains page descriptors for physical memory at 0..200000.

附加

Paging[512*2+1..512*2+511] contains large descriptors for physical memory at 400000..40000000

第二个(内核(,TTBR1,直接指向&分页[512],形成类似的L0、L1、L2继承:

Paging[512+511] points at &paging[512*4]
Paging[512*4+511] points at &paging[512*5]
Paging[512*5] contains a descriptor for MMIO_BASE+0x201000.

第二个集合偏移到每个表的第511个描述符的原因是使它处于非常高的地址。

虚拟地址解码由转换控制寄存器的T1SZ选择;它被注释为3个级别或39位的虚拟寻址:12位偏移和表索引的27位(9位*3级(。

地址位63..40传统上必须具有相同的值——要么全为零,要么全为一。这可以在控制寄存器中放松,但不管怎样,位63都会选择TTBR[01]中的哪一个将用于选择两个L0页表集之一。

传统上,每个进程都有自己的TTBR0,内核将有一个用于所有进程的TTBR1[因此不必更改]。

最新更新