Add shared-slot nRF52 bootloader updates
This commit is contained in:
1 parent
b7c9e37d09
commit
3de5fddf47
43 files changed
+1647
-211
No files matched your search
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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).
|
||||
@@ -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
@@ -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
@@ -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>` |
|
||||
|
||||
Reference in new issue
Block a user