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

标签 c arm armv8

根据ARM手册:

In the case of a 4kB granule, the hardware can use a 4-level look up process. The 48-bit address has nine address bits for each level translated (that is, 512 entries each), with the final 12 bits selecting a byte within the 4kB coming directly from the original address.

Bits [47:39] of the virtual address index into the 512 entry L0 table. Each of these table entries spans a 512GB range and points to an L1 table. Within that 512 entry L1 table, bits [38:30] are used as index to select an entry and each entry points to either a 1GB block or an L2 table.

Bits [29:21] index into a 512 entry L2 table and each entry points to a 2MB block or next table level. At the last level, bits [20:12] index into a 512 entry L2 table and each entry points to a 4kB block


这对我来说 100% 有意义。 L0、L1、L2 表和最终到达物理地址的偏移量。
但是,看看这个代码:https://github.com/bztsrc/raspi3-tutorial/blob/abaf5a5b2bc1a9fdfe5a9d8191c061671555da3d/10_virtualmemory/mmu.c#L66 , 解释 here :

Because we choose 4k as page size, and one translation entry is 8 bytes, that means we have 512 entries on each page. Therefore indeces 0..511 belong to the first page, 512..1023 to the second and so forth. With other words, the address of paging[0] equals to _end (first page), and paging[512] equals to _end + PAGESIZE (second page).


看起来它正在设置手册中提到的 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,直接指向 &paging[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 直接指向 &paging[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 传统上必须具有相同的值——要么全为零,要么全为 1。这可以在控制寄存器中放松,但无论如何,位 63 选择 TTBR[01] 中的哪一个将用于选择两个 L0 页表集之一。
传统上,每个进程都有自己的 TTBR0,内核将有一个 TTBR1 用于所有进程[因此不需要更改]。

关于c - ARMv8a 中的这种简单分页是如何工作的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64843803/

相关文章:

arrays - ARM 汇编数组

gcc - ARM-SVE : wrapping runtime sized register

linux - 拉取与 CPU 架构无关的 Docker 镜像

arm - ARMv8汇编中的MOV,MOVZ,MOVN和MOVK有什么区别?

c - 在嵌入式 C 中查找最接近给定值的多维数组中的值

c - 在 C 中释放特定类型的内存分配

linux-kernel - ARMv8 AARCH64 指令中止处理程序?

c - 如何在基于 arm 的平台上调试随机数据中止问题

c - 以编程方式获取 Linux 上的代理信息

c - 在 Windows XP 上 system() 调用返回 "Permission Denied"