Lazy loaded image[转载]ARM64 内存管理二:创建启动阶段的页表
2023-8-22
| 2023-8-22
字数 2692阅读时长 7 分钟
type
status
date
slug
summary
tags
category
icon
password
URL
< 上一篇中,已经介绍了 stext 宏的preserve_boot_args el2_setup set_cpu_boot_mode_flag __vet_fdt函数,其中
  • preserve_boot_args函数主要任务是按 arm64 规范,在 x0-x3 寄存器中存入 dtb pa 还有 0;并初始化 boot_args 地址段
  • el2_setup:重置 sctlr_elx 寄存器,确定 CPU 处于哪个 exception level, ….. 待补充
  • set_cpu_boot_mode_flag:保存 exception level 到全局变量__boot_cpu_mode,以便系统启动后使用
  • __vet_fdt:校验 fdt 是否符合 arm64 规范要求,见 document/boot.txt 要求

本文场景前提:

ARM64,VA 是 48 bit,page size 是 4K===》在地址映射过程中,地址被分成 9(level 0) + 9(level 1) + 9(level 2) + 9(level 3) + 12(page offset)
主要描述 ARM64 启动过程中,如何建立初始化阶段页表,以便在打开 MMU 后能正确执行 linux 内核代码;场景前提:ARM64,VA 是 48 bit,page size 是 4K
在一般程序中,要想内核执行我们的一个程序,我们只要告知内核 2 个东西即可:1. 代码地址及长度;2. 程序参数地址及长度;linux kernel 就是一个特殊的程序,因此在打开 MMU 前,我们得先准备好打开 MMU 后,Linux image 地址及长度,传入 kernel 的参数地址及长度
因此在初始化阶段,我们需要 mapping 三段地址
  • identify mapping: 把物理地址直接 mapping 到物理地址上,仅仅为了解决 cpu pipeline 机制对于 MMU 打开前后的冲击,具体可以查看 arm 手册说明
  • kernel image mapping: 准备好 MMU 打开后 linux image 地址
  • blob memory mapping: 准备好 MMU 打开后 dtb 参数地址
< 以下均以 ARM64, 48bit 为例,位宽由#define VA_BITS (CONFIG_ARM64_VA_BITS)配置

虚拟地址空间布局

参考linux-4.1.10\Documentation\arm64memory.txt

翻译过程

  1. 通过虚拟地址最高位确定属于 userspace 还是 kernel space,从而分别选择 TTBR0_EL1 或者 TTBR1_EL1;该寄存器保存了 PGD 基地址,PGD 中每个 entry 都是描述符,可能是 table descriptor, block descriptor, page descriptor,可以根据 entry 中标志位确认
  1. 如果是 block descriptor, 翻译就结束了;否则指向下一节的 translation table(PUD), 同理……

section mapping

ARM64_SWAPPER_USES_SECTION_MAPS宏定义了 swapper/idpmap 是否使用 section map;什么是 section mapping?
我们用一个实际的例子来描述。假设 VA 是 48 bit,page size 是 4K,那么,在地址映射过程中,地址被分成 9(level 0) + 9(level 1) + 9(level 2) + 9(level 3) + 12(page offset),对于 kernel image 这样的 big block memory region,使用 4K 的 page 来 mapping 有点得不偿失,在这种情况下,可以考虑让 level 2 的 Translation table entry 指向一个 2M 的 memory region,而不是下一级的 Translation table。所谓的 section map 就是指使用 2M 的为单位进行映射。
当然,不是什么情况都是可以使用 section map,对于 kernel image,其起始地址是 2M 对齐的,因此 block size 是 2M 的情况下才 OK,对于 PAGE SIZE 是 16K,其 Block descriptor 指向了一个 32M 的内存块,PAGE SIZE 是 64K 的时候,Block descriptor 指向了一个 512M 的内存块,因此,只有 4K page size 的情况下,才可以启用 section map。

代码分析__create_page_tables

以 48bit(9+9+9+9+12),Page size 为 4K 为例,如果是 seciton map, PGD(Level 0)、PUD(Level 1)、PMD(Level 2) 的 translation table 中的 entry 都是 512 项,每个描述符是 8 个 byte,因此这些 translation table 都是 4KB,恰好是一个 page size; 共 3page size

参考文献

http://www.wowotech.net/armv8a_arch/create_page_tables.html

附录

  • 内存管理
  • 高通平台dtbo揭秘[转载]ARM64 内存管理三:MMU 前 CPU 初始化及打开 MMU
    Loading...