我一直在研究对某些嵌入式软件的更改,因为我们希望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结构的指针传递)。
所以我的问题是这个。假设设备树对于您所描述的设备而言是固定的 结构,那么当运行时,如何传递任意内核命令行参数(在运行时计算)引导程序正在调用内核?
答案 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)。