Configuration
What this page covers: All Kconfig options, DeviceTree partition setup, and sizing guidelines for UBI.
Prerequisites: Overview and Getting Started.
UBI is configured via Zephyr’s Kconfig system and DeviceTree overlays.
Kconfig Options
Enable UBI and its options in your prj.conf:
CONFIG_UBI_ENABLE=y
Option Reference
Option |
Type |
Default |
Range |
Description |
|---|---|---|---|---|
|
bool |
n |
— |
Enable the UBI subsystem |
|
bool |
y |
— |
Use |
|
bool |
n |
— |
Use |
|
int |
1 |
1–4 |
Maximum number of concurrent UBI device handles (static backend) |
|
int |
14 |
1–4096 |
Maximum data PEBs per device (static backend pool sizing) |
|
bool |
n |
— |
Enable slab pool usage statistics (static backend only) |
|
int |
2 |
2–4 |
Number of reserved PEBs for device/volume metadata |
|
int |
10 |
1–128 |
Maximum number of volumes per device |
|
int |
3 |
1–5 |
Flash write retries on data PEBs before marking bad |
|
int |
3 |
1–10 |
Bad PEBs tortured per |
|
int |
1 |
1–10 |
Max erase attempts per bad PEB during torture |
|
choice |
INF |
— |
Log verbosity: OFF, ERR, WRN, INF, DBG |
|
bool |
n |
— |
Enable test-only APIs ( |
|
bool |
n |
— |
Controllable allocation failure hook for simulating OOM. Depends on |
|
bool |
n |
— |
Enable the secure (authenticated-encryption) backend. Requires Mbed TLS PSA Crypto. |
|
int |
4 |
1–255 |
Maximum distinct key versions per attach session. Sizes per-key-version bookkeeping arrays. |
|
int |
4 |
1–255 |
Maximum entries in |
|
int |
1000000 |
— |
Max metadata AEAD invocations per {domain, key_version} before KEY_ROTATE event. |
|
int |
100000000 |
— |
Max cumulative authenticated metadata bytes per {domain, key_version}. |
|
int |
1000000 |
— |
Max LEB AEAD invocations per {key_version, volume_id}. |
|
int |
100000000 |
— |
Max cumulative authenticated LEB bytes per {key_version, volume_id}. |
|
int |
80 |
1–99 |
Soft rotation threshold (%). Emits KEY_ROTATE_SOON. |
|
int |
95 |
1–100 |
Hard rotation threshold (%). Emits KEY_ROTATE_NOW; writes may be rejected. |
|
bool |
n |
— |
Use chunked LEB layout: multiple AEAD tags per LEB for partial-read authentication (§7.8). |
|
int |
4096 |
256–65536 |
Chunk size in bytes (must be multiple of flash write alignment). Smaller = finer reads, more tag overhead. |
|
bool |
y |
— |
Allocate a PEB-sized staging buffer for secure encrypt/decrypt. Required for secure I/O. |
|
bool |
n |
— |
Allocate PEB staging buffer at compile time (else per-device at init). |
|
int |
0 |
0–65535 |
Mutations between sync_freshness callbacks. 0 = sync after every commit. |
|
bool |
y |
— |
Enter read-only mode on RNG failure instead of only rejecting the current write. |
|
bool |
y |
— |
Enter read-only on freshness policy rejection or rollback mismatch. |
|
bool |
n |
— |
Enter read-only when sync_freshness callback errors. |
|
bool |
n |
— |
Secure backend fault injection (PSA crypto failures). Depends on |
Memory Backend
UBI supports two memory backends, selected at compile time via a Kconfig choice:
Static (
CONFIG_UBI_MEM_BACKEND_STATIC, default): All allocations usek_mem_slabpools sized at compile time. Provides deterministic RAM budget and full isolation from the application heap. Pool sizes are derived fromCONFIG_UBI_MAX_NR_OF_DEVICES,CONFIG_UBI_MAX_NR_OF_DATA_PEBS, andCONFIG_UBI_MAX_NR_OF_VOLUMES.Heap (
CONFIG_UBI_MEM_BACKEND_HEAP): Delegates tok_malloc/k_free(legacy behaviour). Useful for prototyping or when pool sizing is unknown.
When to use each:
Use case |
Recommended backend |
|---|---|
Production deployment |
STATIC — deterministic, no fragmentation |
Prototyping / unknown flash geometry |
HEAP — no pool sizing required |
Multiple UBI devices |
STATIC — set |
Memory Sizing Guide
Under the static backend, all pool memory is pre-allocated at compile time. The total RAM budget is:
Pool |
Formula |
Example (D=14, V=2) |
|---|---|---|
Device slab |
|
1 × 136 = 136 B |
Volume slab |
|
1 × 10 × 44 = 440 B |
Leaf slab |
|
1 × (14+10) × 16 = 384 B |
Scratch slab |
|
32 + 10 × 48 = 512 B (or 2×4096+16 = 8208 B with chunked) |
Total |
~1,464 B |
At init time, ubi_device_init() verifies that the actual flash geometry fits within the configured pools. If the flash partition has more data PEBs than CONFIG_UBI_MAX_NR_OF_DATA_PEBS, init returns -ENOMEM.
Impact Analysis
Option |
Flash layout |
RAM usage |
Recovery / robustness |
Performance |
|---|---|---|---|---|
|
No impact |
Pre-allocated pools (known at compile time) |
No fragmentation risk |
O(1) slab alloc |
|
No impact |
Dynamic; proportional to PEBs + volumes |
Subject to heap fragmentation |
k_malloc overhead |
|
No impact |
Multiplies all pool sizes |
No impact |
No impact |
|
No impact |
16 B per PEB in leaf slab |
Init fails if flash has more data PEBs |
No impact |
|
More reserved PEBs = fewer data PEBs |
+16 B per additional reserved PEB (RBT node) |
Higher = more redundancy for metadata; 3–4 adds cold spares |
No measurable impact |
|
Limits volume headers stored in reserved PEBs |
+48 B per volume + 16 B per volume RBT node |
No direct impact |
No measurable impact |
|
No impact |
No impact |
Higher = more chances to recover from transient write errors |
Higher = slower failure path (more retries) |
|
No impact |
No impact |
Higher = more aggressive bad block recovery attempts |
Higher = longer |
|
No impact |
No impact |
Higher = more erase attempts per bad PEB |
Higher = longer per-PEB torture |
Log Level
UBI uses Zephyr’s logging subsystem. Set the log level in prj.conf:
# Show only errors
CONFIG_UBI_LOG_LEVEL_ERR=y
# Debug everything
CONFIG_UBI_LOG_LEVEL_DBG=y
Flash Partition (DeviceTree)
UBI requires a named flash partition defined in a DeviceTree overlay. The partition label is referenced at compile time via FIXED_PARTITION_ID() and FIXED_PARTITION_DEVICE().
native_sim (simulator)
&flash0 {
erase-block-size = <8192>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
ubi_partition: partition@0 {
label = "ubi_partition";
reg = <0x00000000 DT_SIZE_K(128)>;
};
};
};
b_u585i_iot02a (STM32U5)
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
ubi_partition: partition@d0000 {
label = "ubi_partition";
reg = <0x000d0000 DT_SIZE_K(128)>;
};
};
};
nrf5340dk/nrf5340/cpuapp (nRF5340 DK)
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
ubi_partition: partition@f0000 {
label = "ubi_partition";
reg = <0x000f0000 DT_SIZE_K(64)>;
};
};
};
nRF5340 has 4 KB erase blocks (vs 8 KB on STM32U5). With 64 KB the partition yields 16 PEBs (2 reserved, 14 data), matching the default CONFIG_UBI_MAX_NR_OF_DATA_PEBS.
Sizing Guidelines
Minimum: At least
N + 2PEBs (N reserved + 2 data), where N =CONFIG_UBI_DEV_HDR_NR_OF_RES_PEBS. In practice, use >= 8 PEBs.Reserved PEBs: The first N PEBs are reserved for device/volume metadata (configurable via
CONFIG_UBI_DEV_HDR_NR_OF_RES_PEBS, default 2). Only PEBs N..total-1 are available for volume data.LEB size:
erase_block_size - 48bytes (48 bytes are consumed by EC + VID headers on each data PEB).Example (STM32U5): With 8 KB erase blocks and 128 KB partition: 16 total PEBs, 2 reserved, 14 data PEBs, each with 8144 B usable per LEB.
Example (nRF5340): With 4 KB erase blocks and 64 KB partition: 16 total PEBs, 2 reserved, 14 data PEBs, each with 4048 B usable per LEB.
Zephyr Module Integration
UBI registers as a Zephyr module via zephyr/module.yml. When using west, add UBI as a project in your west.yml:
manifest:
projects:
- name: ubi
url: https://github.com/kamil-kielbasa/ubi
revision: main
path: module/lib/ubi
Then initialize and update:
west init -l .
west update --narrow -o=--depth=1