Revert adaptive RAK app-owned bootloader recovery after ACL test

This commit is contained in:
mikecarper committed 2026-09-27 15:07:29 -07:00
1 parent a007346561
commit ea40663f09
17 files changed
+49 -521

No files matched your search

-183
View File
@@ -18,7 +18,6 @@
#include "OtaSelf.h" // SelfFwInfo / ota_self_firmware (running-image base_hash gate)
#endif
#elif defined(NRF52_PLATFORM)
#include <SHA256.h>
#include "OtaVerify.h"
#include "OtaSelf.h"
#include "OtaFlashLayout_nrf52.h"
@@ -27,9 +26,7 @@
#include "nrf.h"
#include "nrf_soc.h"
#include "nrf_sdm.h"
#include "nrf_mbr.h"
#include "../nrf52/SoftDeviceState.h"
#include <stdlib.h>
#if defined(OTA_SD_STORE)
#include "OtaStoreSdNrf52.h"
#endif
@@ -471,31 +468,6 @@ static OtaStoreFlashNrf52* g_nrf52_apply_store = nullptr;
#if defined(OTA_QSPI_STORE)
static uint8_t g_nrf52_qspi_handoff = GPREGRET2_OTA_STAGE_QSPI;
#endif
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
// Set only after the exact-board signed image has been copied to the internal
// source and independently hashed there. Mesh drains the LoRa reply first.
static bool g_rak_recovery_ready = false;
static uint8_t g_rak_recovery_hash[32] = {0};
static bool ota_rak_recovery_source_hash_matches() {
SHA256 sha;
const uint8_t* image = (const uint8_t*)(uintptr_t)MOTA_NRF52_SHARED_BOOT_STAGE_START;
for (uint32_t off = 0; off < OTA_BOOT_IMAGE_SIZE; off += 512u)
sha.update(image + off, 512u);
uint8_t hash[32];
sha.finalize(hash, sizeof(hash));
return memcmp(hash, g_rak_recovery_hash, sizeof(hash)) == 0;
}
static bool ota_rak_mbr_addresses_ready() {
const uint32_t mbr_boot = *(const volatile uint32_t*)(uintptr_t)MBR_BOOTLOADER_ADDR;
const uint32_t mbr_params = *(const volatile uint32_t*)(uintptr_t)MBR_PARAM_PAGE_ADDR;
const uint32_t boot = mbr_boot == UINT32_MAX ? NRF_UICR->NRFFW[0] : mbr_boot;
const uint32_t params = mbr_params == UINT32_MAX ? NRF_UICR->NRFFW[1] : mbr_params;
return boot == OTA_BOOT_IMAGE_START &&
params == OTA_BOOT_IMAGE_START + OTA_BOOT_IMAGE_SIZE;
}
#endif
static void ota_nrf52_set_reset_handoff(uint8_t request, uint8_t source) {
uint8_t sd_en = 0;
@@ -568,40 +540,6 @@ void ota_reboot_to_apply() { // public: set the apply magic +
}
void ota_reboot_to_bootloader_update() {
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
if (g_rak_recovery_ready) {
// COPY_BL succeeds by resetting directly into the new bootloader. Never
// hand 0x6B to an older adaptive loader: it cannot consume this package.
if (!ota_rak_mbr_addresses_ready() ||
!ota_rak_recovery_source_hash_matches()) {
g_rak_recovery_ready = false;
ota_nrf52_set_reset_handoff(0u, GPREGRET2_RAK_RECOVERY_FAILED);
NVIC_SystemReset();
return;
}
uint8_t sd_enabled = 0;
if (mesh_nrf52::softdeviceIsEnabled(sd_enabled) != NRF_SUCCESS ||
(sd_enabled && sd_softdevice_disable() != NRF_SUCCESS)) {
g_rak_recovery_ready = false;
ota_nrf52_set_reset_handoff(0u, GPREGRET2_RAK_RECOVERY_FAILED);
NVIC_SystemReset();
return;
}
sd_mbr_command_t command = {};
command.command = SD_MBR_COMMAND_COPY_BL;
command.params.copy_bl.bl_src =
(uint32_t*)(uintptr_t)MOTA_NRF52_SHARED_BOOT_STAGE_START;
command.params.copy_bl.bl_len = OTA_BOOT_IMAGE_SIZE / sizeof(uint32_t);
NRF_POWER->GPREGRET = 0u;
NRF_POWER->GPREGRET2 = 0u;
(void)sd_mbr_command(&command); // success never returns
g_rak_recovery_ready = false;
NRF_POWER->GPREGRET = 0u;
NRF_POWER->GPREGRET2 = GPREGRET2_RAK_RECOVERY_FAILED;
NVIC_SystemReset();
return;
}
#endif
uint8_t source = GPREGRET2_OTA_STAGE_QSPI;
#if defined(OTA_INTERNAL_BOOTLOADER_UPDATE)
source = GPREGRET2_OTA_STAGE_EXPANDED;
@@ -1076,127 +1014,6 @@ static const char* ota_bootloader_continuity_error(OtaBootloaderContinuityGate g
}
}
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
bool ota_prepare_rak_bootloader_recovery(OtaStore& store, bool internal,
const SignerAllowlist& allow,
const OtaBootloaderIdentity& installed,
const uint8_t actual_mid[4],
const uint8_t operator_mid[4],
const uint8_t operator_hash8[8],
ApplyState& st, char* msg) {
st = ApplyState();
g_rak_recovery_ready = false;
const uint32_t total = store.staged_size();
uint8_t header[8], manifest[MOTA_MFL];
MotaManifest m;
if (total != MOTA_NRF52_BOOT_CONTAINER_SIZE ||
!store.read(0, header, sizeof(header)) ||
memcmp(header, MOTA_MAGIC, sizeof(MOTA_MAGIC)) != 0 ||
rd_u32le(header + 4) != total ||
!store.read(8, manifest, sizeof(manifest)) ||
!mota_parse_manifest(manifest, sizeof(manifest), m)) {
strcpy(msg, "recovery bootloader container is invalid"); return false;
}
if (ota_bootloader_confirmation_gate(m, installed, actual_mid, operator_mid,
operator_hash8) != OTA_BOOT_CONFIRM_OK) {
strcpy(msg, "recovery bootloader identity/MID/hash confirmation failed"); return false;
}
const OtaBlCaps current = ota_bootloader_app_caps();
const uint8_t rak_flags = OTA_BL_PROFILE_RAK_AUTO;
if (!current.present || current.storage_flags != rak_flags ||
current.apply_abi < MOTA_APP_FORMAT_VER ||
(current.codec_mask & OTA_BL_REQUIRED_APP_CODEC_MASK) !=
OTA_BL_REQUIRED_APP_CODEC_MASK) {
strcpy(msg, "installed bootloader is not the adaptive RAK OTAFIX profile"); return false;
}
SelfFwInfo fi;
const uint32_t app_base = mota_nrf52_app_base();
if (!ota_self_firmware(fi) ||
!ota_bootloader_scratch_headroom_valid(
fi.valid, app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START) ||
!ota_bootloader_live_bank_preserves_scratch(
app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START) ||
ota_nrf52_effective_stage_ceiling() != MOTA_NRF52_APP_END ||
!ota_rak_mbr_addresses_ready()) {
strcpy(msg, "running app/settings or MBR do not preserve bootloader scratch"); return false;
}
if (internal) {
OtaStoreFlashNrf52& flash = static_cast<OtaStoreFlashNrf52&>(store);
if (flash.write_start() != MOTA_NRF52_SHARED_BOOT_STAGE_START ||
!flash.data() || flash.is_hybrid()) {
strcpy(msg, "internal recovery container placement is invalid"); return false;
}
}
const uint32_t payload_off = 8u + MOTA_MFL + (uint32_t)m.block_count * 4u;
if (payload_off != 365u || payload_off + OTA_BOOT_IMAGE_SIZE + 5u != total) {
strcpy(msg, "recovery payload layout is invalid"); return false;
}
mesh::Identity signer(m.signer_pubkey);
if (!signer.verify(m.signature, m.manifest_start, (int)m.signed_len) ||
!allow.contains(m.signer_pubkey)) {
strcpy(msg, "recovery bootloader signer is not trusted"); return false;
}
const VerifyResult verified = ota_verify(store, allow, manifest);
st.manifest_ok = verified.parsed;
st.sig_ok = verified.sig_ok;
st.trusted = verified.trusted;
st.image_size = m.image_size;
memcpy(st.image_hash, m.image_hash, sizeof(st.image_hash));
if (!verified.auto_appliable() || !verified.container_hash_ok) {
strcpy(msg, "recovery bootloader package failed full verification"); return false;
}
uint8_t vectors[8];
OtaBootloaderIdentity candidate;
OtaBootloaderCapsMarker candidate_caps;
if (!store.read(payload_off, vectors, sizeof(vectors)) ||
!ota_bootloader_vector_sane(vectors) ||
!ota_bootloader_external_image_metadata(
store, payload_off, rak_flags, candidate, candidate_caps, false) ||
!ota_bootloader_identity_matches(installed, candidate) ||
candidate_caps.apply_abi < current.apply_abi ||
(candidate_caps.codec_mask & current.codec_mask) != current.codec_mask) {
strcpy(msg, "recovery candidate identity/capabilities/CRC mismatch"); return false;
}
const OtaBootloaderContinuityGate continuity = ota_bootloader_continuity_gate(
installed, candidate, m.fw_version, OTA_BOOT_CONTINUITY_FAMILY_S140,
ota_runtime_softdevice_fwid(), app_base, OTA_BOOT_CONTINUITY_LAYOUT_ABI);
if (continuity != OTA_BOOT_CONTINUITY_OK) {
strncpy(msg, ota_bootloader_continuity_error(continuity), 96);
msg[95] = 0; return false;
}
uint8_t* page = static_cast<uint8_t*>(malloc(MOTA_NRF52_FLASH_PAGE));
if (!page) { strcpy(msg, "not enough RAM for recovery copy"); return false; }
bool copied = true;
for (uint32_t off = 0; off < OTA_BOOT_IMAGE_SIZE; off += MOTA_NRF52_FLASH_PAGE) {
const uint32_t dest = MOTA_NRF52_SHARED_BOOT_STAGE_START + off;
// Internal packages overlap the destination by 365 bytes. Read the next
// complete source page before erasing the lower destination page.
if (!store.read(payload_off + off, page, MOTA_NRF52_FLASH_PAGE) ||
flash_nrf5x_write(dest, page, MOTA_NRF52_FLASH_PAGE) < 0) {
copied = false; break;
}
flash_nrf5x_flush();
if (memcmp((const void*)(uintptr_t)dest, page, MOTA_NRF52_FLASH_PAGE) != 0) {
copied = false; break;
}
}
free(page);
if (!copied) {
strcpy(msg, "recovery scratch copy/readback failed; bootloader unchanged"); return false;
}
memcpy(g_rak_recovery_hash, m.image_hash, sizeof(g_rak_recovery_hash));
if (!ota_rak_recovery_source_hash_matches()) {
strcpy(msg, "recovery scratch hash mismatch; bootloader unchanged"); return false;
}
st.slot_ok = true;
g_rak_recovery_ready = true;
strcpy(msg, "signed bootloader copied and verified; MBR install follows this reply");
return true;
}
#endif
#if defined(OTA_SD_BOOTLOADER_UPDATE)
static bool external_bootloader_approve(OtaStoreSdNrf52& store,
const uint8_t image_hash[32],
-15
View File
@@ -15,8 +15,6 @@
namespace mesh {
namespace ota {
class OtaStore;
struct ApplyState {
bool manifest_ok = false;
bool sig_ok = false;
@@ -133,19 +131,6 @@ bool ota_prepare_bootloader_update_nrf52(OtaStoreFlashNrf52& store,
ApplyState& st, char* msg);
#endif
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
// Application-owned recovery for adaptive RAK loaders lacking BOOT_UPDATE.
// Copies a verified full bootloader from either active store into internal
// scratch; deferred commit invokes Nordic's MBR after the LoRa reply drains.
bool ota_prepare_rak_bootloader_recovery(OtaStore& store, bool internal,
const SignerAllowlist& allow,
const OtaBootloaderIdentity& installed,
const uint8_t actual_mid[4],
const uint8_t operator_mid[4],
const uint8_t operator_hash8[8],
ApplyState& st, char* msg);
#endif
// Commit the (already approved/armed) update and reboot into it - does NOT return. Call this only after
// a successful ota_apply_* AND after the confirmation reply has been delivered, so the operator knows
// the apply started (over LoRa the device then goes silent while the bootloader applies). nRF52: set
-3
View File
@@ -93,9 +93,6 @@ static const uint8_t OTA_BL_PROFILE_INTERNAL_BOOT_UPDATE =
static const uint8_t OTA_BL_PROFILE_QSPI_BOOT_UPDATE =
OTA_BL_STORAGE_STAGE_CEILING | OTA_BL_STORAGE_QSPI |
OTA_BL_STORAGE_BOOT_UPDATE;
static const uint8_t OTA_BL_PROFILE_RAK_AUTO =
OTA_BL_STORAGE_STAGE_CEILING | OTA_BL_STORAGE_QSPI |
OTA_BL_STORAGE_HEADER_W25;
// A successor must retain both application update paths used by qualified
// external stores: bit 0 CODEC_FULL and bit 2 CODEC_DETOOLS_INPLACE.
static const uint16_t OTA_BL_REQUIRED_APP_CODEC_MASK = 0x0005u;
+6 -21
View File
@@ -32,17 +32,6 @@
#endif
#endif
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
#if !defined(NRF52_PLATFORM) || !defined(OTA_RAK_AUTO_STORE) || \
!defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || !defined(OTA_FLASH_STORE) || \
!defined(OTA_QSPI_STORE)
#error "RAK application recovery requires the adaptive nRF52 shared-slot profile"
#endif
#if !defined(RAK_3401) && !defined(RAK_4631)
#error "RAK application recovery is restricted to the two qualified RAK profiles"
#endif
#endif
#if defined(OTA_SD_BOOTLOADER_UPDATE)
#if !defined(NRF52_PLATFORM) || !defined(OTA_SD_STORE)
#error "OTA_SD_BOOTLOADER_UPDATE requires nRF52 SD staging"
@@ -523,19 +512,17 @@ inline bool ota_bootloader_caps_marker_parse(const uint8_t raw[16],
inline bool ota_bootloader_caps_from_image(const uint8_t* image, size_t image_size,
uint8_t exact_storage_flags,
OtaBootloaderCapsMarker& out,
bool require_boot_update = true) {
OtaBootloaderCapsMarker& out) {
out = OtaBootloaderCapsMarker();
if (!image || exact_storage_flags == 0) return false;
uint8_t valid_count = 0;
for (size_t off = 0; off + 16u <= image_size; off += 4u) {
OtaBootloaderCapsMarker parsed;
if (!ota_bootloader_caps_marker_parse(image + off, parsed) ||
parsed.apply_abi < (require_boot_update ? MOTA_BOOT_FORMAT_VER : MOTA_APP_FORMAT_VER) ||
parsed.apply_abi < MOTA_BOOT_FORMAT_VER ||
(parsed.codec_mask & OTA_BL_REQUIRED_APP_CODEC_MASK) !=
OTA_BL_REQUIRED_APP_CODEC_MASK ||
((parsed.storage_flags & OTA_BL_STORAGE_BOOT_UPDATE) != 0u) !=
require_boot_update) continue;
(parsed.storage_flags & OTA_BL_STORAGE_BOOT_UPDATE) == 0) continue;
if (++valid_count != 1u) return false; // privileged marker identity must be unambiguous
if (parsed.storage_flags != exact_storage_flags) continue;
out = parsed;
@@ -569,8 +556,7 @@ inline bool ota_bootloader_external_crc_ok(
template <typename Store>
inline bool ota_bootloader_external_image_metadata(
Store& store, uint32_t payload_off, uint8_t exact_storage_flags,
OtaBootloaderIdentity& candidate, OtaBootloaderCapsMarker& caps,
bool require_boot_update = true) {
OtaBootloaderIdentity& candidate, OtaBootloaderCapsMarker& caps) {
candidate = OtaBootloaderIdentity();
caps = OtaBootloaderCapsMarker();
if (exact_storage_flags == 0u) return false;
@@ -590,11 +576,10 @@ inline bool ota_bootloader_external_image_metadata(
if ((absolute & 3u) == 0u && local + 16u <= len) {
OtaBootloaderCapsMarker parsed;
if (ota_bootloader_caps_marker_parse(buf + local, parsed) &&
parsed.apply_abi >= (require_boot_update ? MOTA_BOOT_FORMAT_VER : MOTA_APP_FORMAT_VER) &&
parsed.apply_abi >= MOTA_BOOT_FORMAT_VER &&
(parsed.codec_mask & OTA_BL_REQUIRED_APP_CODEC_MASK) ==
OTA_BL_REQUIRED_APP_CODEC_MASK &&
((parsed.storage_flags & OTA_BL_STORAGE_BOOT_UPDATE) != 0u) ==
require_boot_update) {
(parsed.storage_flags & OTA_BL_STORAGE_BOOT_UPDATE) != 0u) {
if (++valid_caps != 1u) return false;
if (parsed.storage_flags == exact_storage_flags) caps = parsed;
}
+2 -38
View File
@@ -400,17 +400,11 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
const OtaBootloaderIdentity& bid = c.bootloaderIdentity();
installable = h->flags == (MFLAG_FULL | MFLAG_SIGNED | MFLAG_BOOTLOADER) &&
h->codec == CODEC_FULL && bid.present && bid.crc_ok &&
h->target_id == ota_bootloader_target_id(bid);
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
installable = installable &&
list_bl.storage_flags == OTA_BL_PROFILE_RAK_AUTO &&
(c.fetch_store.usesExternal() || c.fetch_store.usesInternal());
#else
installable = installable && ota_bootloader_self_update_caps_valid(list_bl_update);
h->target_id == ota_bootloader_target_id(bid) &&
ota_bootloader_self_update_caps_valid(list_bl_update);
#if defined(OTA_SD_BOOTLOADER_UPDATE)
installable = installable && list_sd_headroom;
#endif
#endif
#endif
fit = installable ? "yours" : "bootloader unsupported";
} else if (myt && h->target_id == myt) {
@@ -547,11 +541,7 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
(defined(OTA_QSPI_BOOTLOADER_UPDATE) || defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || \
defined(OTA_SD_BOOTLOADER_UPDATE))
const OtaBootloaderIdentity& bid = c.bootloaderIdentity();
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
const OtaBlCaps& bl = c.bootloaderAppCaps();
#else
const OtaBlCaps& bl = c.bootloaderUpdateCaps();
#endif
if (selflags != (MFLAG_FULL | MFLAG_SIGNED | MFLAG_BOOTLOADER) ||
selcodec != CODEC_FULL) {
strcpy(reply, "ERR malformed bootloader catalog row; capture it to folder for inspection");
@@ -561,17 +551,10 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
strcpy(reply, "ERR bootloader package does not match this installed bootloader identity");
return true;
}
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
if (bl.storage_flags != OTA_BL_PROFILE_RAK_AUTO) {
strcpy(reply, "ERR installed bootloader is not the adaptive RAK profile");
return true;
}
#else
if (!ota_bootloader_self_update_caps_valid(bl)) {
strcpy(reply, "ERR installed bootloader lacks safe LoRa bootloader-update support");
return true;
}
#endif
#if defined(OTA_SD_BOOTLOADER_UPDATE)
SelfFwInfo sd_self;
if (!ota_self_firmware(sd_self) ||
@@ -596,21 +579,13 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
return true;
}
#if defined(NRF52_PLATFORM)
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
const OtaBlCaps& bl = c.bootloaderAppCaps();
#else
const OtaBlCaps& bl = selboot ? c.bootloaderUpdateCaps()
: c.bootloaderAppCaps();
#endif
if (!bl.present) {
strcpy(reply, "ERR bootloader has no mOTA apply support; update it over USB first");
return true;
}
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
const uint8_t need_abi = MOTA_APP_FORMAT_VER;
#else
const uint8_t need_abi = selboot ? MOTA_BOOT_FORMAT_VER : MOTA_APP_FORMAT_VER;
#endif
if (bl.apply_abi < need_abi || selcodec >= 16 || !(bl.codec_mask & (1u << selcodec))) {
snprintf(reply, 160, "ERR bootloader cannot apply mOTA ABI %u codec %u (has abi=%u codecs=0x%x)",
need_abi, (unsigned)selcodec, bl.apply_abi, bl.codec_mask);
@@ -883,27 +858,16 @@ bool handle_ota_command(const char* command, char* reply, mesh::MainBoard& board
(defined(OTA_QSPI_BOOTLOADER_UPDATE) || defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || \
defined(OTA_SD_BOOTLOADER_UPDATE))
const OtaBootloaderIdentity& bid = c.bootloaderIdentity();
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
const OtaBlCaps& bl = c.bootloaderAppCaps();
#else
const OtaBlCaps& bl = c.bootloaderUpdateCaps();
#endif
if (*rest == 0 || strcmp(rest, "status") == 0) {
if (!bid.present || !bid.crc_ok) {
strcpy(reply, "Bootloader update unavailable: installed embedded manifest/CRC is invalid");
return true;
}
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
if (bl.storage_flags != OTA_BL_PROFILE_RAK_AUTO) {
strcpy(reply, "Bootloader recovery unavailable: installed loader is not adaptive RAK OTAFIX");
return true;
}
#else
if (!ota_bootloader_self_update_caps_valid(bl)) {
strcpy(reply, "Bootloader update unavailable: installed bootloader supports application OTA only");
return true;
}
#endif
MotaManifest staged;
char midhx[9] = "-", hashhx[17] = "-";
const bool ready = c.manager.fetchState() == OtaManager::COMPLETE &&
-21
View File
@@ -359,19 +359,6 @@ struct OtaContext {
}
const OtaBootloaderIdentity& installed = bootloaderIdentity();
#if defined(OTA_RAK_AUTO_STORE)
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
if (!fetch_store.usesInternal() && !fetch_store.usesExternal()) {
strncpy(msg, fetch_store.selectionReason(), 96);
msg[95] = 0; return false;
}
const bool internal = fetch_store.usesInternal();
OtaStore& recovery_store = internal
? static_cast<OtaStore&>(fetch_store.internalStore())
: static_cast<OtaStore&>(fetch_store.externalStore());
bool ok = ota_prepare_rak_bootloader_recovery(
recovery_store, internal, allow, installed,
manager.fetchManifestId(), operator_mid, operator_hash8, apply_st, msg);
#else
if (!fetch_store.usesInternal()) {
strncpy(msg, "bootloader LoRa update needs the internal OTAFIX profile", 96);
msg[95] = 0; return false;
@@ -379,7 +366,6 @@ struct OtaContext {
bool ok = ota_prepare_bootloader_update_nrf52(
fetch_store.internalStore(), allow, installed, manager.fetchManifestId(), operator_mid,
operator_hash8, apply_st, msg);
#endif
#else
bool ok = ota_prepare_bootloader_update_nrf52(
fetch_store, allow, installed, manager.fetchManifestId(), operator_mid,
@@ -718,15 +704,8 @@ struct OtaContext {
(defined(OTA_QSPI_BOOTLOADER_UPDATE) || defined(OTA_INTERNAL_BOOTLOADER_UPDATE) || \
defined(OTA_SD_BOOTLOADER_UPDATE))
#if defined(OTA_RAK_AUTO_STORE)
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
manager.set_accept_bootloader(
(fetch_store.usesInternal() || fetch_store.usesExternal()) &&
bootloaderIdentity().crc_ok &&
bootloaderAppCaps().storage_flags == OTA_BL_PROFILE_RAK_AUTO);
#else
manager.set_accept_bootloader(fetch_store.usesInternal() &&
ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps()));
#endif
#else
manager.set_accept_bootloader(true);
#endif
-1
View File
@@ -52,7 +52,6 @@ static const uint32_t MOTA_NRF52_FLASH_PAGE = 4096u;
static const uint32_t MOTA_NRF52_CONTAINER_MIN_SIZE = 8u + 197u + 5u;
static const uint8_t GPREGRET_OTA_APPLY = 0x6Au; // distinct from DFU magics 0x57/0x4E/0xA8
static const uint8_t GPREGRET_OTA_BOOTLOADER_UPDATE = 0x6Bu;
static const uint8_t GPREGRET2_RAK_RECOVERY_FAILED = 0xCEu;
static const uint8_t GPREGRET2_OTA_STAGE_LEGACY = 0xD4u;
static const uint8_t GPREGRET2_OTA_STAGE_EXPANDED = 0xEDu;
static const uint8_t GPREGRET2_OTA_STAGE_QSPI = 0x51u;
+5 -29
View File
@@ -4,7 +4,6 @@
#include "OtaSelf.h"
#include "OtaBlInfo.h"
#include "OtaBootloaderUpdate.h"
#include "MotaContainer.h"
#include "OtaDebug.h"
#include "OtaByteIO.h" // align_down / rd_u32le (flash-page geometry + header read)
@@ -155,11 +154,7 @@ bool OtaStoreFlashNrf52::plan_layout(bool is_full, uint32_t image_size,
#if defined(OTA_INTERNAL_BOOTLOADER_UPDATE)
if (!is_full || image_size != 40u * 1024u || payload_size != 40u * 1024u ||
payload_off != 365u || total64 != MOTA_NRF52_BOOT_CONTAINER_SIZE ||
!(ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps())
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
|| ota_bootloader_app_caps().storage_flags == OTA_BL_PROFILE_RAK_AUTO
#endif
))
!ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps()))
return false;
// This is the release-blocking no-EndF gate: package kind is known before
@@ -170,12 +165,7 @@ bool OtaStoreFlashNrf52::plan_layout(bool is_full, uint32_t image_size,
const uint32_t app_base = mota_nrf52_app_base();
if (!ota_self_firmware(fi) || !fi.valid || fi.image_len > UINT32_MAX - app_base ||
!mota_nrf52_shared_boot_stage_plan(
(uint32_t)total64, app_base, true, app_base + fi.image_len, start)
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
|| !ota_bootloader_live_bank_preserves_scratch(
app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START)
#endif
)
(uint32_t)total64, app_base, true, app_base + fi.image_len, start))
return false;
_planned_bootloader = true;
_planned_total = (uint32_t)total64;
@@ -355,12 +345,7 @@ bool OtaStoreFlashNrf52::begin(uint32_t total_size) {
!ota_self_firmware(fi) || !fi.valid || fi.image_len > UINT32_MAX - app_base ||
!mota_nrf52_shared_boot_stage_plan(
total_size, app_base, true, app_base + fi.image_len, checked_start) ||
checked_start != planned_start
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
|| !ota_bootloader_live_bank_preserves_scratch(
app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START)
#endif
)
checked_start != planned_start)
return false;
app_end = app_base + fi.image_len;
#else
@@ -612,19 +597,10 @@ bool OtaStoreFlashNrf52::reopenFor(const uint8_t* want_mid, uint32_t expected_ta
if (bootloader) {
#if defined(OTA_INTERNAL_BOOTLOADER_UPDATE)
SelfFwInfo fi;
if (!(ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps())
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
|| ota_bootloader_app_caps().storage_flags == OTA_BL_PROFILE_RAK_AUTO
#endif
) ||
if (!ota_bootloader_self_update_caps_valid(ota_bootloader_update_caps()) ||
!ota_self_firmware(fi) || !fi.valid || fi.image_len > UINT32_MAX - app_base ||
!mota_nrf52_shared_boot_stage_plan(
total, app_base, true, app_base + fi.image_len, want) || want != start
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
|| !ota_bootloader_live_bank_preserves_scratch(
app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START)
#endif
)
total, app_base, true, app_base + fi.image_len, want) || want != start)
continue;
#else
continue;
+2 -26
View File
@@ -4,10 +4,6 @@
#include "OtaByteIO.h"
#include "OtaFlashLayout_nrf52.h"
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
#include "OtaBootloaderUpdate.h"
#include "OtaSelf.h"
#endif
#include "hal/nrf_gpio.h"
#include "hal/nrf_qspi.h"
#include "nrf.h"
@@ -889,9 +885,8 @@ uint32_t OtaStoreQspiNrf52::capacity() const {
return result;
}
bool OtaStoreQspiNrf52::plan_layout(bool is_full, uint32_t image_size,
uint32_t payload_off, uint32_t payload_size,
bool is_bootloader) {
bool OtaStoreQspiNrf52::plan_layout(bool, uint32_t image_size, uint32_t,
uint32_t payload_size, bool) {
// This is the start of a new manifest admission attempt. Clear diagnostics
// left by the normal empty-store reopen probe, then latch the first error
// from this attempt until the operator reads it or starts another attempt.
@@ -900,25 +895,6 @@ bool OtaStoreQspiNrf52::plan_layout(bool is_full, uint32_t image_size,
_stage = OtaQspiStage::IDLE;
const uint32_t app_base = mota_nrf52_app_base();
const uint32_t app_ceiling = mota_nrf52_application_ceiling();
#if defined(OTA_RAK_BOOTLOADER_RECOVERY)
if (is_bootloader) {
SelfFwInfo fi;
if (!is_full || image_size != OTA_BOOT_IMAGE_SIZE ||
payload_size != OTA_BOOT_IMAGE_SIZE || payload_off != 365u ||
ota_nrf52_effective_stage_ceiling() != MOTA_NRF52_APP_END ||
!ota_self_firmware(fi) ||
!ota_bootloader_scratch_headroom_valid(
fi.valid, app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START) ||
!ota_bootloader_live_bank_preserves_scratch(
app_base, fi.image_len, MOTA_NRF52_SHARED_BOOT_STAGE_START)) {
fail("recovery scratch is unavailable");
releaseFlash();
return false;
}
}
#else
(void)is_full; (void)payload_off; (void)is_bootloader;
#endif
if (image_size == 0 || payload_size == 0 || app_base >= app_ceiling ||
image_size > app_ceiling - app_base) {
fail("image exceeds nRF52 application region");