1

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:

  • I've define CONFIG_SYS_BOOT_GET_CMDLINE in arch\arm\include\asm\config.h so that boot_get_cmdline() is called.
  • I've modified that 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?

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • @sawdust. The problem is really the shared environment in conjunction with the fact we will have legacy U-Boots. We *could* get the new-style ones to always write their ID but, if we subsequently reverted to an old-style, there's nothing in them that clears out that data, so it would be inaccurate. I've updated the question to make that clearer. The use of a separate kernel parameter will work simply becaue old-styles will provide nothing and new-style will provide something we can search for. It may end up that we just have to bite the bullet and refuse switching back to an old-style. – paxdiablo Nov 02 '18 at 08:05
  • 1
    You can use a dummy environment variable for your platform in `include/configs/<board.h>`. For example, `bootconf = "uboot_instance = X"` as default value and append this in bootargs. 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>/<start_up.c>`. By this way, you don't need ATAGS. – Parthiban Nov 02 '18 at 08:06
  • Sorry, I meshed my comment. But still the logic remains correct. – Parthiban Nov 02 '18 at 08:10
  • @Parthiban: do you mean changing our `mmcargs` env-script from `setenv bootargs console=${console},blah` into `setenv bootargs ${sneaky} console=${console},blah` and defining `sneaky` as `id=42` in those files? If this would be stored in the UBoot environment area (ie, persistent), we still have a problem. But if it's set for new-style and not for old-style, that could work. – paxdiablo Nov 02 '18 at 08:14
  • @sawdust: that might work. If we get each new-style UBoot to write a variable when it boots but not `saveenv`, a reboot to an old-style will naturally see that variable disappear. And, of course, any new-style will create a new instance of the variable as it boots. – paxdiablo Nov 02 '18 at 08:18
  • 1
    Yes, by using `env_set` you won't save it. The value will be again default in next boot until otherwise changed in `board_late_init` – Parthiban Nov 02 '18 at 08:19
  • Just one more bit of sneakiness needed, I think. We have the ability to change environment from the kernel itself. I guess in that case, we'd modify that facility so that it remembered the variable, deleted it, made its changes, saved those changes, then recreated the variable. That way, the variable could never be persisted. That'll just be a slight mod to uboot-tools, I guess. – paxdiablo Nov 02 '18 at 08:21
  • It might be worth putting these options into answers so I can start handing out rep :-) – paxdiablo Nov 02 '18 at 08:23
  • Sure :-) Stackoverflow for Android is not that friendly yet for me. Will do shortly! – Parthiban Nov 02 '18 at 08:26

1 Answers1

4

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).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Parthiban
  • 2,130
  • 2
  • 14
  • 27
  • 1
    No reason you have to give the variable a default value if "empty" is ok. – TrentP Nov 03 '18 at 02:05
  • Let me see if I understand this. In `board//.c`, we already *have* `board_late_init` (configured in `include/configs/.h`). You propose we `setenv("ubstanza","ubid=42")` from there, and modify `bootargs` in the persistent UBoot environment to be `${ubstanza} original-bootargs`. That way, old UBoots won't have a `ubstanza` so `bootargs` will be `original-bootargs`. New UBoots *will* have the stanza so `bootargs` will in all cases have that stanza. My only question is: does `ubstanza` persist over boots or is it ephemeral to the current boot? – paxdiablo Nov 05 '18 at 03:16
  • The reason I ask is that we *want* that stanza not to persist if, for example, we revert to an older UBoot (that will neither clear it nor set it to another value). So, ideally, `bootargs` would persist and `ubstanza` would not. – paxdiablo Nov 05 '18 at 03:30
  • One final note, I assume `board_late_init` is actually done *before* running `bootcmd` from the environment since that latter action does a `bootz` as part of it (`bootcmd` calls `mmcboot` which calls `loadimage/loadfdt/bootz`) so will not return. – paxdiablo Nov 05 '18 at 05:37
  • Yes it's called very early during initialization here https://github.com/u-boot/u-boot/blob/master/common/board_r.c#L809. So you should not be having any troubles in getting access to the variable in Kernel. Using `env_set` or `setenv` does the same in setting the variable for the current boot and it will _not_ be saved to your persistent storage. You have to use `env_save` or `saveenv` command to save it separately. – Parthiban Nov 05 '18 at 08:40
  • Parthiban, this worked wonders. I hope you don't mind that I modified your answer to match what was done to solve it. I thought that better than adding my own answer. – paxdiablo Nov 06 '18 at 01:03