Revert adaptive RAK app-owned bootloader recovery after ACL test
This commit is contained in:
1 parent
a007346561
commit
ea40663f09
17 files changed
+49
-521
No files matched your search
@@ -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,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in new issue
Block a user