All U-Boot env storage backends, their trade-offs, and every relevant CONFIG_ symbol — with the exact defconfig change needed to move from the current raw-NAND setup to a wear-leveled, power-safe UBI volume.
# configs/atn_*_defconfig CONFIG_ENV_IS_IN_NAND=y CONFIG_ENV_SIZE=0x20000 # 128 KB CONFIG_ENV_OFFSET=0x100000 # fixed MTD offset # ↑ no REDUND → power-cut corrupts env # ↑ no RANGE → one bad block = unbootable # ↑ no UBI → 1-2 erase blocks total, # no wear leveling
# configs/atn_*_defconfig CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_SIZE=0x20000 # 128 KB in RAM (unchanged) CONFIG_MTD_UBI=y CONFIG_CMD_UBI=y CONFIG_UBI_SILENCE_MSG=y CONFIG_ENV_UBI_PART="ubi" CONFIG_ENV_UBI_VOLUME="uboot-env" CONFIG_ENV_UBI_VOLUME_REDUND="uboot-env-redund" CONFIG_SYS_REDUNDAND_ENVIRONMENT=y # ↑ full UBI wear leveling across device # ↑ redundant copy, atomic CRC-swap # ↑ bad-block handled by UBI layer
# Add if U-Boot needs to read files # written by Linux (e.g. boot_params.txt) CONFIG_CMD_UBIFS=y CONFIG_FS_UBIFS=y CONFIG_LZO=y # UBIFS compression CONFIG_UBIFS_SILENCE_MSG=y # U-Boot script usage: # ubi part ubi # ubifsmount ubi:rootfs # ubifsload $loadaddr /atn/boot_params.txt
| Backend | Wear leveling | Power-loss safe | Write — U-Boot | Write — Linux | Max size | Data format | Boot overhead | NAND | Pros / Cons |
|---|---|---|---|---|---|---|---|---|---|
| Raw NAND CONFIG_ENV_IS_IN_NAND | None 1–2 erase blocks |
No needs REDUND |
saveenv | fw_setenv /dev/mtdX |
ENV_SIZERAM = flash |
key=value | ~5 ms | Yes | Simplest, no deps Fastest read No wear leveling Power-cut = brick without REDUND Bad block needs ENV_RANGE |
| UBI volume CONFIG_ENV_IS_IN_UBI | Full UBI entire UBI device |
Yes CRC-swap + UBI |
saveenv | fw_setenv /dev/ubiX_Y |
ENV_SIZERAM constraint |
key=value | 50–200 ms UBI attach |
Yes | UBI wear leveling — same pool as UBIFS REDUND on separate volumes, not blocks Bad-block handled by UBI layer fw_printenv/setenv unchanged from Linux Needs UBI attach at env load (~50–200 ms) Flat key=value format only Size limited by CONFIG_ENV_SIZE (RAM) |
| UBIFS read CMD_UBIFS / ubifsmount | Full UBIFS UBI + UBIFS journal |
Yes UBIFS journal |
Read-only no write in U-Boot |
Full file I/O standard Linux |
Partition size no RAM limit |
Any file (XML, JSON…) | 100–300 ms UBI + UBIFS mount |
Yes | Reads any file Linux writes to UBIFS Structured format — XML, binary, etc. No RAM size constraint No journal conflict (forced MS_RDONLY) Read-only from U-Boot — cannot persist changes Requires UBI attach + UBIFS mount Used alongside IS_IN_UBI, not instead of it |
|
FAT / ext4
CONFIG_ENV_IS_IN_FAT CONFIG_ENV_IS_IN_EXT4 |
FTL only eMMC controller |
Partial no power-safe rename on FAT |
fatwrite / ext4write | Standard file I/O | Filesystem size | Any file | Varies | No eMMC/SD only |
Large capacity, standard tooling Easy backup/restore on host Not for NAND — eMMC/SD only FAT has no atomic write guarantee |
| JFFS2 read CONFIG_FS_JFFS2 / CMD_JFFS2 | Limited log-structured GC, raw MTD |
Partial log-structured |
Read-only | Via MTD | MTD partition | Any file | High full scan on mount |
Yes | Legacy — no new designs Slow mount (full NAND scan) GC-based wear leveling is less robust than UBI Exists in tree — do not use for new work |
| Symbol | Description | Recommendation |
|---|---|---|
| CONFIG_ENV_IS_IN_NAND | Stores env at a fixed offset in a raw MTD partition. Writes go to the same 1–2 erase blocks every time. No wear leveling, no bad-block skipping without CONFIG_ENV_RANGE. |
Replace with IS_IN_UBI |
| CONFIG_ENV_IS_IN_UBI | Stores env in a named UBI logical volume. UBI layer handles wear leveling, bad-block management, and erase-count balancing across the entire UBI device — the same wear pool used by UBIFS. | Use this |
| CONFIG_ENV_IS_IN_FAT | Env stored as a file on a FAT filesystem (SD card or eMMC partition). Wear leveling delegated to the eMMC FTL controller. FAT writes are not atomic — power cut during write can corrupt the file. | eMMC/SD only |
| CONFIG_ENV_IS_IN_EXT4 | Env stored as a file on an ext4 filesystem. Journaling provides better safety than FAT. Still eMMC/SD only — not applicable to NAND designs. | eMMC/SD only |
| CONFIG_ENV_IS_NOWHERE | Env is never saved — board always boots with compiled-in defaults. Used in manufacturing fixtures, CI builds, or recovery images where persistent env would cause confusion. | Factory/test only |
| Symbol | Typical value | Description |
|---|---|---|
| CONFIG_ENV_SIZE | 0x20000128 KB |
Both the in-RAM buffer size and the flash storage size. U-Boot reads the entire env into a heap-allocated buffer of this size at startup and keeps it for the boot session.
This is the practical ceiling on total env content — not wear, not partition size. Increasing it costs RAM during the U-Boot phase. Must be erase-block aligned for raw NAND. Practical range: 0x4000 (16 KB) to 0x20000 (128 KB). Values above 128 KB are unusual and may conflict with tight SRAM budgets on some boards.
|
| CONFIG_SYS_REDUNDAND_ENVIRONMENT | y |
Enables a redundant copy of the env (second block for raw NAND, second volume for UBI). On each saveenv, U-Boot writes the new copy, verifies CRC32, then atomically promotes it to primary. The stale copy becomes the backup. A power cut at any point leaves one valid copy intact.
With IS_IN_UBI: set CONFIG_ENV_UBI_VOLUME_REDUND as well. With IS_IN_NAND: set CONFIG_ENV_OFFSET_REDUND as well.
|
| Symbol | Typical value | Description |
|---|---|---|
| CONFIG_ENV_OFFSET | 0x100000 |
Byte offset of the env within the NAND MTD partition. Must be erase-block aligned (e.g. 128 KB boundary for typical NAND). If this offset lands on a bad block, env load fails — use ENV_RANGE to reserve a region for bad-block skipping. |
| CONFIG_ENV_OFFSET_REDUND | 0x140000 |
Offset of the redundant copy. Must be a different erase block from ENV_OFFSET. Enables atomic CRC-swap writes — if power is cut during write, the other copy survives. Required together with CONFIG_SYS_REDUNDAND_ENVIRONMENT. |
| CONFIG_ENV_RANGE | 0x40000 |
Size of the NAND region reserved for env, including room to skip bad blocks. U-Boot searches forward from ENV_OFFSET within this range for a usable block. Without this, a single bad block at the env offset bricks the board. Recommend at least 4× erase block size (4 × 128 KB = 512 KB for typical NAND). |
| Symbol | Typical value | Description |
|---|---|---|
| CONFIG_ENV_UBI_PART | "ubi" |
Name of the MTD partition to attach as the UBI device. Must match exactly the MTD partition label used in the kernel DTS and the Linux UBI volume layout. U-Boot runs ubi part <name> internally during env load. |
| CONFIG_ENV_UBI_VOLUME | "uboot-env" |
Name of the UBI logical volume that holds the primary env copy. Must be a static UBI volume of size ≥ CONFIG_ENV_SIZE. Create it in your partition layout tool (e.g. ubinize.cfg). |
| CONFIG_ENV_UBI_VOLUME_REDUND | "uboot-env-redund" |
Name of the redundant UBI volume. Same size requirement as the primary. UBI places these on different physical erase blocks automatically — no manual offset calculation needed, unlike raw NAND REDUND. Required together with CONFIG_SYS_REDUNDAND_ENVIRONMENT. |
| CONFIG_MTD_UBI | y |
Enables the UBI subsystem in U-Boot. Required for IS_IN_UBI. Also enables the UBI wear-leveling layer, erase-counter tracking, and bad-block remapping used by all UBI volumes including UBIFS. |
| CONFIG_CMD_UBI | y |
Enables the ubi shell command (ubi part, ubi read, ubi write, ubi info, ubi create). Required for IS_IN_UBI. Also used in boot scripts that manually attach UBI before UBIFS read. |
| CONFIG_UBI_SILENCE_MSG | y |
Suppresses verbose UBI attach/scan log output. UBI prints per-PEB erase-counter messages on attach; on a large NAND partition this can flood the console and add perceptible delay. Enable for production builds. |
| Symbol | Value | Description |
|---|---|---|
| CONFIG_CMD_UBIFS | y |
Enables ubifsmount, ubifsumount, ubifsls, ubifsload commands. U-Boot always mounts UBIFS read-only (forced MS_RDONLY in fs/ubifs/super.c) — there is no ubifswrite command. Linux can mount the same volume for writing without conflict because the read-only mount does not write the master node or commit a journal entry. |
| CONFIG_FS_UBIFS | y |
UBIFS filesystem driver for U-Boot. Required by CMD_UBIFS. Implements the UBIFS on-disk format reader, journal replay (read path), and index traversal. Does not implement the write/commit path. |
| CONFIG_LZO | y |
LZO compression library. Required by UBIFS — the filesystem uses LZO compression for data nodes by default. Without this, ubifsload will fail on compressed files (which is most files written by a standard Linux UBIFS mount). |
| CONFIG_UBIFS_SILENCE_MSG | y |
Suppresses UBIFS mount/replay log messages. Similar to UBI_SILENCE_MSG — enables for production to keep boot log clean. |
| Tool / file | Description |
|---|---|
| fw_printenv (mtd-utils) |
Reads U-Boot env from Linux userspace. Works with both IS_IN_NAND (reads /dev/mtdX) and IS_IN_UBI (reads /dev/ubiX_Y). Config file is /etc/fw_env.config. Identical interface regardless of backend — only the config file changes. |
| fw_setenv (mtd-utils) |
Writes one or more key=value pairs atomically — reads env, modifies all specified vars, writes entire env back in one operation. Multiple vars in one call are atomic. Build mtd-utils with --enable-ubifs for full UBI volume support. |
| /etc/fw_env.config |
Tells fw_printenv/fw_setenv where the env lives. Format differs by backend:
Raw NAND: /dev/mtd1 0x0 0x20000 0x20000
UBI volume: /dev/ubi0_1 0x0 0x20000 (UBI handles geometry)
|
| ubinize.cfg | Partition layout file used to create the UBI image at build time. Must declare the uboot-env and uboot-env-redund static volumes alongside the rootfs and data volumes. Both env volumes must be ≥ CONFIG_ENV_SIZE. |