mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-20 13:52:10 +00:00
120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
"""Give the pinned Bluefruit DFU service a safe FreeRTOS bootloader handoff.
|
|
|
|
The original callback selects MSP while its C frame is still on PSP. GCC 14
|
|
then emits a stack restore on MSP before reaching the bootloader jump, outside
|
|
the nRF52840 SRAM boundary. Keep the legacy B1/retained-peer protocol, but move
|
|
the stack transition into a naked, nonreturning assembly helper. Patch a private
|
|
build copy; never modify PlatformIO's shared framework cache.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
OLD_HELPER = 'extern "C" void bootloader_util_app_start(uint32_t start_addr);\n'
|
|
HELPER_NAME = "mesh_nrf52_dfu_jump"
|
|
HELPER = r'''// Keep all stack operations inside this assembly-only transition. In particular,
|
|
// the callback must return neither through its PSP frame nor through a C helper
|
|
// after CONTROL selects MSP. Preserve handler-mode entry supported by BLEDfu.
|
|
extern "C" __attribute__((naked, noinline, noreturn, used))
|
|
void mesh_nrf52_dfu_jump(uint32_t start_addr)
|
|
{
|
|
__asm volatile (
|
|
"cpsid i\n"
|
|
"mrs r3, ipsr\n"
|
|
"ldr r1, [r0]\n"
|
|
"ldr r2, [r0, #4]\n"
|
|
"msr msp, r1\n"
|
|
"movs r0, #0\n"
|
|
"msr control, r0\n"
|
|
"msr basepri, r0\n"
|
|
"msr faultmask, r0\n"
|
|
"dsb\n"
|
|
"isb\n"
|
|
"cmp r3, #0\n"
|
|
"bne 1f\n"
|
|
"mvn lr, #0\n"
|
|
"cpsie i\n"
|
|
"bx r2\n"
|
|
"1:\n"
|
|
"sub sp, sp, #32\n"
|
|
"str r0, [sp, #0]\n"
|
|
"str r0, [sp, #4]\n"
|
|
"str r0, [sp, #8]\n"
|
|
"str r0, [sp, #12]\n"
|
|
"str r0, [sp, #16]\n"
|
|
"mvn r0, #0\n"
|
|
"str r0, [sp, #20]\n"
|
|
"str r2, [sp, #24]\n"
|
|
"mov r0, #0x21000000\n"
|
|
"str r0, [sp, #28]\n"
|
|
"mvn lr, #6\n"
|
|
"cpsie i\n"
|
|
"bx lr\n"
|
|
);
|
|
}
|
|
'''
|
|
|
|
OLD_INTERRUPTS = ''' // Disable all interrupts
|
|
NVIC->ICER[0]=0xFFFFFFFF;
|
|
NVIC->ICPR[0]=0xFFFFFFFF;
|
|
#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2
|
|
NVIC->ICER[1]=0xFFFFFFFF;
|
|
NVIC->ICPR[1]=0xFFFFFFFF;
|
|
#endif
|
|
'''
|
|
INTERRUPTS = ''' // nRF52 has external IRQs in both banks. FreeRTOS system exceptions
|
|
// need separate cleanup: they are not covered by NVIC->ICER/ICPR.
|
|
SysTick->CTRL = 0;
|
|
SysTick->LOAD = 0;
|
|
SysTick->VAL = 0;
|
|
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk | SCB_ICSR_PENDSVCLR_Msk;
|
|
NVIC->ICER[0] = 0xFFFFFFFF;
|
|
NVIC->ICER[1] = 0xFFFFFFFF;
|
|
NVIC->ICPR[0] = 0xFFFFFFFF;
|
|
NVIC->ICPR[1] = 0xFFFFFFFF;
|
|
__DSB();
|
|
__ISB();
|
|
'''
|
|
OLD_JUMP = ''' __set_CONTROL(0); // switch to MSP, required if using FreeRTOS
|
|
bootloader_util_app_start(NRF_UICR->NRFFW[0]);
|
|
'''
|
|
JUMP = ''' // The vector-table SVC above must complete before the helper masks
|
|
// interrupts. B1 and the retained peer record preserve legacy DFU entry.
|
|
mesh_nrf52_dfu_jump(NRF_UICR->NRFFW[0]);
|
|
'''
|
|
|
|
|
|
def patched_source(source):
|
|
source = source.replace("\r\n", "\n")
|
|
replacements = ((OLD_HELPER, HELPER), (OLD_INTERRUPTS, INTERRUPTS),
|
|
(OLD_JUMP, JUMP))
|
|
if all(new in source and old not in source for old, new in replacements):
|
|
return source
|
|
if any(source.count(old) != 1 for old, _ in replacements):
|
|
raise RuntimeError(
|
|
"nRF52 BLE DFU handoff: unrecognized framework source; "
|
|
"review the framework update before building"
|
|
)
|
|
for old, new in replacements:
|
|
source = source.replace(old, new)
|
|
return source
|
|
|
|
|
|
def replace_framework_source(build_env, node):
|
|
source = Path(node.srcnode().get_abspath())
|
|
if source.name != "BLEDfu.cpp" or source.parent.name != "services":
|
|
return node
|
|
patched = patched_source(source.read_text(encoding="utf-8"))
|
|
build_env.AppendUnique(CPPPATH=[str(source.parent), str(source.parent.parent)])
|
|
destination = Path(build_env.subst("$BUILD_DIR")) / "patched-nrf52-ble" / source.name
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
if not destination.exists() or destination.read_text(encoding="utf-8") != patched:
|
|
destination.write_text(patched, encoding="utf-8")
|
|
print("nRF52 BLE: private FreeRTOS-safe DFU handoff")
|
|
return build_env.File(str(destination))
|
|
|
|
|
|
if "Import" in globals():
|
|
Import("env")
|
|
env.AddBuildMiddleware(replace_framework_source, "*BLEDfu.cpp")
|