使用设备树时将内核参数从 U-Boot 传递到 ARM Linux

Passing kernel params from U-Boot to ARM Linux when device tree is used

我一直在研究对一些嵌入式软件的更改,因为我们希望 U-Boot 能够将特定的命令行参数传递给内核,这些参数事先不一定知道。

这样内核就可以告诉它是由哪个 U-Boot分区启动的(我们有两个副本,一个在/dev/mmc3boot0/dev/mmc3boot1,它们都共享一个(冗余)环境 space,所以我们不能单独使用它来唯一标识实例)。

一个想法是简单地让每个 U-Boot 在启动时将其 ID 写入共享环境,但缺点是目前有一些变体不这样做。因此,如果我们从一个有 ID 的设备启动,它会写入其 ID,如果我们从一个没有的设备启动,它不会 将 ID 更改 回空白,从而导致如果我们依赖该信息,则信息不正确。

这就是我们考虑使用内核参数的原因 - 因为旧式 U-Boot 实例从不提供 ID,所以我们知道它在 boot0 中是 运行。较新的样式会提供它们的实际 ID,这样我们就可以搜索两个 boot 分区以查看它在哪个分区中。

为此,我修改了 U-Boot,以便它设置 ATAG 以传递所需的额外参数。具体来说:

这一切都编译得很好,U-Boot 成功启动了内核,但是额外的信息没有反映在 Linux 内核中,它的内核参数设置为常规的 plugh=xyzzy

经过进一步研究,我们似乎与调用内核的两种可能方式发生了冲突。其中一个是 ATAG,一个是扁平设备树 (FDT),它们似乎是互斥的(内核启动代码根据传入的签名选择一个或另一个,指针引用 ATAG 或 FDT 结构).

所以我的问题是这样的。鉴于设备树是您描述的设备的 fixed 结构,您如何传递 arbitrary 内核命令行参数(在运行时计算)当引导加载程序调用内核时?

您可以在 include/configs/<board>.h 中为您的平台使用虚拟环境变量。

例如,假设您有以下(简化的)UBoot 环境变量用于引导:

bootcmd=run mmcargs
        run loadimage loadfdt
        bootz ${loadaddr} - ${fdt_addr}
mmcargs=setenv bootargs blah=blah

这使用mmcargs设置要使用的内核命令行。我们需要做的是以当前 UBoot 实例不提供任何内容而新实例提供实际 ID 的方式插入该虚拟环境变量。这只需通过以下更改即可完成:

mmcargs=setenv bootargs ${uboot_id_stanza} blah=blah

然后,在电路板初始化期间,您可以使用 env_set API 设置此变量,具体是通过在 board/<vendor>/<init_code>.c.

以下行应放在 board_late_init 函数的末尾:

setenv("uboot_id_stanza", "uboot_id=<uniqueId>");

那样,uboot_id 变量设置被添加到内核命令行,但是,由于您没有执行 saveenv,它不会变得持久。每个 UBoot 实例都会设置正确的 ID(包括那些设置 ID 的旧实例)。