Add shared-slot nRF52 bootloader updates

This commit is contained in:
mikecarper committed 2026-08-21 00:55:01 -07:00
1 parent b7c9e37d09
commit 3de5fddf47
43 files changed
+1647 -211

No files matched your search

+4 -4
View File
@@ -165,8 +165,8 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without
| LoRa OTA | [`ota ls`; `ota neighbors`; `ota nbrs`; `ota updates`; `ota n`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes |
| LoRa OTA | [`ota get`; `ota pull`; `ota download`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build; internal-store nRF52 installs in-place deltas, while matched SD/QSPI nRF52 also accepts full images | No | No | Yes |
| LoRa OTA | [`ota install`; `ota apply`; `ota applydelta`](ota_protocol.md#11-cli-surface-otaclicpp) | Compatible bootloader and completed update | No | No | Yes |
| LoRa OTA | [`ota rescue install <base_hash16>`](ota_protocol.md#12-apply-bootloader-contract) | Internal-flash nRF52 LoRa OTA build with failed app-side EndF validation | No | No | Feature |
| LoRa OTA | [`ota bootloader`; `ota bootloader install <MID8> <HASH16>`](ota_nrf52_qspi.md#explicit-xiao-bootloader-updates-over-lora) | Boot-update-capable XIAO-module QSPI repeater with ABI-3 exact-board OTAFIX | No | No | Feature |
| LoRa OTA | [`ota rescue install <base_hash16>`](ota_protocol.md#12-apply-bootloader-contract) | Legacy internal-flash nRF52 LoRa OTA build with failed app-side EndF validation; shared bootloader-update builds require valid EndF | No | No | Feature |
| LoRa OTA | [`ota bootloader`; `ota bootloader install <MID8> <HASH16>`](ota_nrf52_bootloader_update.md) | Allowlisted internal-flash or XIAO-QSPI nRF52 repeater with ABI-3 exact-board OTAFIX | No | No | Feature |
| LoRa OTA | [`ota cancel`; `ota drop`; `ota stop`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes |
| LoRa OTA | [`ota announce`; `ota adv`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes |
| LoRa OTA | [`ota self`; `ota id`](ota_protocol.md#11-cli-surface-otaclicpp) | Firmware with EndF trailer | No | No | Yes |
@@ -325,8 +325,8 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without
| LoRa OTA | [`ota ls`; `ota neighbors`; `ota nbrs`; `ota updates`; `ota n`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes | Yes | Yes |
| LoRa OTA | [`ota get`; `ota pull`; `ota download`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes | Yes | Yes |
| LoRa OTA | [`ota install`; `ota apply`; `ota applydelta`](ota_protocol.md#11-cli-surface-otaclicpp) | Compatible completed update | No | No | Yes | Yes | Yes |
| LoRa OTA | [`ota rescue install <base_hash16>`](ota_protocol.md#12-apply-bootloader-contract) | Internal-flash nRF52 LoRa OTA build with failed app-side EndF validation | No | No | Feature | No | No |
| LoRa OTA | [`ota bootloader`; `ota bootloader install <MID8> <HASH16>`](ota_nrf52_qspi.md#explicit-xiao-bootloader-updates-over-lora) | nRF52 XIAO QSPI only | No | No | No | No | No |
| LoRa OTA | [`ota rescue install <base_hash16>`](ota_protocol.md#12-apply-bootloader-contract) | Legacy internal-flash nRF52 LoRa OTA build with failed app-side EndF validation; shared bootloader-update builds require valid EndF | No | No | Feature | No | No |
| LoRa OTA | [`ota bootloader`; `ota bootloader install <MID8> <HASH16>`](ota_nrf52_bootloader_update.md) | Allowlisted nRF52 internal/QSPI repeater feature | No | No | No | No | No |
| LoRa OTA | [`ota cancel`; `ota drop`; `ota stop`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes | Yes | Yes |
| LoRa OTA | [`ota announce`; `ota adv`](ota_protocol.md#11-cli-surface-otaclicpp) | LoRa OTA build | No | No | Yes | Yes | Yes |
| LoRa OTA | [`ota self`; `ota id`](ota_protocol.md#11-cli-surface-otaclicpp) | Firmware with EndF trailer | No | No | Yes | Yes | Yes |
+1
View File
@@ -12,6 +12,7 @@ Below are a few quick start guides.
- [Easy LoRa OTA: ESP32 and nRF52 firmware updates](./ota_easy.md)
- [Scripted LoRa OTA: Bash and PowerShell](./lora_ota_automation.md)
- [nRF52 repeater OTA with external QSPI](./ota_nrf52_qspi.md)
- [nRF52 bootloader updates over LoRa](./ota_nrf52_bootloader_update.md)
- [MeshTower V2 microSD self-updates](./ota_meshtower_v2_sdcard.md)
- [GPS Tracking](./gps_tracking.md)
- [Companion Protocol](./companion_protocol.md)
+4 -4
View File
@@ -16,10 +16,10 @@ controller, and check the rebooted node.
The script cannot install the destination's first OTA-capable firmware. It is
also deliberately application-only: it rejects both v3 bootloader containers
and a v2 container carrying the bootloader flag, and it never sends the
privileged install command. Do the first nRF52 bootloader installation over USB;
an already-capable XIAO QSPI repeater may later use the separate, manual
[`ota bootloader install`](ota_nrf52_qspi.md#explicit-xiao-bootloader-updates-over-lora)
workflow.
privileged install command. Do the first nRF52 bootloader installation over USB.
An already-capable, explicitly supported internal-flash or XIAO QSPI repeater
may later use the separate manual
[`ota bootloader install`](ota_nrf52_bootloader_update.md) workflow.
## Required topology
+8 -4
View File
@@ -334,18 +334,22 @@ shows an older row. Select `[same target]`: it can say `full` for ESP32 and exte
or `delta` for any supported nRF52 target. Do not select `[unsupported]` (for example, a source's self-served
full image on an internal-staging nRF52).
Rows labelled `bootloader` are also outside this ordinary application flow:
they are never automatic and `ota install` refuses them. Only an already-capable
XIAO QSPI repeater can use the separate
[explicit bootloader workflow](ota_nrf52_qspi.md#explicit-xiao-bootloader-updates-over-lora).
they are never automatic and `ota install` refuses them. Only an
already-capable, allowlisted internal-flash or XIAO-QSPI nRF52 target can use
the separate [explicit bootloader workflow](ota_nrf52_bootloader_update.md).
Use the row's stable eight-hex manifest ID rather than its changing list position:
```text
ota pull 838B8169 flash
```
If an internal-flash nRF52 reports `no EndF`, only a row marked `[rescue]` is eligible. Current rescue-capable
If a legacy internal-flash nRF52 reports `no EndF`, only a row marked `[rescue]` is eligible. Current rescue-capable
firmware requires `ota pull <mid8> flash rescue`, followed after completion by
`ota rescue install <base_hash16>`. Older running firmware without those commands must be recovered over USB.
Shared-internal bootloader-update builds are stricter: without a valid live
`EndF`, every internal pull is refused before erase because the normal
application may extend through `0xED000`. Recover those builds over USB/BLE DFU
or SWD instead of relying on the older 608 KiB rescue estimate.
Monitor the transfer:
+150
View File
@@ -0,0 +1,150 @@
# nRF52 bootloader updates over LoRa
Selected nRF52840 repeater LoRa-OTA builds can replace their matching OTAFIX
bootloader without replacing the running application. This is a privileged
maintenance path, not a normal firmware update. It cannot bootstrap a stock or
older bootloader: install the exact ABI-3 self-update-capable OTAFIX build once
over USB/BLE DFU or SWD.
## Storage layouts
| Layout | Application limit | Staged boot package | Work area | Handoff / capability |
| --- | ---: | ---: | ---: | --- |
| XIAO-module raw QSPI | below `0xE0000` | external QSPI offset 0 | dedicated internal `0xE0000..0xEA000` scratch | source `0x51`, flags `0x0E` |
| Qualified internal-flash target | normal `0xED000` limit | shared internal slot, exact start `0xE2000` | the same eleven-page slot; no second reservation | source `0xED`, flags `0x0A` |
The internal path does not change the application linker or permanently set
aside separate app-OTA, boot-package, and scratch regions. The ordinary
bottom-aligned internal store holds one container at a time: either an
application delta or a bootloader package.
The exact bootloader container is 41,330 bytes: 365 bytes of signed mOTA
metadata, a 40 KiB payload, and the five-byte trailer. Below the normal
`0xED000` store ceiling it bottom-aligns at `0xE2000`. Admission requires a
hash-valid live `EndF` proving the current application, including its trailer,
ends at or before `0xE2000`. OTAFIX then reads each source window before
erasing and compacts the payload forward in place to the page-aligned raw range
`0xE2000..0xEC000`; it verifies every page and the whole image before asking the
MBR to copy that image over `0xF4000..0xFE000`.
An ordinary application delta can be smaller or larger than this eleven-page
shape. It bottom-aligns dynamically below `0xED000` and may begin below
`0xE2000`; its detools workspace must stop at its actual container start, while
the reconstructed application must stop below `0xED000`. The two package kinds
are mutually exclusive because they use the same store.
For internal-self-update builds, an absent or corrupt live `EndF` disables
**all** internal staging before the first erase. The older 608 KiB rescue
estimate is unsafe when a normally linked application may extend to
`0xED000`. Builds without this feature retain the legacy rescue behavior.
## Internal-flash target inventory
The release builder consumes the allowlist in
`tools/mota/nrf52_internal_bootloader_targets.txt`. Ten names are also literal
PlatformIO environments and are enabled automatically when built directly.
The other eleven are release aliases assembled from a base environment plus
the lean OTA overlay; build them through `build.sh`, which passes the same
allowlist decision to the common pre-build guard. These lean repeater/bridge
targets have no OTA-owned SD/QSPI store and have an exact curated OTAFIX
manifest identity:
| Build target(s) | Installed OTAFIX identity | Boot target ID |
| --- | --- | ---: |
| `Heltec_tower_v2_repeater_lora_ota_no_external_sensors` | `239A0071 / TOWER_V2_OTA` | `1150F50E` |
| T096 lean repeater and RS232 bridge | `239A0071 / T096_DFU` | `42354C85` |
| `Heltec_t1_repeater_lora_ota_no_external_sensors` | `239A0071 / T1_DFU` | `FC556FFC` |
| T114 display and without-display lean repeaters | `239A0071 / T114_DFU` | `0C3F2902` |
| `Mesh_pocket_repeater_lora_ota_no_external_sensors` | `239A0071 / MESH_POCKET_OTA` | `059277F4` |
| `KeepteenLT1_repeater_lora_ota_no_external_sensors` | `239A00B3 / KeepteenLT1_OTA` | `DB2E7B51` |
| `Minewsemi_me25ls01_repeater_lora_ota_no_external_sensors` | `239A0029 / MX25_DFU` | `026AA982` |
| `ProMicro_repeater_lora_ota_no_external_sensors` | `239A00B3 / PROM_DFU` | `AF79E8CC` |
| `t1000e_repeater_lora_ota_no_external_sensors` | `28860057 / T1KE_DFU` | `E6F5F03F` |
| `ThinkNode_M3_repeater_lora_ota_no_external_sensors` | `239A00DA / TNM3_DFU` | `0CA41DB2` |
| `RAK_3401_repeater_lora_ota_no_external_sensors` | `239A0029 / 3401_DFU` | `23818A80` |
| RAK4631 lean repeater and both lean RS232 bridges | `239A0029 / 4631_DFU` | `2D0DF000` |
| GAT562 30S/Tracker Pro/EVB Pro and R1Neo lean carrier aliases | `239A0029 / 4631_DFU` | `2D0DF000` |
| `RAK_WisMesh_Tag_repeater_lora_ota_no_external_sensors` | `239A0029 / RTAG_DFU` | `C72E9C9C` |
Board IDs are not globally unique. For generic targets, the signed hardware ID
is the exact NUL-padded 32-byte value
`NRF_BL_<BOARD_ID>_<DEVICE_NAME>`. The wire target is the little-endian first
four SHA-256 bytes of all 32 padded bytes. The installed and candidate embedded
manifest pairs must match exactly. XIAO retains its deployed
`XIAO_BL_28860044` / `XIAO_BL_28860045` identity and raw board-ID target.
The Python reference builder and release tooling audit these boot targets for
duplicates and collisions with application target IDs. Generic image parsing
can inspect a future canonical identity, but signing/building a package fails
until that exact identity is in the qualified inventory.
The `no_external_sensors` profiles omit optional/add-on sensor and GPS packages
to preserve flash headroom. Board-integrated GPS can be retained by a board's
recipe. The RAK3401 lean target specifically omits RAK12501/add-on GPS; use the
ordinary full-sensor target when that module is required.
Boards with onboard external flash are not silently redirected to internal
staging. Mesh Solar, Nano G2 Ultra, T-Impulse Plus, ThinkNode M8, T-Echo
Lite/Card, MeshTracker X1, and Wio WM1110 have board-specific QSPI hardware and
need a separately matched QSPI path where available. Full Companions,
SD/QSPI/ExtraFS roles, Ethernet roles, source-only roles, and unqualified
full-sensor roles are excluded.
This internal layout is limited to nRF52840 devices with 1 MiB internal flash,
the exact S140 v6/v7 map, and the 40 KiB boot region at
`0xF4000..0xFE000`. nRF52833 and smaller nRF52 parts cannot provide that map
plus a non-overlapping 41,330-byte live staging slot, so configuration fails
closed instead of selecting smaller or overlapping geometry.
## Explicit install workflow
Check the installed identity and capability marker:
```text
ota bootloader
```
The response must show a CRC-valid exact identity, ABI 3 or newer, full codec,
and exact flags `0x0A` for internal shared storage or `0x0E` for XIAO QSPI. A
bootloader row is visible in `ota ls`, but it is never autofetched or
autoinstalled. Fetch its exact MID, then explicitly arm it:
```text
ota pull <MID8> flash
# wait for ota status to report the download ready
ota bootloader
ota bootloader install <MID8> <HASH16>
```
Copy both confirmation values from the second `ota bootloader` response.
Ordinary `ota install` rejects a bootloader package; the bootloader command
rejects an application package. The FULL-codec exception exists only for that
manual bootloader MID. Ordinary application FULL remains disabled on an
internal single-slot node, bootloader autofetch remains off, and a partial
bootloader package is not automatically resumed after an application reboot.
Before writing `APRV`, the application authenticates and authorizes the
package: exact v3 geometry, trusted Ed25519 signer, signed/embedded identity,
one unambiguous capability marker, embedded CRC, sane vectors, complete
Merkle/payload/image hashes, safe live placement, and the typed MID/hash
confirmation. OTAFIX consumes that application-written authorization and then
independently rechecks the safety/integrity subset: strict v3 structure,
canonical identity/capabilities, vectors, full payload SHA, embedded manifest
CRC, live `EndF` no-overlap geometry, page readback, and final copy hash. It
does not re-run Ed25519, the signer allowlist, Merkle leaves/root, or the typed
operator confirmation. Success is reported as `blup:C8`.
## Failure behavior
The feature fails closed when the MCU/map is wrong, current valid `EndF`
headroom is insufficient, external/ExtraFS storage owns the target, the exact
installed capability marker is absent or ambiguous, identity cannot be derived
unambiguously, or any package check fails. Before compaction, the application
and bootloader are unchanged. OTAFIX consumes the trigger/approval before the
first in-place compaction erase, so an interrupted conversion cannot retry a
partly converted package; it boots the untouched application and old
bootloader instead. Use USB/BLE DFU or SWD for initial provisioning and local
recovery.
For XIAO and ordinary external-QSPI details, see
[nRF52 repeater LoRa OTA with external QSPI](ota_nrf52_qspi.md).
+9 -2
View File
@@ -176,6 +176,11 @@ enforces the package's hardware identity before approval.
## Explicit XIAO bootloader updates over LoRa
This section documents the deployed XIAO raw-QSPI layout. Curated nRF52840
targets without external staging use a separate internal-flash layout with the
same explicit operator safety model; see
[nRF52 bootloader updates over LoRa](ota_nrf52_bootloader_update.md).
Bootloader delivery is available only when all of these are already true:
- the application is an `OTA_QSPI_BOOTLOADER_UPDATE` XIAO-module repeater build
@@ -212,8 +217,10 @@ continuity. A signed older bootloader that would remove remote update support
is refused.
After the reply drains, GPREGRET `0x6B` and GPREGRET2 `0x51` enter the special
OTAFIX path. OTAFIX independently rechecks the package before using the
reserved scratch bank to replace its own `0xF4000..0xFE000` region. The running
OTAFIX path. `APRV` carries the app's signature/allowlist and explicit operator
authorization decision. OTAFIX independently rechecks the strict structure,
identity/capabilities, vectors, payload SHA, embedded CRC, and copy hashes
before using the reserved scratch bank to replace its own `0xF4000..0xFE000` region. The running
application remains preserved; a rejected candidate returns to it unchanged.
Post-reboot `ota status` reports bootloader-update diagnostics as `blup:C0` to
`blup:CF` (`blup:C8` is success), separately from ordinary application `blrc`.
+35 -11
View File
@@ -62,7 +62,7 @@ the authoritative reference for byte-level details.
| `EndF` marker | `45 6E 64 46` | `EndF` |
| `hash_algo` (sha2-256) | `0x12` | multihash code |
| application `format_ver` | `0x02` | ordinary full/delta application package |
| bootloader `format_ver` | `0x03` | privileged XIAO bootloader package only |
| bootloader `format_ver` | `0x03` | privileged exact-identity nRF52 bootloader package only |
| `approval` = not approved | `FF FF FF FF` | erased NOR word |
| `approval` = approved | `41 50 52 56` | `APRV` |
| `MFLAG_FULL` | `0x01` | flags bit0 |
@@ -260,17 +260,19 @@ cover `approval` or `leaves[]`:
- Bound to this image (lives in this `.mota`'s manifest, re-erased when a new `.mota` is staged).
- A **consent** marker, not a security primitive. Authenticity = `signature` + `image_hash` + `hw_id`.
### 4.3 Privileged XIAO bootloader package profile
### 4.3 Privileged nRF52 bootloader package profile
A v3 bootloader package has a deliberately narrow, non-extensible profile:
- flags exactly `FULL|SIGNED|BOOTLOADER`, `CODEC_FULL`, nonzero `fw_version`, zero `base_hash`;
- a raw payload and `image_size` of exactly `0xA000` (40 KiB), split into exactly forty 1024-byte blocks;
- `target_id` equal to the installed OTAFIX embedded board ID (`0x28860044` for XIAO nRF52840 or
`0x28860045` for XIAO nRF52840 Sense);
- signed `hw_id` exactly `XIAO_BL_28860044` or `XIAO_BL_28860045`, derived from that board ID;
- a sane nRF52840 vector table, a CRC-valid embedded manifest v1 with the exact padded device name
`XIAO_DFU`, and a `MOTABLDR` marker advertising ABI >= 3, full codec, QSPI, and boot-update continuity.
- a target derived from the installed CRC-valid embedded manifest identity. Deployed XIAO identities keep
raw board IDs `0x28860044`/`0x28860045`; generic identities use LE32(SHA-256(canonical padded hw32));
- signed `hw_id` exactly `XIAO_BL_28860044`/`XIAO_BL_28860045` for deployed XIAO, or the zero-padded
32-byte `NRF_BL_<BOARD_ID>_<DEVICE_NAME>` for a generic target;
- a sane nRF52840 vector table, exactly one CRC-valid embedded manifest v1 with the exact board/name pair,
and exactly one `MOTABLDR` marker advertising ABI >= 3, full codec, boot-update continuity, and the exact
storage flags for the application layout (`0x0E` XIAO QSPI or `0x0A` shared internal staging).
The incoming embedded identity must exactly match the installed CRC-valid bootloader identity. Both scans
consider every aligned structurally valid candidate so magic bytes in a literal pool cannot shadow the real
@@ -770,7 +772,7 @@ ota get | pull | download <mid8|#index> flash [rescue] | folder [validate]
fetch by stable mid8 (preferred) or current page index
ota install | apply | applydelta verify + approve + (ESP32) apply / (nRF52) reboot-to-bootloader
ota rescue install <base_hash16> internal-flash nRF52 only: recover from failed app-side EndF validation
ota bootloader [status] capable XIAO QSPI repeater: installed BL identity/caps + staged confirmation
ota bootloader [status] capable allowlisted nRF52 repeater: installed BL identity/caps + staged confirmation
ota bootloader install <MID8> <HASH16>
explicitly verify/arm one complete trusted v3 package; never automatic
ota cancel | drop | stop drop the current fetch session (frees the slot)
@@ -805,7 +807,9 @@ ota dev ... bring-up helpers (stage/recv/serve/verify)
- **nRF52 internal staging ceiling:** an internal-store application derives the ceiling from facts available
in every build, not a board-name list. A companion that actually links the internal ExtraFS datastore stays
below `0xD4000`; a default linker region or a role that does not mount ExtraFS can reclaim the unused
100 KiB through `0xED000`. The application uses the larger window only when the
100 KiB through `0xED000`. An internal bootloader-self-update target keeps that normal linker and ceiling;
it does not reserve a second boot-package or scratch region. The application uses a larger-than-legacy
window only when the
installed bootloader advertises the GPREGRET2 ceiling-handoff capability. The bootloader treats every
unknown/legacy handoff value as
`0xD4000`, and accepts a container only at the bottom-aligned position for the selected ceiling.
@@ -832,6 +836,9 @@ ota dev ... bring-up helpers (stage/recv/serve/verify)
fails, so a rescue-capable bridge can fetch its exact successor before invoking the guarded command. Such
a node must acknowledge the condition up front with `ota pull <mid8> flash rescue`; an ordinary flash pull
refuses before altering staged data. Firmware that predates both rescue commands still requires USB recovery.
Internal-bootloader-self-update builds are a stricter exception: because their ordinary linker may extend
through `0xED000`, an absent/corrupt live `EndF` disables every internal staging pull before erase instead
of trusting the legacy 608 KiB estimate.
- **MeshTower V2 SD nRF52:** the application stores a contiguous `/meshcore-ota.mota` on microSD and
publishes its raw sector range in a checksummed handoff record outside the MBR partition. The matching
bootloader reads the card without mounting FAT, supports either a full image or an in-place delta,
@@ -852,10 +859,27 @@ ota dev ... bring-up helpers (stage/recv/serve/verify)
`ota bootloader install <MID8> <HASH16>`. The app repeats the strict v3 geometry, installed/candidate
identity, vectors, embedded CRC/capabilities, complete payload/image hashes, signature, and trusted-key
gates before writing `APRV`. GPREGRET `0x6B` plus GPREGRET2 `0x51` hands the QSPI package to OTAFIX.
OTAFIX independently repeats all privileged checks, uses the scratch bank to preserve the running
application while replacing `0xF4000..0xFE000`, and reports boot-update results in GPREGRET2 `0xC0..0xCF`
`APRV` carries the app's authenticated and explicitly confirmed authorization decision; OTAFIX does not
repeat Ed25519/allowlist, Merkle, or typed operator confirmation. It independently rechecks the strict v3
structure, canonical identity/capabilities, vectors, payload SHA, embedded CRC, and scratch/copy hashes,
uses the scratch bank to preserve the running application while replacing `0xF4000..0xFE000`, and reports
boot-update results in GPREGRET2 `0xC0..0xCF`
(`0xC8` success). This mechanism cannot bootstrap a stock/older bootloader; install an ABI-3,
boot-update-capable exact-board OTAFIX over USB/BLE DFU or SWD once first.
- **Internal-flash bootloader self-update (explicit only):** curated nRF52840 lean repeater/bridge targets
without an OTA-owned SD/QSPI store share the normal bottom-aligned internal store below `0xED000`.
It holds either an ordinary app delta or the exact 41,330-byte v3 container, never both. The boot package
bottom-aligns at `0xE2000`; a hash-valid live `EndF` must prove the complete running image ends at or below
that address before the first erase. OTAFIX reads each source window before erasing and compacts the
payload forward in the same eleven pages to raw `0xE2000..0xEC000`; no separate scratch bank or special
application linker exists. GPREGRET `0x6B` plus GPREGRET2 `0xED` selects boot update, while ordinary app
apply uses GPREGRET `0x6A` plus the same storage source. Exact installed/candidate capability flags are
`0x0A` (`STAGE_CEILING|BOOT_UPDATE`). Ordinary deltas remain dynamically sized, may start below
`0xE2000`, and reconstruct only below the normal `0xED000` app ceiling. The same signature, explicit
confirmation, exact identity, vector, CRC, and single-marker rules as the XIAO path apply. Bootloader FULL
admission is isolated from ordinary application FULL policy, and privileged partials are never resumed
automatically after an application reboot. See
[the nRF52 bootloader-update guide](ota_nrf52_bootloader_update.md) for the exact target inventory.
A signature, when present, proves author authenticity and must pass the device allowlist. Unsigned v2
application packages remain installable when local policy permits them. A v3 bootloader package is always
+30 -19
View File
@@ -216,21 +216,22 @@ rejected; trusted signed images can auto-install only when that policy is enable
After it reboots, run `ota status` to confirm the new version.
### Updating a XIAO bootloader (advanced, explicit only)
### Updating an nRF52 bootloader (advanced, explicit only)
This is available only on the specially marked XIAO nRF52840/Sense QSPI
repeater builds after a one-time exact-board ABI-3 OTAFIX installation over
USB/BLE DFU or SWD. It is not the normal firmware update path. Check support
first:
This is available on specially marked no-external-flash nRF52840 lean
repeater/bridge builds and on the legacy XIAO nRF52840/Sense raw-QSPI builds,
after a one-time exact-board ABI-3 OTAFIX installation over USB/BLE DFU or
SWD. It is not the normal firmware update path. Check support first:
```text
ota bootloader
```
The reply must show a valid `XIAO_DFU` board identity plus ABI 3 and the QSPI /
boot-update capability bits. A bootloader package appears as `bootloader` in
`ota ls`. It is never downloaded or installed automatically, even if both OTA
automation settings are enabled. Use its stable ID explicitly:
The reply must show a CRC-valid installed identity plus ABI 3 and the exact
storage/boot-update capability bits for that build (`0x0A` for the shared
internal store or `0x0E` for XIAO raw QSPI). A bootloader package appears as
`bootloader` in `ota ls`. It is never downloaded or installed automatically,
even if both OTA automation settings are enabled. Use its stable ID explicitly:
```text
ota pull <MID8> flash
@@ -241,19 +242,25 @@ ota bootloader install <MID8> <HASH16>
Copy both confirmation values exactly from the second `ota bootloader` reply.
Ordinary `ota install` deliberately refuses this package. The privileged
command requires an exact 40 KiB candidate for the installed XIAO board, a
valid embedded identity/CRC and vector table, continued boot-update support,
and a valid signature from a key already in `ota key`'s trusted allowlist. It
preserves the running application while OTAFIX replaces itself; `blup:C8` in
post-reboot `ota status` means success. Any node lacking this command or those
capabilities must update its bootloader locally instead. See
[the nRF52 QSPI guide](ota_nrf52_qspi.md#explicit-xiao-bootloader-updates-over-lora)
for the complete safety contract.
command requires an exact 40 KiB candidate payload in the fixed 41,330-byte
container, a valid exact embedded identity/CRC and vector table, continued
boot-update support, and a valid signature from a key already in `ota key`'s
trusted allowlist. It preserves the running application while OTAFIX replaces
itself; `blup:C8` in post-reboot `ota status` means success. Any node lacking
this command or those capabilities must update its bootloader locally instead.
On an internal-flash target, the package shares the ordinary store below
`0xED000` and bottom-aligns at `0xE2000`; there is no separate reserved scratch
bank. A valid live `EndF` must prove the current image ends at or below that
address before any page is erased. If `EndF` is missing/corrupt or the app is
too large, the pull is refused and local DFU/SWD is required.
See [the nRF52 bootloader-update guide](ota_nrf52_bootloader_update.md) for the
complete target inventory, storage layouts, and safety contract.
### 5. If something goes wrong
- A download that stalls or gets interrupted just **resumes** later, or you can `ota cancel` and try again.
- An internal-flash **nRF52** that still runs but reports `no EndF` can use the pre-provisioned rescue path
- A legacy app-only internal-flash **nRF52** that still runs but reports `no EndF` can use the pre-provisioned rescue path
if its physical EndF is intact and only app-side validation is failing. Fetch the exact `[rescue]`
in-place delta with an explicit acknowledgement, obtain its 16-hex-digit `base_hash` from the package
metadata, then run:
@@ -269,6 +276,10 @@ for the complete safety contract.
the running app and rejects a wrong base before writing the app. If the physical EndF is absent or the
rescue commands were not already in the running firmware, recover over USB.
Release chains should put this command in their first bridge and keep it in every bridge after that.
The shared-internal bootloader-update builds are intentionally excluded:
without valid live `EndF`, they refuse every internal pull before erase
because their normal application can extend through `0xED000`. Recover one
of those builds over USB/BLE DFU or SWD.
- If an **install** fails, the node won't boot a broken image - it lands in **recovery mode**:
- **nRF52:** it appears as a USB drive; drag a known-good firmware `.uf2` for that exact board onto it
to recover.
@@ -398,7 +409,7 @@ that only contains what changed). You get them by:
| Download a listed update for installation | `ota get <mid8> flash` |
| Cancel a download | `ota cancel` |
| Install a finished download | `ota install` |
| Recover app-side `no EndF` on internal nRF52 | `ota rescue install <base_hash16>` |
| Recover app-side `no EndF` on a legacy app-only internal nRF52 | `ota rescue install <base_hash16>` |
| Turn on auto-download | `ota config autofetch any` |
| Turn on auto-install (trusted only) | `ota config autoinstall trusted` |
| Trust a signer | `ota key add <hex>` |