mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-07-26 16:28:06 +08:00
fix(bootloader): remove broken PROTO_SET_DELAY boot-delay feature (#27081)
The bootloader boot-delay feature has been mechanically broken on every modern FMU board since the STM32F7/H7 transition. It has three independent bugs that prevent it from ever working: 1. Offset mismatch: BOOT_DELAY_ADDRESS is hardcoded to 0x1a0, but the NuttX vector table is 504 B (F76x) to 664 B (H743) long. The linker places _bootdelay_signature at ALIGN(32) past end of vectors (e.g. 0x2a0 on CubeOrange), never at 0x1a0. The bootloader reads random exception_common pointers in place of the magic and never matches BOOT_DELAY_SIGNATURE1/2. Verified on CubeOrange with objdump of cubepilot_cubeorange_default.elf. 2. Flash cache never flushes: fc_write() stores arbitrary writes in cache line 1 and only flushes on a very specific condition tied to the sequential firmware upload flow. A standalone write during PROTO_SET_DELAY is cached forever. fc_read() then returns the cached value, so the post-write verify lies and the bootloader reports success. Nothing ever reaches flash. 3. H7 write granularity: the STM32H7 flash controller requires a full 32-byte program cycle per write. Single 32-bit writes from flash_func_write_word() would not be accepted by the controller even if they reached it. The feature has been silently dead on every H7/F7 FMU board for years and no one noticed, which is strong evidence nothing actually depends on it. Rather than fix it (which would mean rewriting PROTO_SET_DELAY, the flash cache path, and the H7 flash programming path), remove it. Changes: - bl.c: PROTO_SET_DELAY case now immediately NACKs (goto cmd_bad) so clients that still send the command get a clear rejection instead of the previous silent fake-success. The opcode stays in the protocol enum for backwards compatibility. - bl.h: drop BOOT_DELAY_SIGNATURE1/2 and BOOT_DELAY_MAX. - stm/stm32_common/main.c, nxp/imxrt_common/main.c: drop the startup boot-delay sig check block. - image_toc.c: decouple find_toc() from BOOT_DELAY_ADDRESS. BOARD_IMAGE_TOC_OFFSET is now the required define when BOOTLOADER_USE_TOC is enabled. The body is wrapped in #ifdef BOOTLOADER_USE_TOC and falls back to a stub returning false when the TOC is not in use (no upstream board currently enables it). - Linker scripts: strip EXTERN(_bootdelay_signature) and the FILL/. += 8 block from all 142 affected .ld files across boards/. - hw_config.h: strip the #define BOOT_DELAY_ADDRESS and its comment block entry from all 48 affected boards. - Tools/px4_uploader.py, Tools/teensy_uploader.py: remove --boot-delay, set_boot_delay(), and SET_BOOT_DELAY client-side counterpart. Smoke-built on cubepilot_cubeorange_default and cubepilot_cubeorange_bootloader; no link errors, no unresolved symbols, flash usage unchanged. Tested: - New BL, new FW - Old BL, old FW - Old BL, new FW - New BL, old FW
This commit is contained in:
@@ -104,7 +104,7 @@
|
||||
#define PROTO_GET_OTP 0x2a // read a byte from OTP at the given address
|
||||
#define PROTO_GET_SN 0x2b // read a word from UDID area ( Serial) at the given address
|
||||
#define PROTO_GET_CHIP 0x2c // read chip version (MCU IDCODE)
|
||||
#define PROTO_SET_DELAY 0x2d // set minimum boot delay
|
||||
#define PROTO_SET_DELAY 0x2d // set boot delay (deprecated; always NACKed)
|
||||
#define PROTO_GET_CHIP_DES 0x2e // read chip version In ASCII
|
||||
#define PROTO_GET_VERSION 0x2f // read version
|
||||
#define PROTO_BOOT 0x30 // boot the application
|
||||
@@ -1021,49 +1021,19 @@ bootloader(unsigned timeout)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef BOOT_DELAY_ADDRESS
|
||||
|
||||
case PROTO_SET_DELAY: {
|
||||
/*
|
||||
Allow for the bootloader to setup a
|
||||
boot delay signature which tells the
|
||||
board to delay for at least a
|
||||
specified number of seconds on boot.
|
||||
*/
|
||||
int v = cin_wait(100);
|
||||
|
||||
if (v < 0) {
|
||||
goto cmd_bad;
|
||||
}
|
||||
|
||||
uint8_t boot_delay = v & 0xFF;
|
||||
|
||||
if (boot_delay > BOOT_DELAY_MAX) {
|
||||
goto cmd_bad;
|
||||
}
|
||||
|
||||
// expect EOC
|
||||
if (!wait_for_eoc(2)) {
|
||||
goto cmd_bad;
|
||||
}
|
||||
|
||||
uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS);
|
||||
uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4);
|
||||
|
||||
if (sig1 != BOOT_DELAY_SIGNATURE1 ||
|
||||
sig2 != BOOT_DELAY_SIGNATURE2) {
|
||||
goto cmd_bad;
|
||||
}
|
||||
|
||||
uint32_t value = (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00) | boot_delay;
|
||||
flash_func_write_word(BOOT_DELAY_ADDRESS, value);
|
||||
|
||||
if (flash_func_read_word(BOOT_DELAY_ADDRESS) != value) {
|
||||
goto cmd_fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROTO_SET_DELAY:
|
||||
/*
|
||||
* Boot delay used to let the bootloader pause before
|
||||
* starting the app by writing a signature next to the
|
||||
* vector table. It never worked correctly on modern
|
||||
* FMUs (signature was placed past where the bootloader
|
||||
* looked, H7 flash granularity prevented single-word
|
||||
* writes, and the flash cache never flushed the write),
|
||||
* so it has been removed. NACK so a client that still
|
||||
* sends it gets a clear rejection instead of silent
|
||||
* fake success.
|
||||
*/
|
||||
goto cmd_bad;
|
||||
|
||||
// finalise programming and boot the system
|
||||
//
|
||||
|
||||
@@ -89,12 +89,6 @@ extern int buf_get(void);
|
||||
#define LED_ACTIVITY 1
|
||||
#define LED_BOOTLOADER 2
|
||||
|
||||
#ifdef BOOT_DELAY_ADDRESS
|
||||
# define BOOT_DELAY_SIGNATURE1 0x92c2ecff
|
||||
# define BOOT_DELAY_SIGNATURE2 0xc5057d5d
|
||||
# define BOOT_DELAY_MAX 30
|
||||
#endif
|
||||
|
||||
#define MAX_DES_LENGTH 20
|
||||
#define MAX_VERSION_LENGTH 32
|
||||
|
||||
|
||||
@@ -41,6 +41,13 @@
|
||||
#include "image_toc.h"
|
||||
|
||||
#include "bl.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef BOOTLOADER_USE_TOC
|
||||
|
||||
#ifndef BOARD_IMAGE_TOC_OFFSET
|
||||
# error "BOARD_IMAGE_TOC_OFFSET must be defined when BOOTLOADER_USE_TOC is enabled"
|
||||
#endif
|
||||
|
||||
/* Helper macros to define flash start and end addresses, based on info from
|
||||
* hw_config.h
|
||||
@@ -50,7 +57,7 @@
|
||||
|
||||
bool find_toc(const image_toc_entry_t **toc_entries, uint8_t *len)
|
||||
{
|
||||
const uintptr_t toc_start_u32 = APP_LOAD_ADDRESS + BOOT_DELAY_ADDRESS + 8;
|
||||
const uintptr_t toc_start_u32 = APP_LOAD_ADDRESS + BOARD_IMAGE_TOC_OFFSET;
|
||||
const image_toc_start_t *toc_start = (const image_toc_start_t *)toc_start_u32;
|
||||
const image_toc_entry_t *entry = (const image_toc_entry_t *)(toc_start_u32 + sizeof(image_toc_start_t));
|
||||
|
||||
@@ -105,3 +112,14 @@ bool find_toc(const image_toc_entry_t **toc_entries, uint8_t *len)
|
||||
*len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
#else // BOOTLOADER_USE_TOC
|
||||
|
||||
bool find_toc(const image_toc_entry_t **toc_entries, uint8_t *len)
|
||||
{
|
||||
(void)toc_entries;
|
||||
(void)len;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_USE_TOC
|
||||
|
||||
@@ -744,33 +744,6 @@ bootloader_main(void)
|
||||
board_set_rtc_signature(0);
|
||||
}
|
||||
|
||||
#ifdef BOOT_DELAY_ADDRESS
|
||||
{
|
||||
/*
|
||||
if a boot delay signature is present then delay the boot
|
||||
by at least that amount of time in seconds. This allows
|
||||
for an opportunity for a companion computer to load a
|
||||
new firmware, while still booting fast by sending a BOOT
|
||||
command
|
||||
*/
|
||||
uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS);
|
||||
uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4);
|
||||
|
||||
if (sig2 == BOOT_DELAY_SIGNATURE2 &&
|
||||
(sig1 & 0xFFFFFF00) == (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00)) {
|
||||
unsigned boot_delay = sig1 & 0xFF;
|
||||
|
||||
if (boot_delay <= BOOT_DELAY_MAX) {
|
||||
try_boot = false;
|
||||
|
||||
if (timeout < boot_delay * 1000) {
|
||||
timeout = boot_delay * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if the force-bootloader pins are strapped; if strapped,
|
||||
* don't try booting.
|
||||
|
||||
@@ -687,33 +687,6 @@ bootloader_main(void)
|
||||
board_set_rtc_signature(0);
|
||||
}
|
||||
|
||||
#ifdef BOOT_DELAY_ADDRESS
|
||||
{
|
||||
/*
|
||||
if a boot delay signature is present then delay the boot
|
||||
by at least that amount of time in seconds. This allows
|
||||
for an opportunity for a companion computer to load a
|
||||
new firmware, while still booting fast by sending a BOOT
|
||||
command
|
||||
*/
|
||||
uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS);
|
||||
uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4);
|
||||
|
||||
if (sig2 == BOOT_DELAY_SIGNATURE2 &&
|
||||
(sig1 & 0xFFFFFF00) == (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00)) {
|
||||
unsigned boot_delay = sig1 & 0xFF;
|
||||
|
||||
if (boot_delay <= BOOT_DELAY_MAX) {
|
||||
try_boot = false;
|
||||
|
||||
if (timeout < boot_delay * 1000) {
|
||||
timeout = boot_delay * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if the force-bootloader pins are strapped; if strapped,
|
||||
* don't try booting.
|
||||
|
||||
Reference in New Issue
Block a user