nx_mcu_brick.nx
buildroot/runtime/nx_mcu_brick.nx
about
nx_mcu_brick.nx -- Rule-26 reversibility classifier for persistent-state writes on MCU targets.
WHY THIS EXISTS: Rule 26 is absolute and brand-critical, and it demands the never-brick guarantee be
PROVEN MECHANICALLY, never asserted as a promise. Flashing an ESP32 writes persistent hardware state.
So the guard is built BEFORE the gun: this classifier exists before any flashing capability does, and
it is the function a write chokepoint must call. A capability gated only inside a gate IS the baseline.
THE SILICON FACTS THIS ENCODES (verified 2026-07-31 against Espressif ESP-IDF security docs):
- eFuses are ONE-TIME PROGRAMMABLE. Default bit value is 0 after manufacturing and once set they
cannot be reverted. So EVERY eFuse burn is irreversible BY CONSTRUCTION, not by policy.
- SPI flash writes ARE recoverable: the first-stage bootloader lives in unerasable mask ROM and
re-enters UART download mode, so a bad app image is re-flashable -- annoying, not a brick.
- THE KEYSTONE, and the whole reason this is a function and not a constant: that recovery path is
ITSELF an eFuse. Burning DIS_DOWNLOAD_MODE (CONFIG_SECURE_DISABLE_ROM_DL_MODE, or a runtime
esp_efuse_disable_rom_download_mode() call) permanently removes it. The instant download mode is
burned, the ENTIRE flash surface converts from reversible to irreversible.
Hence flash-class writes are GREEN only while the recovery path is intact -- reversibility is
CONDITIONAL, never intrinsic. Anything undeclared is RED, fail-closed, because an unclassified write
is precisely the case where we do not know whether it bricks.
license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 1 imports · 3 importers
imports: nx_syscalls.nx
imported by: nx_eqprobe.nxnx_mcu_ready.nxnx_neverbrick_gate.nx
structs
| none |
consts
| 25 | const NB_VOLATILE: i64 = 0 |
| 26 | const NB_REVERSIBLE: i64 = 1 |
| 27 | const NB_IRREVERSIBLE: i64 = 2 |
| 28 | const NB_UNKNOWN: i64 = 3 |
| 31 | const NB_GREEN: i64 = 0 |
| 32 | const NB_RED: i64 = 1 |
| 35 | const NB_DL_INTACT: i64 = 1 |
| 36 | const NB_DL_BURNED: i64 = 0 |
functions
| 38 | func nb_streq(a: *u8, b: *u8) -> i64 |
| 52 | func nb_class_of_ns(ns: *u8) -> i64 |
| 63 | func nb_efuse_kills_recovery(field: *u8) -> i64 |
| 79 | func nb_verdict(ns: *u8, dl_state: i64) -> i64 |
| 90 | func nb_verdict_efuse(field: *u8) -> i64 called by 1: main |