From 67105f8db3279c54898be42fb44548bb7adf5a87 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 15 May 2026 00:05:00 +0700 Subject: [PATCH] validate app presence more robustly, allow debugger flashing e.g with jlink without flashing the setting page --- AGENTS.md | 4 ++ .../libraries/bootloader_dfu/bootloader.c | 37 +++++++++++++------ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 67f8947..aaebd02 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -87,6 +87,10 @@ Each board lives in `src/boards/{board_name}/` with: - `DEFAULT_TO_OTA_DFU` — Default to BLE OTA instead of serial DFU - `DEBUG` — Enable RTT debugging, larger bootloader region +## PR Review Checklist + +- **VID/PID assignment**: When a PR adds or modifies a board, verify `USB_DESC_VID`/`USB_DESC_UF2_PID` in `board.h`. New boards should use unique values. The Adafruit VID `0x239A` is reserved for Adafruit-allocated boards; third-party boards must use their own VID. Some legacy boards intentionally share a VID/PID with a reference board (see `// Shared VID/PID with ...` comments) — these are pending cleanup, not a template for new boards. + ## CI GitHub Actions (`.github/workflows/githubci.yml`) builds all boards in parallel using a matrix generated from `src/boards/` directory names. On release, artifacts (zip, hex, uf2) are uploaded as release assets. diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c index bd9b8cc..500e229 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c @@ -149,23 +149,22 @@ static void wait_for_events(void) bool bootloader_app_is_valid(void) { - bool success = false; uint32_t const app_addr = DFU_BANK_0_REGION_START; - - bootloader_settings_t const *p_bootloader_settings; - bootloader_util_settings_get(&p_bootloader_settings); + uint32_t const sp_addr = *((uint32_t*)app_addr); + uint32_t const reset_addr = *((uint32_t*)(app_addr + 4)); enum { EMPTY_FLASH = 0xFFFFFFFFUL }; - // Application is invalid if first 2 words are all 0xFFFFFFF - if ( *((uint32_t *)app_addr ) == EMPTY_FLASH && - *((uint32_t *)(app_addr+4)) == EMPTY_FLASH ) + if (sp_addr == EMPTY_FLASH && reset_addr == EMPTY_FLASH) { return false; } - // The application in CODE region 1 is flagged as valid during update. - if ( p_bootloader_settings->bank_0 == BANK_VALID_APP ) + bootloader_settings_t const * p_bootloader_settings; + bootloader_util_settings_get(&p_bootloader_settings); + + // Primary path: a prior DFU flagged bank 0 as valid. + if (p_bootloader_settings->bank_0 == BANK_VALID_APP) { uint16_t image_crc = 0; @@ -177,10 +176,26 @@ bool bootloader_app_is_valid(void) NULL); } - success = (image_crc == p_bootloader_settings->bank_0_crc); + return (image_crc == p_bootloader_settings->bank_0_crc); } - return success; + // Fallback for debugger-flashed apps: settings page is erased (bank_0 = 0xFFFF) + // but an app may still have been written to bank 0 directly. Accept it if its + // Cortex-M vector table is plausible: initial SP within RAM, reset vector + // within app flash region with the Thumb bit set. The SP upper bound is + // inclusive because the empty-descending stack initializes one past RAM end. + if (p_bootloader_settings->bank_0 == 0xFFFF) + { + uint32_t const ram_start = 0x20000000UL; + uint32_t const ram_end = ram_start + (NRF_FICR->INFO.RAM << 10u); + bool const sp_valid = (sp_addr >= ram_start) && (sp_addr <= ram_end) && ((sp_addr & 3U) == 0); + bool const reset_in_app = (reset_addr & 1U) && + (reset_addr >= app_addr) && + (reset_addr < BOOTLOADER_REGION_START); + return sp_valid && reset_in_app; + } + + return false; }