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

Command line 使用设备树时将内核参数从U-Boot传递到ARM Linux,command-line,parameters,linux-kernel,arm,u-boot,Command Line,Parameters,Linux Kernel,Arm,U Boot,我一直在研究一些嵌入式软件的变化,因为我们希望U-Boot能够将特定的命令行参数传递给内核,这些参数不一定事先就知道 这样内核就可以知道它是由哪个U-Boot分区启动的(我们有两个副本,一个在/dev/mmc3boot0和/dev/mmc3boot1中,它们都共享一个(冗余)环境空间,所以我们不能单独使用它来唯一地标识实例) 一种想法是简单地让每个U-Boot在启动时将其ID写入共享环境,但这有一个缺点,即目前有一些变体不这样做。因此,如果我们从一个有ID的启动,它将写入其ID,如果我们从一个没

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

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

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

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

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

  • 我在
    arch\arm\include\asm\CONFIG.h
    中定义了
    CONFIG\u SYS\u BOOT\u GET\u CMDLINE
    ,以便调用
    BOOT\u GET\u CMDLINE()
  • 我修改了
    boot\u get\u cmdline()
    函数,以便在附加正常参数之前设置特定参数。换句话说,我们现在得到的不是
    plugh=xyzy
    ,而是
    uboot\u实例=42 plugh=xyzy
这一切编译都很好,U-Boot成功地启动了内核,但是额外的信息没有反映在Linux内核中,它的内核参数设置为常规的
plugh=xyzy

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


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

您可以在
include/configs/.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/.c
中编写自己的自定义
board_late_init
板初始化代码来设置此变量

以下行应放在
board\u late\u init
函数的末尾:

setenv("uboot_id_stanza", "uboot_id=<uniqueId>");
setenv(“uboot_id_节”,“uboot_id=”);

通过这种方式,
uboot\u id
变量设置被添加到内核命令行中,但是,由于您没有执行
saveenv
,因此它不会变得持久。每个UBoot实例都将设置正确的ID(包括未设置ID的旧实例)。

您可以在
include/configs/.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/.c
中编写自己的自定义
board_late_init
板初始化代码来设置此变量

以下行应放在
board\u late\u init
函数的末尾:

setenv("uboot_id_stanza", "uboot_id=<uniqueId>");
setenv(“uboot_id_节”,“uboot_id=”);

通过这种方式,
uboot\u id
变量设置被添加到内核命令行中,但是,由于您没有执行
saveenv
,因此它不会变得持久。每个UBoot实例都将设置正确的ID(包括未设置ID的旧实例)。

@sawdust。问题实际上是共享环境,再加上我们将拥有传统U-Boots。我们可以让新样式的总是写他们的ID,但是,如果我们随后恢复到旧样式,它们中没有任何东西可以清除这些数据,因此这将是不准确的。我已经更新了问题,使之更清楚。使用一个单独的内核参数很简单,因为旧的样式将不提供任何东西,而新的样式将提供我们可以搜索的东西。最终我们可能不得不咬紧牙关,拒绝切换回旧式。您可以在
include/configs/board.h
中为您的平台使用虚拟环境变量。例如,
bootconf=“uboot\u instance=X”
作为默认值,并将其附加到bootargs中。在电路板初始化过程中,您可以使用
env_set
API设置此变量,特别是通过在
board/vendor/start_.c
中编写自己的自定义
board_late_init
中的board init代码来设置此变量。这样,您就不需要ATAGS了。对不起,我的评论有误。