[RFC PATCH] env: Export environment config to OS devicetree
Stefano Babic
sbabic at denx.de
Thu Aug 3 15:21:44 CEST 2023
Hi Frieder,
On 03.08.23 14:51, Frieder Schrempf wrote:
> Hi Stefano,
>
> On 03.08.23 10:14, Stefano Babic wrote:
>> Hi Frieder,
>>
>> On 01.08.23 16:46, Frieder Schrempf wrote:
>>> From: Frieder Schrempf <frieder.schrempf at kontron.de>
>>>
>>> There are plenty of cases where the OS wants to know where the
>>> persistent environment is stored in order to print or manipulate it.
>>>
>>> In most cases a userspace tool like libubootenv [1] is used to handle
>>> the environment. It uses hardcoded settings in a config file in the
>>> rootfs to determine the exact location of the environment.
>>>
>>
>> ...or the configuration file is generated, or it is located on a rw
>> (overlayfs) partition.
>>
>>> In order to make systems more flexible and let userspace tools
>>> detect the location of the environment currently in use, let's
>>> add an option to export the runtime configuration to the FDT passed
>>> to the OS.
>>>> This is especially useful when your device is able to use multiple
>>> locations for the environment and the rootfs containing the
>>> fw_env.config file should be kept universal.
>>
>> Ok
>>
>> One possible issue is there is a hard dependency between the properties
>> set in DT and the user space tool. The tool in user space is bound to
>> the list of properties, and changes / extensions for the user tool
>> requires changes in DT semantics (which properties, their path, etc).
>>
>> The same hard dependency is set by fw_env.config with its strong
>> hardcoded and position dependent syntax. This one of the reason I
>> introduced YAML support in libubootenv, so that the user tool is
>> independent and can add own properties.
>>
>> I am just asking if this use case requires a new interface, or it is
>> already available in some way. I mean, the configuration is YAML instead
>> of fw_env.config and contains multiple setup ("namespaces"), like:
>>
>> mmc:
>> size : 0x100000
>> lockfile : /var/lock/fw_printenv.lock
>> devices:
>> - path : /dev/mmcblk0boot0
>> offset : 0x1E0000
>> sectorsize : 0x100000
>> - path : /dev/mmcblk0boot0
>> offset : 0x1E0000
>> sectorsize : 0x100000
>> spi:
>> size : 0x100000
>> lockfile : /var/lock/fw_printenv.lock
>> devices:
>> - path : /dev/mtd0
>> offset : 0x1E0000
>> sectorsize : 0x100000
>> - path : /dev/mtd0
>> offset : 0x1F0000
>> sectorsize : 0x100000
>>
>> This configuration file can safely stored in your common rootfs and
>> covers all possible storage for environment. It does not cover "runtime"
>> changes, but well, I do not think this is a use case.
>>
>> An advantage here is that new options, useful for the User Space tool,
>> can be simply introduced for the tool without the need to synchronize
>> with DT spec and U-Boot.
>>
>> A mapping between location index and device path is not required. What
>> is still required is a selector, and this can be implemented in DT or as
>> kernel parameter.
>>
>> Does this already cover your use case or do we need the introduction of
>> this new interface ?
>
> Thanks for the feedback! I've seen the YAML configuration feature in
> libubootenv but I missed the fact, that it already supports something
> like the namespace parameter for selecting different configurations.
>
> Indeed this would solve one part of the issue. And yes, I think we could
> use the DT or a kernel parameter to pass a selector from U-Boot to
> userspace.
Exactly.
>
> Do you think we could add something to libubootenv to automatically
> select the default namespace based on some DT property or kernel parameter?
Yes, we just need to add a way to set up a default "namespace". There is
currently a default "uboot" namespace, and we just need a way to pass
the information to the library. Maybe with an env ?
>
> If yes, I think this would be a viable solution for me.
Fine !
>
>>
>>>
>>> Currently the general information like location/type, size, offset
>>> and redundancy are exported. Userspace tools might already be able
>>> to guess the correct device to access based on this information.
>>>
>>> For further device-specific information two additional properties
>>> 'id1' and 'id2' are used. The current implementation uses them for
>>> MMC and SPI FLASH like this:
>>>
>>> | Type | id1 | id2 |
>>> | ---------- | -------------------------- | -------------------------- |
>>> | MMC | MMC device index in U-Boot | MMC hwpart index in U-Boot |
>>> | SPI FLASH | SPI bus index in U-Boot | SPI CS index in U-Boot |
>>>
>>> Further extensions for other environment devices are possible.
>>>
>>> We add the necessary information to the '/chosen' node. The following
>>> shows two examples:
>>>
>>> Redundant environment in MMC:
>>>
>>> /chosen {
>>> u-boot,env-config {
>>> location = <5>; # according to 'enum env_location'
>>> offset = <0x1E0000>;
>>> size = <0x100000>;
>>> sect_size = <0x100000>;
>>> id1 = <1>; # MMC device index
>>> id2 = <0>; # MMC HW partition index
>>> };
>>> u-boot,env-redund-config {
>>> offset = <0x1F0000>;
>>> };
>>> };
>>>
>>> Redundant environment in SPI NOR:
>>>
>>> /chosen {
>>> u-boot,env-config {
>>> location = <10>; # according to 'enum env_location'
>>> offset = <0x1E0000>;
>>> size = <0x100000>;
>>> sect_size = <0x100000>;
>>> id1 = <0>; # SPI bus
>>> id2 = <0>; # SPI CS
>>> };
>>> u-boot,env-redund-config {
>>> offset = <0x1F0000>;
>>> };
>>> };
>>>
>>> See [2] for an example parser implementation for libubootenv.
>>>
>>> [1]
>>> https://github.com/sbabic/libubootenv
>>> [2]
>>> https://github.com/fschrempf/libubootenv/commit/726a7ac9b1b1020354ee8fe750f4cad3df01f5e7
>>>
>>> Cc: Stefano Babic <sbabic at denx.de>
>>> Cc: Michael Walle <michael at walle.cc>
>>> Signed-off-by: Frieder Schrempf <frieder.schrempf at kontron.de>
>>> ---
>>> boot/Kconfig | 9 ++++++++
>>> boot/image-fdt.c | 8 ++++++++
>>> env/env.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
>>> include/env.h | 4 ++++
>>> 4 files changed, 74 insertions(+)
>>>
>>> diff --git a/boot/Kconfig b/boot/Kconfig
>>> index e8fb03b801..16a94f9b35 100644
>>> --- a/boot/Kconfig
>>> +++ b/boot/Kconfig
>>> @@ -702,6 +702,15 @@ config OF_BOARD_SETUP
>>> board-specific information in the device tree for use by the OS.
>>> The device tree is then passed to the OS.
>>> +config OF_EXPORT_ENV_CONFIG
>>> + bool "Export environment config to device tree before boot"
>>> + depends on OF_LIBFDT
>>> + help
>>> + This causes U-Boot to call fdt_environment_config() before
>>> booting into
>>> + the operating system. This function exports the currently in use
>>> + environemnt configuration to the "chosen" node of the fdt. This
>>> allows
>>> + the OS to determine where the environment is located.
>>> +
>>> config OF_SYSTEM_SETUP
>>> bool "Set up system-specific details in device tree before boot"
>>> depends on OF_LIBFDT
>>> diff --git a/boot/image-fdt.c b/boot/image-fdt.c
>>> index f10200f647..c02c8f33ef 100644
>>> --- a/boot/image-fdt.c
>>> +++ b/boot/image-fdt.c
>>> @@ -643,6 +643,14 @@ int image_setup_libfdt(struct bootm_headers
>>> *images, void *blob,
>>> /* Append PStore configuration */
>>> fdt_fixup_pstore(blob);
>>> #endif
>>> + if (IS_ENABLED(CONFIG_OF_EXPORT_ENV_CONFIG)) {
>>> + fdt_ret = fdt_environment_config(blob);
>>> + if (fdt_ret) {
>>> + printf("ERROR: environment config fdt fixup failed: %s\n",
>>> + fdt_strerror(fdt_ret));
>>> + goto err;
>>> + }
>>> + }
>>> if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) {
>>> const char *skip_board_fixup;
>>> diff --git a/env/env.c b/env/env.c
>>> index 2aa52c98f8..a640977205 100644
>>> --- a/env/env.c
>>> +++ b/env/env.c
>>> @@ -8,6 +8,7 @@
>>> #include <env.h>
>>> #include <env_internal.h>
>>> #include <log.h>
>>> +#include <mmc.h>
>>> #include <asm/global_data.h>
>>> #include <linux/bitops.h>
>>> #include <linux/bug.h>
>>> @@ -156,6 +157,58 @@ __weak enum env_location env_get_location(enum
>>> env_operation op, int prio)
>>> return arch_env_get_location(op, prio);
>>> }
>>> +#ifdef CONFIG_OF_EXPORT_ENV_CONFIG
>>> +int fdt_environment_config(void *blob)
>>> +{
>>> + struct mmc *mmc;
>>> + u32 location;
>>> + int chosen_offs, offs;
>>> + int ret;
>>> +
>>> + if (CONFIG_IS_ENABLED(ENV_IS_NOWHERE))
>>> + return 0;
>>> +
>>> + chosen_offs = fdt_path_offset(blob, "/chosen");
>>> + if (chosen_offs < 0) {
>>> + printf("Could not find chosen node.\n");
>>> + return chosen_offs;
>>> + }
>>> +
>>> + offs = fdt_add_subnode(blob, chosen_offs, "u-boot,env-config");
>>> + if (offs < 0) {
>>> + printf("Could not create env-config node.\n");
>>> + return offs;
>>> + }
>>> +
>>> + location = env_get_location(0, 0);
>>> + fdt_setprop_u32(blob, offs, "location", location);
>>> + fdt_setprop_u32(blob, offs, "offset", CONFIG_ENV_OFFSET);
>>> + fdt_setprop_u32(blob, offs, "size", CONFIG_ENV_SIZE);
>>> + fdt_setprop_u32(blob, offs, "sect_size", CONFIG_ENV_SECT_SIZE);
>>> +
>>
>> My major concern is regarding the dependency that is introduced. These
>> properties are then compiled into U-Boot. If a new property will be
>> required in future, this could required an update for the bootloader in
>> field. Even if yes, bootloader's updates are done in field, they are
>> often risky and not power-cut safe.
>>
>> If the whole configuration, new properties, etc, remains as much as
>> possible in User Space, to get the new feature we need an update of
>> rootfs (in your example), that is (mostly) safe (and then it is not, the
>> update procedure should be revisited). A single rootfs for multiple
>> hardware using different locations and maybe different options (if
>> needed or if they will be introduced) is possible, the yaml
>> configuration will contain all of them and some detection (in user
>> space) can do the trick to select the right one.
>>
>> What do you think ?
>
> Yeah, I get your point. My idea was that the bootloader exports
> "everything" it knows about the environment to the DT. But indeed, there
> is some (minimal?) risk that changes to the exported data are needed
> which would require the bootloader to be updated.
Right - the idea with libubootenv is that it is hardware-independent,
and setup is done just via configuration files.
>
> Using the YAML config with multiple namespaces sounds like a good
> alternative. But detecting the right namespace to use can only be done
> based on information passed by the bootloader.
Agree.
> So if we could build a
> default namespace selection by DT property or kernel parameter into
> libubootenv that would be great.
Of course, we can !
Best regards,
Stefano
>
> Thanks
> Frieder
--
=====================================================================
DENX Software Engineering GmbH, Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, 82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
More information about the U-Boot
mailing list