简体   繁体   English

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

[英]Passing kernel params from U-Boot to ARM Linux when device tree is used

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

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). 这样内核就可以知道它是从哪个 U-Boot分区启动的(我们有两个副本,一个在/dev/mmc3boot0/dev/mmc3boot1 ,它们都共享一个(冗余)环境空间,因此我们可以不能单独使用它来唯一标识实例)。

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. 一种想法是在引导时将每个U-Boot简单地将其ID写入共享环境,但这有一个缺点,就是目前有一些变体目前不执行此操作。 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. 因此,如果我们从一个不启动的启动,它将写入其ID;如果从一个不启动的启动,则它将写入ID,如果依赖它,它将不会将ID 回空白,从而导致信息不正确。

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 . 这就是为什么我们考虑使用内核参数的原因-由于较早版本的U-Boot实例从不提供ID,因此我们知道它在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. 较新的样式将提供其实际ID,因此我们可以搜索两个boot分区以查看其所在的分区。

To that end, I've modified U-Boot so that it sets up ATAGs to pass through the extra parameter needed. 为此,我修改了U-Boot,以便它设置ATAG以传递所需的额外参数。 Specifically: 特别:

  • I've define CONFIG_SYS_BOOT_GET_CMDLINE in arch\\arm\\include\\asm\\config.h so that boot_get_cmdline() is called. 我在arch\\arm\\include\\asm\\config.h定义了CONFIG_SYS_BOOT_GET_CMDLINE ,以便调用boot_get_cmdline()
  • I've modified that boot_get_cmdline() function so that it sets up a specific parameter before appending the normal parameters. 我已经修改了boot_get_cmdline()函数,以便附加普通参数之前先设置一个特定参数。 In other words, rather than just plugh=xyzzy , we now get uboot_instance=42 plugh=xyzzy . 换句话说,我们现在得到的不仅仅是plugh=xyzzy ,而是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 . 所有这些都可以正常编译,并且U-Boot成功启动了内核,但是额外的信息没有反映在Linux内核中,该内核的内核参数设置为常规的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). 其中之一与ATAG一起使用,一个与扁平设备树(FDT)一起使用,并且它们似乎是互斥的(内核启动代码根据传递的签名选择一个或另一个,该签名通过引用ATAG或FDT结构的指针传递)。

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 . 您可以在include/configs/<board>.h为您的平台使用虚拟环境变量。

For example, assume you have the following (simplified) UBoot environment variables for booting: 例如,假定您具有以下(简化的)UBoot环境变量用于引导:

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. 这使用mmcargs设置要使用的内核命令行。 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. 我们需要做的是以当前UBoot实例不提供任何内容而新的实例提供实际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 . 然后,板的初始化过程中,您可以通过设置此变量env_set API专门写自己的自定义, board_late_init在板初始化代码的board/<vendor>/<init_code>.c

The following line should be placed at the end of the board_late_init function: 以下行应放在board_late_init函数的末尾:

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. 这样, uboot_id变量设置将添加到内核命令行,但是由于您没有执行saveenv ,因此它不会持久化。 Every UBoot instance will set the correct ID (including old ones that don't set an ID). 每个UBoot实例都将设置正确的ID(包括设置ID的旧ID)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM