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

时间:2018-11-02 05:58:20

标签: command-line parameters linux-kernel arm u-boot

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

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

一个想法是在引导时将每个U-Boot简单地将其ID写入共享环境,但这有一个缺点,就是目前有一些变体无法执行此操作。因此,如果我们从一个不启动的设备启动,它将写入其ID;如果我们从一个不启动的设备启动,则不会将ID 更改变回空白,从而导致错误信息。我们依靠它。

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

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

  • 我在CONFIG_SYS_BOOT_GET_CMDLINE中定义了arch\arm\include\asm\config.h,以便调用boot_get_cmdline()
  • 我已经修改了boot_get_cmdline()函数,以便它在附加正常参数之前在 之前设置一个特定参数。换句话说,我们不仅得到plugh=xyzzy,而且得到了uboot_instance=42 plugh=xyzzy

这一切编译正常,U-Boot成功启动了内核,但是额外的信息并未反映在Linux内核中,该内核的内核参数设置为常规plugh=xyzzy

在进一步的研究中,似乎我们与调用内核的两种可能方式不符。其中之一与ATAG一起使用,一个与扁平设备树(FDT)一起使用,并且它们似乎是互斥的(内核启动代码根据传递的签名选择一个或另一个,该签名通过引用ATAG或FDT结构的指针传递)。

所以我的问题是这个。假设设备树对于您所描述的设备而言是固定的 结构,那么当运行时,如何传递任意内核命令行参数(在运行时计算)引导程序正在调用内核?

1 个答案:

答案 0 :(得分:3)

您可以在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_late_init中编写自己的开发板初始化代码board/<vendor>/<init_code>.c自定义。

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

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

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