I’m working on implementation of the redundancy and range of environment variables in U-Boot. So far the changes in U-Boot config were pretty straight forward.
CONFIG_ENV_RANGE=CONFIG_ENV_SIZE * 2
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
CONFIG_ENV_OFFSET_REDUND=CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE
But modifications to the configuration file fw_env.config
used by fw_printenv
and fw_setenv
utility proved to be more challenging, than I expected. The meaning of parameters like Flash sector size
or Number of sectors
is not very straightforward, but I finally got it working by analyzing the source code of this utility.
Now I cannot stop to think that your original fw_env.config
is misconfigured. Here is the content of the original file taken from meta-toradex-nxp
git repository at recipes-bsp/u-boot/files/colibri-imx7/fw_env.config
:
# MTD device name Device offset Env. size Flash sector size Number of sectors
# Colibri iMX7
/dev/mtd3 0x00000000 0x00020000 0x20000 4
First four parameters are correct, they are just taken directly from U-Boot configuration, but not the last one Number of sectors
. As far as I’m concerned this value should be equal to configuration makro CONFIG_ENV_RANGE
in U-Boot, which in colibri_imx7_defconfig
is not set. The only difference between them is that in U-Boot you have to manually align the length of range to multiple erase-blocks and here it’s just number of erase-blocks (less prone to error).
To further prove my point when you look at source code of fw_env.c
, the last value from config file is parsed as &ENVSECTORS
parameter.
https://source.denx.de/u-boot/u-boot/-/blob/master/tools/env/fw_env.c
#if defined(CONFIG_FILE)
static int get_config(char *fname)
{
...
while (i < 2 && getline(&line, &linesize, fp) != -1) {
/* Skip comment strings */
if (line[0] == '#')
continue;
rc = sscanf(line, "%ms %lli %lx %lx %lx",
&devname,
&DEVOFFSET(i),
&ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
...
The &ENVSECTORS
parameter is then referenced in different functions like for example following one, where in the comment is written, that we have to stay within those sectors. This sounds like description for CONFIG_ENV_RANGE
.
/*
* Write count bytes from begin of environment, but stay within
* ENVSECTORS(dev) sectors of
* DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
* erase and write the whole data at once.
*/
static int flash_write_buf(int dev, int fd, void *buf, size_t count)
{
...
/*
* For mtd devices only offset and size of the environment do matter
*/
if (DEVTYPE(dev) == MTD_ABSENT) {
blocklen = count;
erase_len = blocklen;
blockstart = DEVOFFSET(dev);
block_seek = 0;
write_total = blocklen;
} else {
blocklen = DEVESIZE(dev);
erase_offset = DEVOFFSET(dev);
/* Maximum area we may use */
erase_len = environment_end(dev) - erase_offset;
blockstart = erase_offset;
/* Offset inside a block */
block_seek = DEVOFFSET(dev) - erase_offset;
Also in that snippet you can see that calculation of the memory area is using function environment_end(dev)
which looks like this:
off_t environment_end(int dev)
{
/* environment is block aligned */
return DEVOFFSET(dev) + ENVSECTORS(dev) * DEVESIZE(dev);
}
This function calculates the end of the reserved memory space for environmental variables by taking the Number of sectors
, multiplying it by Flash sector size
and finally adding it to Device offset
.
Final conlusion
My suspicion is that your current configuration in fw_env.config
corresponds to setting the range of env. vars memory array to 4 erase-blocks. Something like this CONFIG_ENV_RANGE=CONFIG_ENV_SIZE * 4
will do, but the default board configuration in colibri_imx7_defconfig
don’t includes this. (see https://source.denx.de/u-boot/u-boot/-/blob/master/configs/colibri_imx7_defconfig)
In my mind the only way to detect this bug is to rewrite the env. vars so many times, that the first erase-block in NAND became unreadable. At this point you could theoretically be able to write vars from Linux because it just skips the bad block, but not from uboot (it knows only the first one block). This scenario is pretty impossible to encounter.
What do you think?
P.S.
Colibri iMX7 512MB
Linux BSP 5.2.0