启动 ARM Linux

作者:Russell King

日期:2002 年 5 月 18 日

以下文档与 2.4.18-rmk6 及更高版本相关。

要启动 ARM Linux,您需要一个引导加载程序,它是一个在主内核之前运行的小程序。引导加载程序应初始化各种设备,并最终调用 Linux 内核,并将信息传递给内核。

本质上,引导加载程序应提供(至少)以下内容

  1. 设置和初始化 RAM。

  2. 初始化一个串口。

  3. 检测机器类型。

  4. 设置内核标记列表。

  5. 加载 initramfs。

  6. 调用内核镜像。

1. 设置和初始化 RAM

现有引导加载程序

强制性

新引导加载程序

强制性

引导加载程序应找到并初始化内核将用于系统中易失性数据存储的所有 RAM。它以机器相关的方式执行此操作。(它可以使用内部算法自动定位和调整所有 RAM 的大小,或者可以使用机器中 RAM 的知识,或者引导加载程序设计者认为合适的任何其他方法。)

2. 初始化一个串口

现有引导加载程序

可选,推荐

新引导加载程序

可选,推荐

引导加载程序应初始化并启用目标上的一个串口。这允许内核串口驱动程序自动检测它应该使用哪个串口作为内核控制台(通常用于调试目的或与目标通信。)

作为替代方案,引导加载程序可以通过标记列表将相关的“console=”选项传递给内核,指定端口和串口格式选项,如中所述

3. 检测机器类型

现有引导加载程序

可选

新引导加载程序

强制性,除非是仅使用 DT 的平台

引导加载程序应通过某种方法检测其运行的机器类型。这是否是一个硬编码值,或者是一些查看连接硬件的算法,都超出了本文档的范围。引导加载程序最终必须能够为内核提供 MACH_TYPE_xxx 值。(参见 linux/arch/arm/tools/mach-types)。这应该在寄存器 r1 中传递给内核。

对于仅使用 DT 的平台,机器类型将由设备树确定。将机器类型设置为全 1 (~0)。这不是绝对必要的,但可以确保它不会匹配任何现有类型。

4. 设置引导数据

现有引导加载程序

可选,强烈推荐

新引导加载程序

强制性

引导加载程序必须提供标记列表或 dtb 镜像,用于将配置数据传递给内核。引导数据的物理地址在寄存器 r2 中传递给内核。

4a. 设置内核标记列表

引导加载程序必须创建并初始化内核标记列表。有效的标记列表以 ATAG_CORE 开头,以 ATAG_NONE 结尾。ATAG_CORE 标记可能为空,也可能不为空。一个空的 ATAG_CORE 标记的大小字段设置为 ‘2’ (0x00000002)。ATAG_NONE 必须将大小字段设置为零。

任何数量的标签都可以放在列表中。重复的标签是否附加到先前标签携带的信息,或者是否完全替换信息是未定义的;一些标签的行为就像前者,另一些标签的行为就像后者。

引导加载程序必须至少传递系统内存的大小和位置,以及根文件系统的位置。因此,最小的标记列表应该如下所示

              +-----------+
base ->       | ATAG_CORE |  |
              +-----------+  |
              | ATAG_MEM  |  | increasing address
              +-----------+  |
              | ATAG_NONE |  |
              +-----------+  v

标记列表应存储在系统 RAM 中。

标记列表必须放置在内核解压缩器或 initrd “bootp” 程序都不会覆盖的内存区域中。建议的放置位置是 RAM 的前 16KiB。

4b. 设置设备树

引导加载程序必须将设备树镜像 (dtb) 加载到系统 ram 中,地址为 64 位对齐,并使用引导数据对其进行初始化。dtb 格式的文档位于 https://www.devicetree.org/specifications/. 内核将查找 dtb 物理地址处的 0xd00dfeed 的 dtb 魔术值,以确定是否已传递 dtb 而不是标记列表。

引导加载程序必须至少传递系统内存的大小和位置,以及根文件系统的位置。dtb 必须放置在内核解压缩器不会覆盖它的内存区域中,同时保持在内核低内存映射覆盖的区域内。

一个安全的位置是 RAM 起始位置上方 128MiB 边界的正上方。

5. 加载 initramfs。

现有引导加载程序

可选

新引导加载程序

可选

如果正在使用 initramfs,那么与 dtb 一样,它必须放置在内核解压缩器不会覆盖它的内存区域中,同时也要位于内核低内存映射覆盖的区域中。

一个安全的位置是设备树 blob 正上方,设备树 blob 本身将被加载到如上推荐的 RAM 起始位置上方 128MiB 边界的正上方。

6. 调用内核镜像

现有引导加载程序

强制性

新引导加载程序

强制性

有两种调用内核 zImage 的选项。如果 zImage 存储在闪存中,并且已正确链接以从闪存运行,则引导加载程序可以直接调用闪存中的 zImage。

zImage 也可以放置在系统 RAM 中并在那里调用。内核应放置在 RAM 的前 128MiB 中。建议将其加载到 32MiB 以上,以避免在解压缩之前需要重新定位,这将使启动过程稍微快一些。

当启动原始(非 zImage)内核时,约束更严格。在这种情况下,必须将内核加载到系统中的一个偏移量,该偏移量等于 TEXT_OFFSET - PAGE_OFFSET。

在任何情况下,都必须满足以下条件

  • 停止所有具有 DMA 功能的设备,以避免内存被错误的网络数据包或磁盘数据损坏。这将为您节省许多调试时间。

  • CPU 寄存器设置

    • r0 = 0,

    • r1 = 在上述 (3) 中发现的机器类型编号。

    • r2 = 系统 RAM 中标记列表的物理地址,或系统 RAM 中设备树块 (dtb) 的物理地址

  • CPU 模式

    必须禁用所有形式的中断(IRQ 和 FIQ)

    对于不包含 ARM 虚拟化扩展的 CPU,CPU 必须处于 SVC 模式。(Angel 存在一个特殊例外)

    包含虚拟化扩展支持的 CPU 可以进入 HYP 模式,以便内核可以充分利用这些扩展。这是此类 CPU 的推荐启动方法,除非虚拟化已被预安装的虚拟机监控程序使用。

    如果内核由于任何原因未进入 HYP 模式,则必须进入 SVC 模式。

  • 缓存,MMU

    MMU 必须关闭。

    指令缓存可以打开或关闭。

    数据缓存必须关闭。

    如果内核以 HYP 模式进入,则上述要求适用于 HYP 模式配置以及普通的 PL1(特权内核模式)配置。此外,必须禁用所有进入虚拟机监控程序的陷阱,并且必须授予 PL1 对所有外围设备和 CPU 资源的访问权限,只要在架构上可行。除了进入 HYP 模式外,系统配置应使不包含虚拟化扩展支持的内核可以在没有额外帮助的情况下正确启动。

  • 引导加载程序应通过直接跳转到内核镜像的第一个指令来调用内核镜像。

    在支持 ARM 指令集的 CPU 上,即使对于 Thumb-2 内核,也必须在 ARM 状态下进行输入。

    在仅支持 Thumb 指令集的 CPU 上,例如 Cortex-M 类 CPU,必须在 Thumb 状态下进行输入。