ROM代码如何找到u-boot启动指令

How u-boot start instruction is found by ROM Code

我正在尝试了解 ARM Linux 启动过程。

这些是我的理解:

我的问题是这个 Boot ROM 代码如何获取 u-boot 第一条指令的地址?

这取决于 SoC,用于引导的方案因 SoC 而异。它通常记录在 SoC 的参考手册中,并且它确实描述了各种约定(从哪里读取 u-boot,具体地址)该 SoC 特定的 u-boot 端口应该遵循以便代码ROM 能够加载 u-boot,并最终将控制权转移到 u-boot。

ROM 中的这段代码可以执行如下操作:
- 如果引脚 x 为 0,从 eMMC 的第一个扇区读取 64KiB 到片上静态 RAM,然后将控制转移到位于 OCRAM 偏移量 256 处的代码例如。
- 如果引脚 x 为 1,将 UART 配置为 19200 波特、8 位奇偶校验、无停止位,尝试使用 X-MODEM 协议从串行端口读取 64KiB 到 OCRAM,然后将控制转移到位于 OCRAM 偏移量 256 处的代码。

此代码通常称为辅助程序加载器 (SPL),然后负责配置 SDRAM 控制器,然后将u-boot的non-SPL部分读入SDRAM的开头,然后跳转到SDRAM中的特定地址。给定 SoC 的 SPL 应该足够小以适合 SoC 片上 RAM。在这种情况下,ROM 代码将是主引导加载程序。

以 TI AM335x Cortex-A8 SoC 为例,Technical Reference Manual, and more specifically figure 26-10, explains the boot process. Some input pins may be used by the ROM code to direct the boot process - see SYSBOOT Configuration Pins in table 26-7. See The AM335x U-Boot User's Guide 的第 26.1.6 节提供更多 u-boot 具体的 AM335x 相关信息。

ARM 不制造芯片,它制造芯片供应商购买的 IP。这是他们芯片设计中的一个块,通常他们有许多其他块,usb 控制器(可能购买的 ip),pcie 控制器(可能购买的 ip),ddr,以太网,sata,emmc/sd,等等。加上胶合逻辑,再加上无论他们的秘诀是什么,他们都会添加到其中,使它比竞争对手更与众不同,对消费者来说更有趣。

地址 space,特别是对于全尺寸手臂来说是相当开放的,所以即使他们使用与其他人相同的 usb ip,并不意味着它与其他人使用相同的地址。

没有理由假设所有带有 cortex-a 的芯片都以 cortex-a 为中心,cortex-a 可能只是用来启动和管理芯片的真实事物是为了。您询问的芯片很可能以 ARM 处理器为中心,该芯片的目的是制造基于 ARM 的 "CPU"。我们在该市场看到的是需要支持各种 non-volatile 存储解决方案。有些人可能希望 ram 很重并且不关心使用慢速 spi flash 来获取内核和根文件系统并且 运行时间一切都是基于 ram 的,包括文件系统。有些人可能希望支持传统的硬盘驱动器和 ram,文件系统位于 sata 上,例如旋转媒体或 ssd。有些人可能希望使用eMMC、SD等。由于芯片生产成本非常高,因此每种组合都做一个芯片没有意义,而是做一个支持多种组合的芯片。您使用客户接地的几个 "strap" 引脚(不是引脚而是 BGA 上的 balls/pads)或 "high" 无论该电压的定义是什么,以便当芯片出来时复位(该产品的哪个复位引脚被记录为带引脚采样)这些带引脚告诉 "processor"(芯片作为一个实体)您希望它如何启动。我想让你先在这个 spi 总线上寻找一个 sd 卡,如果没有,然后在这个接口上寻找一个 sata 驱动器,如果没有,那么请进入 uart0 上的 xmodem 引导加载程序。

这导致了 Frant 的出色回答。芯片中的 IP 是什么,支持什么可能的 non-volatile 存储,如果 "chip" 本身支持它,加载引导加载程序的可能解决方案是芯片特定的,不仅仅是 broadcom 这样做,而 ti 这样做它是另一个,但可能是大量产品中的特定芯片或芯片系列,没有理由假设供应商的任何两种产品以相同的方式工作,您阅读您感兴趣的每个产品的文档。当然不要假设任何两个供应商的详细信息远程相同,很可能他们为某些技术购买了类似的 ip(例如,也许每个人都使用相同的 usb ip,或者大多数 usb ip 符合一组通用的寄存器,或者可能不......) .

我还没有了解手臂核心,您可能会在这些设计中改变主意,将手臂拉出并放入 mips 并将其作为产品出售...

现在说写入逻辑以读取将闪存的内容加载到内部 sram 中的 spi 闪存,然后对于该引导模式将该 sram 置于 arm 处理器地址零然后重置 arm 是否有意义?是的,仅在逻辑上这样做并不是一个可怕的想法。但是,例如通过 sata 驱动器的文件系统进行逻辑挖掘以找到一些引导加载程序是否有意义?也许不是那么多,可能是肯定的,但是如果你在产品中放置一个 rom,它可以瞄准手臂地址零,那么你的产品可能会存活更长时间关于引导介质是什么的决定启动外围设备(sata、emmc、spi 等)遍历文件系统寻找文件名,将该文件复制到 sram,re-maps arm 地址 space (不使用 mmu,而是使用芯片中的逻辑)并通过分支到地址零来伪造复位。 (rom 被映射到至少地址零然后是其他地址的两个位置,以便它可以分支到另一个地址 space 允许地址零被重新映射和重用)。因此,如果在路上你发现了一个错误,你所要做的就是在交付芯片之前更改刻录到 ROM 中的图像,而不是旋转芯片来更改晶体管 and/or 晶体管的布线(便士和days/weeks 对比数百万美元和数月)。所以你实际上可能永远不会看到或成为 arm 处理器在重置时启动的代码。手臂核心的重置线,您可能永远无法访问任何物理或软件。

然后,根据此芯片产品或许多芯片产品中的任何一个的无数启动选项,下一步非常特定于该芯片以及可能的启动模式。您拥有该板级产品的所有引导代码,可能必须根据芯片和板设计,调出 ddr、调出 pcie、调出 usb。或者一些芯片 vedor logic/code 已经为你做了一些(不太可能,但可能是针对特定的启动情况)。现在你有了像 u-boot 这样的通用和流行的 "boot loaders",你作为软件设计者和实现者可能会选择在 u-boot 之前的代码完成相当多的工作,因为可能移植 u-boot 是 PITA,也许不是。另请注意 linux 绝不需要 u-boot,启动 linux 很容易,u-boot 是一个怪物,它自己的野兽,最简单的启动方式 linux 是为了不打扰移植 u-boot。 u-boot 给出的是一个已经编写好的引导加载程序,这是一个可以选择任何一种方式的论点是移植 u-boot 更便宜还是自己滚动(或将其中一个竞争对手移植到 u-boot)?取决于你想要的启动选项,如果你想要 bootp/tftp 或任何网络堆栈,那是一项任务,尽管有现成的解决方案。如果你想访问某些媒体上的文件系统,那么这是另一个只使用 u-boot 的有力论据。但如果你不需要所有这些,那么也许你不需要 u-boot.

你必须在 linux 引导之前查看需要发生的事情列表,芯片往往没有足够的片上 ram 来保存 linux 内核映像和根文件系统, 所以你需要在 linux 之前把 ddr 起来。您可能需要启动并枚举 pcie,也许 usb 我还没有看过。但是可以通过 linux 驱动程序为该外围设备调出以太网作为示例。

"boot" linux 对 linux 的 arm ports 和其他可能的要求相对简单。您将 linux 内核复制到内存中理想对齐的某个 space 或与对齐地址的商定偏移量(例如 0x10001000,只是将其拉出),然后提供 table 的信息,有多少 ram,ascii 内核引导字符串,以及最近的设备树信息。你分支到 linux 内核,其中一个寄存器说 r0 指向这个 table (google ATAG arm linux 或一些这样的词组合)。就是这样引导 linux 使用一个不太旧的内核在 ram 中设置几十个字节,将内核复制到 ram,然后分支到它,几十行代码,不需要 u-boot怪物。现在是几十个字节了,但还是一个独立于u-boot生成的table,放在ram里,把kernel放在ram里,设置一个或多个寄存器指向[=133] =],分支到内核所在的地址 "booting linux" 完成或 linux 引导加载程序完成。

您仍然需要移植 linux,这是一项需要大量试验和错误并最终需要多年经验的任务。特别是因为 linux 本身就是一个不断进化的野兽。

如何获得 u-boot 代码?您可能需要编写一些前 u-boot 代码才能找到 u-boot 并将其复制到 ram 然后分支到它。芯片供应商可能已经为您解决了这个问题,并且 "all you have to do" 被放置在 u-boot 他们告诉您媒体选择的地方,然后 u-boot 被放置在 arm 内存中的地址零处 space 对于一些内部 sram,或者 u-boot 被放置在 arm 内存中的某个 non-zero 地址 space 和一些魔法(芯片中基于 rom 的引导加载程序)导致你的 u-boot 从该地址执行的代码。

我最近搞砸的一个是各种beagle板上使用的ti芯片,黑色,绿色,白色,pocket等等...其中一种启动模式它会查看sd卡上的特定偏移量(不是部分一个文件系统,一个特定的逻辑块,如果你愿意或基本上在 sd 卡地址中的特定偏移量 space) 对于 table,那么 table 包括 "processors" 中的位置] 地址 space 你希望附加的 "bootloader" 被复制到,它是否被压缩,等等 你制作你的引导加载程序(滚动你自己的或构建一个 u-boot 端口)你构建正确的 table 根据带有目标地址的文档有多少数据,可能是 crc/checksum,无论文档怎么说。 "chip" 神奇地(可能是软件,但可能是纯逻辑)复制它并导致 arm 在该地址开始执行(可能是 arm 软件只是在那里分支)。这就是您如何使用该引导选项在该产品线上获得 u-boot 运行ning。

SAME 产品线有其他表带选项,有其他 sd-card 引导选项来加载 u-boot 和 运行ning。

其他供应商的其他产品有不同的解决方案。

raspberry pi 中的 broadcom 芯片,完全不同的野兽,或者至少它是如何使用的。它有一个 broadcom(发明或购买的)gpu,gpu 引导一些基于 rom 的代码,这些代码知道如何在 sd 卡上找到自己的第一阶段引导加载程序,第一阶段加载程序执行诸如初始化 DDR 之类的事情,没有 pcie 所以不必发生,我认为 gpu 不关心 usb,因此也不必枚举。但它确实搜索了 gpu 代码的第二阶段引导加载程序,这实际上是它正在加载的 RTOS,GPU u 的代码es 做它的图形功能以减轻 ARM 的负担。除此之外,该软件还在闪存上寻找第三个文件(以及第四个和第 n 个),让我们用第三个 kernel.img 将其复制到 ram(ddr 在 gpu 和 arm 之间共享,但不同寻址方案)在商定的偏移量(如果使用 kernel.img 而没有对其进行 config.txt 调整,则为 0x8000)然后 gpu 将 bootstrap 程序和 ATAG 写入地址为零的武器内存中,然后释放重置在 ARM 内核上。 GPU 是引导加载程序,选项相对有限,但对于该平台 design/solution 一个媒体选项,一个可移动 sd 卡,什么操作系统等你 运行 在手臂上就是那个 sd 卡上的任何东西.

我想您会发现许多皮带驱动多个可能的 non-volatile 存储媒体外围设备是更常见的解决方案。出于多种原因,特定 SOC 的这些引导选项中的一个或任何一个是否可以直接采用 u-boot(或选择您的引导加载程序或编写您自己的引导程序)或需要预 u-boot 程序(芯片上的 sram 太小,无法完整 u-boot 让我们举个例子,为了争论)特定于该供应商的该芯片的启动选项,并且在某处记录,尽管如果您不是公司的一部分与该芯片供应商签署 NDA 的电路板,您可能看不到该文档。 And/or 正如您可能知道或将了解到的那样,这并不意味着文档很好或有意义。有些公司或产品做得不好,有些做得很好,大多数介于两者之间。如果您为零件付款并有保密协议,您至少可以选择获得或购买技术支持,并且可以直接提问(同样,答案可能没有用,取决于公司和他们的支持)。

仅仅因为里面有一个 ARM 就意味着什么都没有。 ARM 制造处理器内核而不是 IP,这取决于 SOC 设计,这可能很容易或有点痛苦,但可以将手臂拉出并在其中放置一些其他购买的 ip(如 MIPS)或免费 ip(如 risc-v)和re-use 您已经测试过的其余部分 design/glue。尝试推广基于 ARM 的处理器就像尝试推广配备 V-6 发动机的汽车,如果我有一辆配备 V-6 发动机的车辆,是否意味着前照灯控制装置始终位于转向柱左侧的仪表板上?不!