I've been investigating a change to some embedded software inasmuch as we want U-Boot to be able to pass specific command-line parameters to the kernel, ones that aren't necessarily known in advance.
This is so that the kernel can tell which U-Boot partition it was started by (we have two copies, one in /dev/mmc3boot0
and /dev/mmc3boot1
, and they both share a single (redundant) environment space, so we can't use that alone to uniquely identify the instance).
One thought was to simply have each U-Boot write its ID to the shared environment when it boots but that has the downside that there are variants out there that do not currently do this. So, if we boot from one that does, it will write its ID and, if we then boot from one that doesn't, it will not change the ID back to blank, leading to incorrect information if we rely on that.
This is why we thought to use a kernel parameter - since older style U-Boot instances never supply an ID, we know it's running in boot0
. The newer style would provide their actual ID so we could then search the two boot
partitions to see which one it was in.
To that end, I've modified U-Boot so that it sets up ATAGs to pass through the extra parameter needed. Specifically:
CONFIG_SYS_BOOT_GET_CMDLINE
in arch\\arm\\include\\asm\\config.h
so that boot_get_cmdline()
is called. boot_get_cmdline()
function so that it sets up a specific parameter before appending the normal parameters. In other words, rather than just plugh=xyzzy
, we now get uboot_instance=42 plugh=xyzzy
. This all compiles fine and U-Boot successfully starts the kernel but the extra information is not being reflected in the Linux kernel, which has its kernel parameters set to the regular plugh=xyzzy
.
On further research, it appears that we are falling afoul of the two possible ways to invoke the kernel. One of these is with ATAGs and one is with a flattened device tree (FDT), and they appear to be mutually exclusive (the kernel startup code selects one or the other based on signatures passed in with the pointer referencing either the ATAGs or FDT structure).
So my question is this. Given that the device tree is meant to be a fixed structure for the device you're describing, how do you pass arbitrary kernel command line parameters (calculated at runtime) when the bootloader is invoking the kernel?
You can use a dummy environment variable for your platform in include/configs/<board>.h
.
For example, assume you have the following (simplified) UBoot environment variables for booting:
bootcmd=run mmcargs
run loadimage loadfdt
bootz ${loadaddr} - ${fdt_addr}
mmcargs=setenv bootargs blah=blah
This uses mmcargs
to set up the kernel command line to use. What we need to do is to insert that dummy environment variable in a way that current UBoot instances supply nothing and new ones supply the actual ID. This is done simply with the following change:
mmcargs=setenv bootargs ${uboot_id_stanza} blah=blah
Then, during the initialization of the board, you can set this variable using env_set
API, specifically by writing your own custom board_late_init
of the board init code in board/<vendor>/<init_code>.c
.
The following line should be placed at the end of the board_late_init
function:
setenv("uboot_id_stanza", "uboot_id=<uniqueId>");
That way, the uboot_id
variable setting is added to the kernel command line but, since you didn't do a saveenv
, it doesn't become persistent. Every UBoot instance will set the correct ID (including old ones that don't set an ID).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.