Bootstrap

17-Translation (XLAT) Tables Library

引流关键词: 中断、同步异常、异步异常、irq、fiq、BL1,BL2,BL3,BL31,BL32,BL33,AP_BL1,AP_BL2,AP_BL3,AP_BL31,AP_BL32,AP_BL33,SCP_BL1,SCP_BL2,BL0,BL30, optee、ATF、TF-A、Trustzone、optee3.14、MMU、VMSA、cache、TLB、arm、armv8、armv9、TEE、安全、内存管理、页表…

快速链接:
.
👉👉👉 个人博客笔记导读目录(全部) 👈👈👈


[专栏目录]-ATF/FF-A/specification学习


17.翻译(XLAT)表库

本文档描述了 Trusted Firmware-A (TF-A) 使用的转换表库(版本 2)的设计。该库提供 API 以根据内存布局的描述创建页表,以及设置与内存管理单元 (MMU) 相关的系统寄存器并执行所需的转换后备缓冲区 (TLB) 维护操作。

更具体地说,该库旨在支持的一些用例是:

  • (1) 根据内存布局的描述静态分配转换表并填充它们(在运行时)。内存布局通常由平台端口作为内存区域列表提供;

  • (2) 支持生成与库代码执行的异常级别不同的翻译制度相关的翻译表;

  • (3) 支持动态映射和取消映射区域,即使在 MMU 开启时也是如此。这可用于临时映射一些内存区域,并在以后不再需要时取消映射它们;

  • (4) 支持非身份的虚拟到物理的映射来压缩虚拟地址空间;

  • (5) 支持在运行时更改内存区域的内存属性。

17.1. 关于版本 1、版本 2 和 MPU 库

本文档重点介绍该库的第 2 版,其源代码可在lib/xlat_tables_v2目录中找到。仍然可以在lib/xlat_tables目录中找到该库的版本 1,但它的灵活性较低并且不支持动态映射。lib/xlat_mpu,它等效地配置了 Arm 的 MPU,也在这里解决。这lib/xlat_mpu是实验性的,这意味着它的 API 可能会改变。它目前致力于与 xlat_tables_v2 保持一致性和代码重用。未来的版本可能更特定于 MPU(例如,删除所有提及的虚拟地址)。尽管潜在的错误修复将应用于所有版本的 xlat_* 库,但未来的功能增强将集中在版本 2 上,可能不会向后移植到版本 1 和 MPU 版本。因此,建议使用版本 2,尤其是对于新平台端口(除非平台使用 MPU)。

但是,请注意,版本 2 和 MPU 版本仍在积极开发中,尚未被认为是稳定的。因此,可能会引入兼容性中断。

从此时起,除非另有说明,否则本文档将隐含引用该库的第 2 版。

17.2. 设计概念和界面

本节介绍翻译表库中使用的一些关键概念和数据结构。

17.2.1. 映射区域

Anmmap_region是一种抽象、简洁的方式来表示要映射的内存区域。它是图书馆的关键接口之一。它通过以下方式识别:

  • 它的物理基地址;

  • 它的虚拟基地址;

  • 它的大小;

  • 它的属性;

  • 其映射粒度(可选)。

请参阅 中的类型。struct mmap_regionxlat_tables_v2.h

用户通常会提供要映射的此类 mmap 区域的列表,并让库将其转置到一组翻译表中。因此,图书馆可能会创建新的翻译表,更新或拆分现有的翻译表。

区域属性指定内存的类型(例如设备或缓存的普通内存)以及内存访问权限(只读或读写、可执行与否、安全或非安全等)。在 EL1&0 转换机制的情况下,属性还指定区域是用户区域 (EL0) 还是特权区域 (EL1)。请参阅 中的MT_xxx定义xlat_tables_v2.h。请注意,对于 EL1&0 转换机制,EL1 和 EL0 同时设置 Execute Never 属性。

粒度控制映射区域时要下降到的转换表级别。例如,假设 MMU 已配置为使用 4KB 粒度,则库可能使用以下两个选项之一映射 2MB 内存区域:

  • 使用单个 2 级转换表条目;

  • 使用 2 级中间条目到 3 级转换表(包含 512 个条目,每个映射 4KB)。

第一个解决方案可能需要更少的转换表,因此可能需要更少的内存。但是,如果这个 2MB 区域的一部分稍后被重新映射为不同的内存属性,则库可能需要拆分现有的页表以优化映射。如果这里使用了一个 2 级条目,则需要动态分配一个 3 级表,并将 2 级修改为指向这个新的 3 级表。这在运行时会产生性能成本。

如果用户预先知道可能会发生这样的重新映射操作,那么他们可能会从一开始就为这个 2MB 区域强制执行 4KB 映射粒度;动态地重新映射其中一些 4KB 页面就变成了轻量级操作。

区域的粒度是一个可选字段;如果未指定,则库将选择该区域的映射粒度,因为它认为合适(更多详细信息可以在下面的内存映射算法部分找到)。

MPU 库也用于指定翻译,但 MPU 的翻译仅限于指定有效地址和访问权限。如果请求的虚拟地址和物理地址不匹配,系统将出现紧急情况。作为基于寄存器的确定性内存引用时序,MPU 硬件不涉及内存驻留转换表。struct mmap_region

目前,MPU 库也仅限于 EL2 的 MPU 翻译,其他 EL 没有 MMU 翻译。然而,这些限制有望在未来的库版本中得到克服。

17.2.2. 翻译语境

库可以创建或修改与库代码正在执行的异常级别不同的翻译机制有关的翻译表。例如,EL3 软件(例如 BL31)可能使用该库来创建与 S-EL1&0 翻译机制相关的翻译表。

这种灵活性来自于翻译上下文的使用。翻译上下文构成了图书馆用来跟踪给定翻译制度的一组翻译表的状态的信息的超集。

该库在内部分配了一个默认翻译上下文,该上下文与当前异常级别的翻译机制有关。可以使用 REGISTER_XLAT_CONTEXT()宏显式分配和初始化其他上下文。提供了单独的 API 以作用于默认翻译上下文或替代上下文。

要注册翻译上下文,用户必须向图书馆提供以下信息:

  • 一个名字。
    生成的翻译上下文变量将在此名称之后调用,_xlat_ctx并附加到该名称。例如,如果宏名称参数为 foo,则上下文变量名称将为foo_xlat_ctx。

  • 要映射的最大mmap区域数。
    如果适用,应考虑静态和动态区域。

  • 要分配的子翻译表的数量。
    要为此上下文静态分配的转换表的数量,不包括始终分配的初始查找级别转换表。例如,如果初始查找级别为 1,则此参数将指定要为此上下文预分配的级别 2 和级别 3 转换表的数量。

  • 虚拟地址空间的大小。
    使用此上下文映射的虚拟地址空间的大小(以字节为单位)。这将顺便确定初始查找级别转换表中的条目数:库将分配映射整个虚拟地址空间所需的条目数。

  • 物理地址空间的大小。
    使用此上下文映射的物理地址空间的大小(以字节为单位)。

默认翻译上下文是使用来自平台特定定义的(大部分)信息在内部初始化的:

  • 名称:硬编码为tf;因此默认上下文变量的名称是 tf_xlat_ctx;

  • mmap区域的数量: MAX_MMAP_REGIONS;

  • 子翻译表的数量:MAX_XLAT_TABLES;

  • 虚拟地址空间的大小:PLAT_VIRT_ADDR_SPACE_SIZE;

  • 物理地址空间的大小:PLAT_PHY_ADDR_SPACE_SIZE.

  • 有关这些宏的更多详细信息,请参阅移植指南。

17.2.3. 静态和动态内存区域

该库可选择支持动态内存映射。可以使用PLAT_XLAT_TABLES_DYNAMIC平台构建标志启用此功能。

启用动态内存映射后,库将 mmap 区域分类为 static或dynamic。

  • 静态区域在系统的生命周期内是固定的。它们只能在创建和填充转换表之前尽早添加。之后无法删除它们。

  • 可以随时添加或删除动态区域。

禁用动态内存映射功能时,仅存在静态区域。

动态内存映射特征可用于映射和取消映射瞬态内存区域。当用户需要在固定的时间段内访问某些内存时,这很有用,之后内存可能会被丢弃和回收。例如,仅在系统初始化时启动时才需要的内存区域,或者在正常世界和可信世界之间临时共享内存缓冲区。请注意,由调用者确保在添加或删除区域时不会同时访问这些区域。

尽管此功能提供了某种程度的动态内存分配,但这不允许在任意内存位置动态分配任意数量的内存。用户仍然需要在编译时声明这些分配的限制;库将拒绝任何不适合此预分配内存池的映射请求。

17.3. 库 API

此库公开的外部 API 在 xlat_tables_v2.h头文件中声明和记录。这应该是获取有关此库提供的不同 API 的使用信息的参考点。本节仅提供一些额外的细节和说明。

尽管mmap_region结构是公开可见的类型,但不建议手动填充这些结构。相反,只要 API 需要 type 的函数参数mmap_region_t,就应该使用MAP_REGION*()辅助宏系列来构造它们。这是为了限制兼容性中断的风险,如果mmap_region结构类型在未来发展。

和宏不允许指定映射粒度,这使库实现可以自由选择它MAP_REGION()。MAP_REGION_FLAT()但是,在需要特定粒度的情况下, MAP_REGION2()可能会使用宏。强烈MAP_REGION_FLAT()建议仅用于定义 MPU 库的区域。

如本文档前面所述,当禁用动态映射功能时,没有动态区域的概念。从概念上讲,只有静态区域。出于这个原因(并保持与库版本 1 的向后兼容性),映射静态区域的 API 不会在其函数名称中嵌入单词static(例如mmap_add_region()),与动态区域 API(例如 mmap_add_dynamic_region())相反.

虽然静态和动态区域的定义不是基于 MMU 的状态,但两者在某种程度上还是有关联的。静态区域只能在init_xlat_tables()调用之前添加,并且init_xlat_tables()必须在 MMU 仍然关闭时调用。因此,一旦启用 MMU,就无法添加静态区域。可以在 MMU 打开或关闭时添加动态区域。在实践中,通常的调用流程如下所示:

  • (1) MMU 最初是关闭的。

  • (2) 添加一些静态区域,添加一些动态区域。

  • (3) 根据 mmap 区域列表(使用init_xlat_tables*()API 之一)初始化转换表。

  • (4) 此时,不再可能添加静态区域。仍然可以添加或删除动态区域。

  • (5) 启用 MMU。

  • (6) 可以继续添加或删除动态区域。

因为静态区域是在启动时早期添加的,并且都在平台初始化代码的控制之下,所以mmap_add*()API 系列不会失败。它们不返回任何错误代码。

尽管如此,这些 API 会在更新翻译上下文结构之前预先检查是否可以成功添加区域。如果库检测到没有足够的内存来满足请求,或者新区域将以无效的方式与另一个区域重叠,或者遇到任何其他意外错误,它们将在 UART 上打印错误消息。此外,当启用断言时(通常在调试版本中),将触发断言。否则,函数调用将立即返回,而不会添加有问题的内存区域。

17.4. 库限制

动态区域不允许相互重叠。只要其中一个完全包含在另一个静态区域中,就允许静态区域重叠。这允许与库版本 1 中的先前行为向后兼容。

17.5。实施细节

17.5.1. 代码结构

该库分为4个模块:

  • 核心模块

提供库的主要功能,例如翻译表上下文的初始化和映射/取消映射内存区域。该模块提供了一些功能,例如mmap_add_region_ctx让调用者指定受它们影响的翻译表上下文。

见xlat_tables_core.c。

  • 活动上下文模块

实例化当前 BL 图像使用的上下文,并提供帮助器来操作它,将其从其余代码中抽象出来。该模块提供mmap_add_region了直接影响使用它们的 BL 图像的功能。

见xlat_tables_context.c。

  • 实用程序模块

提供附加功能,如翻译表当前状态的调试打印和帮助查询内存属性并修改它们。

见xlat_tables_utils.c。

  • Architectural module

提供依赖于当前执行状态(AArch32/AArch64)的函数,例如用于 TLB 失效、设置 MMU 或计算物理地址空间大小的函数。他们不需要翻译上下文来工作。

见aarch32/xlat_tables_arch.c和aarch64/xlat_tables_arch.c。

17.5.2. 从 mmap 区域到转换表

翻译上下文包含一个列表mmap_region_t,其中包含在任何给定时间映射的所有区域的信息。每当有映射(resp. unmap)内存区域的请求时,它都会被添加到(resp. 从)mmap_region_t列表中。

mmap 区域列表是一种表示内存布局的概念方式。在某些时候,库必须将此信息转换为实际的翻译表以编程到 MMU 中。

在init_xlat_tables()调用 API 之前,该库仅作用于 mmap 区域列表。此时通过其中一个mmap_add*()API 添加静态或动态区域不会以任何方式影响转换表,它们只会在内部 mmap 区域列表中注册。只有当用户调用时init_xlat_tables(),翻译表才会根据迄今为止注册的 mmap 区域列表填充到内存中。这是一项优化,允许一次性创建初始转换表集,而不必在 MMU 禁用时每次都编辑它们。

调用 API后init_xlat_tables(),只能添加动态区域。对转换表(以及 mmap 区域列表)的更改将立即生效。

17.5.3. 内存映射算法

映射函数被实现为递归算法。然而,它受转换表深度级别的限制(Armv8-A 架构允许多达 4 个查找级别)。

默认情况下1,该算法将尝试最小化为满足用户请求而创建的转换表的数量。它将倾向于使用尽可能大的块来映射区域,仅在绝对必要时才创建子表。这是为了减少固件的内存占用。

需要子表的最常见原因是特定映射需要更精细的粒度。未对齐的区域还需要比用户最初预期的更精细的粒度,使用比预期更多的内存。原因是所有级别的转换都被限制为与该级别的块大小相同粒度的地址转换。例如,对于 4 KiB 的页面大小,2 级块条目最多只能转换为 2 MiB 的粒度。如果物理地址未与 2 MiB 对齐,则还需要额外的 3 级表。

请注意,并非每个翻译级别都允许任何类型的描述符。根据页面大小,转换的级别 0 和 1 可能只允许表描述符。如果一个块条目能够描述翻译,但该级别不允许块描述符,则必须使用表描述符以及下一级的附加表。

对齐示例

mmap 区域的排序方式简化了映射它们的代码。尽管这种排序仅对重叠的静态区域严格需要,但它也必须应用于动态区域以始终保持所有区域的一致顺序。在映射每个新区域时,会检查转换表中的现有条目以确保一致性。使用的排序算法的更多细节请参考核心模块源码中的注释。

此映射算法不适用于 MPU 库,因为 MPU 硬件直接通过“基”和“限制”(底部和顶部)地址映射区域。

17.5.4. TLB 维护操作

该库负责在需要时执行 TLB 维护操作。例如,当用户请求删除动态区域时,库使与该区域关联的所有 TLB 条目无效,以确保这些更改对使用更改的转换表条目的后续执行(包括推测执行)可见。

一个反例是转换表的初始化。在这种情况下,不需要显式的 TLB 维护。Armv8-A 架构保证所有 TLB 都在复位时被禁用,并且它们的内容对复位2时的地址转换没有影响。因此,TLB 失效被推迟到enable_mmu*()函数族,就在 MMU 开启之前。

关于启用和禁用内存管理,对于 MPU 库,为了减少混淆,调用以启用或禁用 MPUmpu在其名称中使用代替mmu. 例如,enable_mmu_el2()呼叫更改为 enable_mpu_el2()。

添加动态区域时也不需要 TLB 失效。动态区域不允许与现有内存区域重叠。因此,如果动态映射请求被认为是合法的,它会自动关注未在此转换机制中映射的内存,并且库会将其相应的转换表条目初始化为无效描述符。鉴于 TLB 在架构上不允许保存任何无效的转换表条目3,这意味着该映射不能缓存在 TLB 中。

;