mirror of
https://github.com/meshtastic/firmware.git
synced 2026-08-01 10:58:30 -04:00
71 lines
2.9 KiB
Python
71 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
# trunk-ignore-all(ruff/F821)
|
|
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
|
#
|
|
# Post-link guard for the warm-node-store raw-flash region on nRF52840.
|
|
#
|
|
# The 3 app-region pages below LittleFS (0xEA000-0xED000, reclaimed by whole-image
|
|
# LTO) are reserved for the WarmNodeStore record-ring (see WarmNodeStore.h). Our
|
|
# linker scripts (nrf52840_s140_v6.ld and nrf52840_s140_v7.ld) cap the image at
|
|
# 0xEA000, but boards on the framework-default script (FLASH ending at 0xED000) could
|
|
# silently place code in those pages - the first warm-store save would then brick the
|
|
# device. This turns that into a build failure.
|
|
#
|
|
# Image flash end = __etext + sizeof(.data) (loaded at LMA __etext); symbols from
|
|
# the framework's nrf52_common.ld.
|
|
import os
|
|
|
|
Import("env")
|
|
|
|
WARM_REGION_BASE = 0xEA000 # keep in sync with WARM_FLASH_REGION_BASE in WarmNodeStore.h (3 x 4 KB record-ring)
|
|
|
|
_tc = env.PioPlatform().get_package_dir("toolchain-gccarmnoneeabi") or ""
|
|
_NM = os.path.join(_tc, "bin", "arm-none-eabi-nm")
|
|
if not os.path.isfile(_NM):
|
|
_NM = "arm-none-eabi-nm" # fall back to PATH
|
|
|
|
|
|
def _assert_warm_region_clear(source, target, env):
|
|
import subprocess
|
|
import sys
|
|
|
|
try:
|
|
elf = env.subst("$BUILD_DIR/${PROGNAME}.elf")
|
|
out = subprocess.check_output([_NM, elf], universal_newlines=True)
|
|
except Exception as exc: # tooling hiccup: warn loudly, don't wedge the build
|
|
print("nrf52_warm_region: WARNING - guard skipped (nm failed: %s)" % exc)
|
|
return
|
|
|
|
syms = {}
|
|
for line in out.split("\n"):
|
|
f = line.split()
|
|
if len(f) >= 3 and f[-1] in ("__etext", "__data_start__", "__data_end__"):
|
|
syms[f[-1]] = int(f[0], 16)
|
|
if len(syms) != 3:
|
|
print("nrf52_warm_region: WARNING - guard skipped (linker symbols not found)")
|
|
return
|
|
|
|
flash_end = syms["__etext"] + (syms["__data_end__"] - syms["__data_start__"])
|
|
if flash_end > WARM_REGION_BASE:
|
|
sys.stderr.write(
|
|
"\n*** nrf52 warm-region guard: image ends at 0x%X, past the reserved "
|
|
"warm-store region at 0x%X ***\n"
|
|
"The 12 KB region at 0xEA000 holds the WarmNodeStore record-ring; a warm-store\n"
|
|
"save would overwrite this firmware's tail. Shrink the image, or shrink/move\n"
|
|
"the region (WARM_FLASH_REGION_BASE in src/mesh/WarmNodeStore.h, the FLASH\n"
|
|
"LENGTH in src/platform/nrf52/nrf52840_s140_v6.ld and _v7.ld, and this guard).\n\n"
|
|
% (flash_end, WARM_REGION_BASE)
|
|
)
|
|
from SCons.Script import Exit
|
|
|
|
Exit(1)
|
|
print(
|
|
"nrf52_warm_region: guard OK -- image ends at 0x%X, %d KB clear of the warm region"
|
|
% (flash_end, (WARM_REGION_BASE - flash_end) // 1024)
|
|
)
|
|
|
|
|
|
# Attach to the phony "buildprog" alias (not the .elf node) so the guard runs
|
|
# on incremental relinks too -- same reasoning as nrf52_lto.py's guard.
|
|
env.AddPostAction("buildprog", _assert_warm_region_clear)
|