启动 ARM Linux¶
作者:Russell King
日期:2002 年 5 月 18 日
以下文档与 2.4.18-rmk6 及更高版本相关。
为了启动 ARM Linux,您需要一个引导加载程序,它是一个在主内核之前运行的小程序。引导加载程序应该初始化各种设备,并最终调用 Linux 内核,将信息传递给内核。
本质上,引导加载程序应(至少)提供以下内容:
设置和初始化 RAM。
初始化一个串行端口。
检测机器类型。
设置内核标记列表。
加载 initramfs。
调用内核镜像。
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 物理地址查找 dtb 魔术值 0xd00dfeed,以确定是否传递了 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(特权内核模式)配置。此外,必须禁用所有进入虚拟机管理程序的中断,并且必须为所有外围设备和 CPU 资源授予 PL1 访问权限,如果架构上允许这样做。除了进入 HYP 模式外,系统配置应使得不包含对虚拟化扩展支持的内核可以正确启动,而无需额外帮助。
引导加载程序应通过直接跳转到内核镜像的第一条指令来调用内核镜像。
在支持 ARM 指令集的 CPU 上,即使对于 Thumb-2 内核,也必须在 ARM 状态下进行输入。
在仅支持 Thumb 指令集(例如 Cortex-M 类 CPU)的 CPU 上,必须在 Thumb 状态下进行输入。