Bootstrap

armv7-a mmu 配置

L1 page table

​ L1 page table 将 32位内核的整个 4GB 地址空间划分为 4096 个大小相等的部分(entry),每个部分映射 1 MB 范围内的虚拟内存空间。

​ 每个条目 (entry) 可以保存指向二级转换的地址,也可以保存用于表示这 1MB 虚拟内存对应的物理内存基地址。

​ L1 转换表中的每个 entry 下的低 2 bit 表示该 entry 类型,有 4 种类型

bit0bit1说明
00fault. This can be either a prefetch data abort
10bit10 ~ bit31 point to 2 level page table
01bit20 ~ bit31 Section Base Address
01bit24 ~ bit31 Supersection Base Address

L1 page table 转换

​ 根据虚拟地址的高 12 bit (32 bit 地址)定位到 L1 page table 中的 entry number,然后计算该 entry 所在的物理地址:L1 page table addr + number * 0x4。

​ 得到 entry 的物理地址后,通过读取该地址的内容获取虚拟地址对应的物理基地址,最终确定物理地址。转换过程如下图:在这里插入图片描述

L2 page table

​ L2 与 L1 page table 一样,都需要存放到一片物理内存上,L2 table 有 256 个字大小(4字节)的 entry ,需要1KB的内存空间,并且必须与1KB的边界对齐,如果每个 entry 映射 4KB 物理内存,那么一个 L2 table 就映射 1MB 物理内存。

​ L2 page table 中的每个 entry 下的低 2 bit 表示该 entry 的类型,有 3 种类型:

bit0bit1说明
00fault:产生同步异常,可以是预取或数据中止,取决于访问类型
10laegr page: 表示该 entry 映射 64KB 的物理地址 (由于每个条目都指向 4KB 的地址空间,因此大页面条目必须重复 16 次)
XN1small page: 表示该 entry 映射 4KB 的物理地址

L2 page table 转换

​ L2 page table 的基地址需要通过 L1 page table 中的 entry 得知,就需要使用 L1 page table 中的第二个类型(用于指向 L1 page table 的物理地址)。

​ 根据虚拟地址的高 12 bit (32 bit 地址) 定位到 L1 page table 中的 entry number,然后计算该 entry 所在的物理地址:L1 page table addr + number * 0x4。然后读取出 entry 中的 L2 page table 的物理地址(entry 中的 bit10 ~ bit31)

​ 得知 L2 page table 物理地址后,根据虚拟地址的 bit12 ~ bit19 定位 L2 page table 的 entry number,然后计算出该 entry 的物理地址,该 entry 中记录了该虚拟内存对应的物理基地址,L2 page table entry 格式如下图:在这里插入图片描述

​ 如采用 small page,bit12 ~ bit31 为物理基地址,最后加上虚拟地址的 bit0 ~ bit11 (页内偏移)即为该虚拟地址对应的物理地址。

​ L2 page table 转换过程如图:在这里插入图片描述

在 rtos 中的应用

​ 系统中可以将 L1 与 L2 同时使用,对于某些地址,如外设的地址,并没有达到 1MB 连续的地址,这时候可以分为更细的粒度,如 4kb 的粒度,这时候将该 L1 entry 指向 L2 table,然后再根据虚拟地址的 bit12 - bit19 来找到 L2 的 entry,因为有 8 bit,所以最大 256。

0x2400fc00 ==> 001001000000 00001111 110000000000
    			  576		  15
通过虚拟地址的高 12bit 定位到 L1 页表第 576 号 entry, 该 entry 中记录了 L2 页表的地址,通过读取该页表的高 22 bit 就能获取到 L2 页表的地址(第 10 bit 无效,说明 L2 页表必然 1KB 地址对齐)。
    
定位到 L2 页表的地址后,再根据虚拟地址的 bit12 ~ bit19 (第 15 个 entry)来定位 L2 页表的 entry,得到 entry 后,该 4 字节的 entry 中就表示了该虚拟地址对应的物理地址,该 entry 是小页表类型,则 bit12 ~ bit31 说明了该虚拟地址对应的起始物理地址(这里有个点,低 12 bit 为 0,说明这个起始物理地址是 4KB 对齐的),得到物理地址之后 + 虚拟地址的第 12 bit。

​ 每个 L1 页表的 entry 能映射 1MB 范围的物理内存,而有时候,芯片的 memmap 可能并不是按照 1MB 来划分,比如 I2c0_base 为 0x90000000, I2c1_base 为 0x90001000,中间其他 IP 的基地址到 0x90010000 就结束了,并没有把这 1MB 完全覆盖,也就是并没有达到 0x90100000。

此时有两个策略:

  • 策略一:使用 L1 page table,直接将 0x90000000 这个地址按照 1MB 进行映射,此时 L1 page table 中的一个 entry 就能覆盖到 0x90000000 ~ 0x90100000,此时这 1MB 的内存属性是一样的,有时我们并不希望 0x90010000 ~ 0x90100000 之后的内存被访问,这时候仅使用 L1 page table 就不合适了。
  • 策略二:使用 L1 page table + L2 page table,L2 page table 能够更小粒度的映射上面的内存,让每 4KB 为一个 entry,这样子每 4KB 的内存属性是一样的。此时 L1 page table 依然是映射的 1MB,只不过这 1MB 被 L2 page table 进而分成了 256 份。

​ 其实这两种策略都是可以的,只不过第二种策略能够更精细化的管理内存,但初始化的时候略微复杂些,不过也还好了,按照手册的说明来就行了,第一种策略就较为简单粗暴了,但也无伤大雅。

page table 中的每个 entry 中还有其余 bit 可以使用,这些 bit 用来描述该 虚拟/物理 内存的属性,如是否可执行、可读、可写、cacheable、uncacheable 等。

;