summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Berkman <[email protected]>2026-03-18 14:15:15 -0700
committerTom Rini <[email protected]>2026-04-02 10:18:50 -0600
commitff7039032b7de3549b9b287b2c000c9e96c60380 (patch)
tree37b54110caca7b9cc49a9abf0db1e36d17d798b6
parent98cf83d81617f489d7ff7bf78d33e693e2799254 (diff)
env: flash: add catch-all for unrecognized flags in env_flash_init()
When both environment copies have valid CRCs but the flag bytes do not match any recognized pair, env_flash_init() falls through without setting gd->env_addr or gd->env_valid. This is a problem because: 1. env_init() then sets gd->env_addr = &default_environment (in RAM). 2. In env_flash_load(), the pointer comparison gd->env_addr != &flash_addr->data evaluates true (RAM != flash), triggering the pointer swap that selects the secondary copy. 3. The repair logic writes OBSOLETE (0x00) to the non-active flag but cannot promote the other flag from 0x00 to ACTIVE (0x01) because NOR flash requires a sector erase to set bits. Both copies end up with flag=0x00. 4. On every subsequent boot, flag1 == flag2 triggers the ENV_REDUND path, printing a spurious "recovered successfully" warning until an explicit saveenv erases and rewrites the sectors. The recognized flag values are ACTIVE (0x01), OBSOLETE (0x00), and erased (0xFF). Of the 256 possible flag values, the existing chain of if/else-if handles only three: 253 of 256 values fall through without setting gd->env_addr. Combined with 0x00 (already stuck on NOR), 254 of 256 values eventually reach the persistent-warning state. Other env backends (SPI flash, NAND, MMC) handle this through env_check_redund() in env/common.c, which uses a numeric comparison of the flags as a serial counter and always reaches a decision. The CFI flash backend is the only one that uses its own flag-matching logic. Add a catch-all else clause that defaults to the primary copy with ENV_REDUND status, matching the existing behavior for the flag1==flag2 case. This ensures gd->env_addr is always set, preventing the unintended pointer swap. The condition is recoverable via saveenv. Signed-off-by: Neil Berkman <[email protected]> Reproducer: https://gist.github.com/neilberkman/4155612a7942d3f510f204eb85e61943 The SPI flash backend (env/sf.c) has a related but distinct issue: it retained legacy boolean save semantics but its load path now uses the common serial-number logic in env_check_redund(), creating an inconsistency under interrupted updates. That has wider implications for fw_env.c and would need separate discussion.
-rw-r--r--env/flash.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/env/flash.c b/env/flash.c
index 0f7393d830c..31dd1656e72 100644
--- a/env/flash.c
+++ b/env/flash.c
@@ -108,6 +108,14 @@ static int env_flash_init(void)
} else if (flag2 == 0xFF) {
gd->env_addr = addr2;
gd->env_valid = ENV_REDUND;
+ } else {
+ /*
+ * Unrecognized flag pair (e.g. bit-flip on NOR flash).
+ * Default to primary copy to prevent unintended pointer
+ * swap in env_flash_load().
+ */
+ gd->env_addr = addr1;
+ gd->env_valid = ENV_REDUND;
}
return 0;