| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(boards/3dr/ctrl-n1): board port fixes and driver corrections (#27405) * fix(drivers/ak09940a): fix probe retry, devtype collision, and register naming * fix(drivers/neopixel): check init return value and fix module name typo * fix(boards/3dr/ctrl-n1): correct magnetometer i2c bus, LED indexing, chip variant for bootloader, and TIM3 conflict with srgbled_dma * fix(boards/3dr/ctrl-n1): update bootloader for STM32H743VI | 5 个月前 | |
boards: ga1 add ICM45686 IMU support (#27281) | 5 个月前 | |
feat(boards): add support for AEDROXH7 flight controller (#27226) * feat(boards): add support for AEDROXH7 flight controller STM32H743-based FPV / racing flight controller from AEDROX. Brings up: - ICM-42688-P IMU on SPI2 - DPS310 baro on internal I2C2 - W25N NAND flash on SPI3 with littlefs at /fs/flash - MAX7456 analog OSD on SPI1 - 8 motor outputs (TIM1 + TIM8) all bidirectional-DShot capable - CAN1 - External I2C1 connector for compass / sensors - 6 UARTs (TEL1, GPS1, RC, TEL2, ESC telemetry, debug console on UART8), - Two user GPIOs on the M5-M8 connector, VTX power and camera-switch GPIOs, buzzer on PA7 (active-buzzer transistor low-side switch), battery V/I sensing via ADC1. Board ID 1198 shared with ArduPilot's AP_HW_AEDROXH7 entry. USB enumerates as 0x16D0:0x14FE with VENDORSTR "AEDROX". Signed-off-by: Julian Oes <julian@oes.ch> * docs(docs): Minor subedit --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
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 | 5 个月前 | |
feat(boards/ark): whitelist generic airframes on ARK FMU boards (#27384) Vendor-specific airframes (Holybro, UVify, ATL, COEX, Bitcraze, ThunderFly, Applied Aeronautics) are not relevant on the ARK FMU boards and only consume flash. Add an rc.board_airframes whitelist to ark_fmu-v6x and ark_fmu-v6s that keeps only the generic multirotor, fixed-wing, VTOL, and rover frame types. Flash savings (default variant): ark_fmu-v6x: 1965708 -> 1957772 B (-7936 B, free 372 -> 8308 B) ark_fmu-v6s: 1960212 -> 1945748 B (-14464 B, free 8108 -> 22572 B) Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com> | 5 个月前 | |
fix(commander): Remove COM_ARM_SDCARD (#27259) hardcoding the default warning and respecting boards without SD card with a define. | 5 个月前 | |
feat(drivers): add support for hiwonder 4 channel encoder motor module (#27229) * driver: hiwonder encoder motor module * fix(drivers): Change HiwonderEMM from CRTP API to non-template ModuleBase * fix(drivers): exclude hiwonder_emm driver from sitl build, as it fails i2c dependencies * feat(drivers, hiwonder4channel): add parameter update subsciption * feat(drivers, hiwonder4channel): add requested changes of original PR * fix(drivers, hiwonder4channel): add default in hiwonder_emm module.yaml * fix(drivers, hiwonder4channel): formatting * fix(drivers, hiwonder4channel): add the hiwonder driver to all px4board s that include the roboclaw driver * cleanup(drivers, hiwonder4channel): update copyright year * chore(drivers): move hiwonder driver startup call from rc.board_sensors to rc.rover * chore(drivers): hiwonder 4 channel - improve HIWONDER_EMM_EN description * chore(drivers): hiwonder4channel - move to int8 for internal speed values * chore(drivers): hiwonder4channel - move unconfigurable value to initialization. * chore(drivers): hiwonder4channel - add reboot_required to enable parameter * chore(drivers): hiwonder4channel - add docs --------- Co-authored-by: chfriedrich98 <chfriedrich@student.ethz.ch> | 5 个月前 | |
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 | 5 个月前 | |
fix(temperature_compensation): remove temp compensation from enclosed autopilots (#27015) * fix(temperature_compensation): remove temp compensation from enclosed autopilots Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from 3dr/mro Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove manually from 6x default kconfig Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from modalai fc-vx boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from all other boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * Update boards/px4/sitl/default.px4board --------- Signed-off-by: dirksavage88 <dirksavage88@gmail.com> Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> | 6 个月前 | |
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 | 5 个月前 | |
fix(temperature_compensation): remove temp compensation from enclosed autopilots (#27015) * fix(temperature_compensation): remove temp compensation from enclosed autopilots Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from 3dr/mro Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove manually from 6x default kconfig Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from modalai fc-vx boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from all other boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * Update boards/px4/sitl/default.px4board --------- Signed-off-by: dirksavage88 <dirksavage88@gmail.com> Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> | 6 个月前 | |
feat(boards): add CBUnmanned H753-SOM flight controller (#27234) * feat(boards): add CBUnmanned H753-Stamp flight controller * Update board_id to 1302 * docs: update CBUnmanned H753-Stamp board docs Apply review feedback: correct the I2C bus count (add internal bus), clarify SPI (IMUs on a dedicated internal bus), note the debug console alongside the user UARTs, and describe how the board is powered from an external 5 V supply with separate battery voltage sensing. Add the pinout image and a PWM Outputs section. Signed-off-by: Julian Oes <julian@oes.ch> * refactor(boards): rename CBUnmanned H753-Stamp to H753-SOM Rename the board directory, build target (cbunmanned_h753-som), USB product strings, docs page, asset directory and pinout image, and the bundled bootloader binary from -Stamp to -SOM. The hardware is a System-on-Module, so SOM is the accurate name. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
fix(boards): trim unused EKF2 features on flash-constrained F4 targets (#26928) Disable EKF2 fusion features with no corresponding hardware: - px4_fmu-v2: optical flow, range finder (~17 KB saved) - mamba-f405-mk2: optical flow, range finder, external vision, aux global position, aux velocity, baro compensation, drag fusion (~42 KB saved) | 6 个月前 | |
fix(temperature_compensation): remove temp compensation from enclosed autopilots (#27015) * fix(temperature_compensation): remove temp compensation from enclosed autopilots Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from 3dr/mro Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove manually from 6x default kconfig Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from modalai fc-vx boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from all other boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * Update boards/px4/sitl/default.px4board --------- Signed-off-by: dirksavage88 <dirksavage88@gmail.com> Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> | 6 个月前 | |
ESP32 Support Sponsored by AutonoSky nsh console running on USB param module running working with i2c and common drivers provided implementation for drv_pwm_output.h i2cdetect working as expected with no device mavlink started succesfully mounts sd card and logger runs logger to file succesfully pwm_servo implemented without using Nuttx lib pwm_out outputs expected waveforms - however currently if the frequency is higher than what the pwm_out driver runs, there will be aliasing, based on how the registers gets resets wifi softap working - Seeing wifi hotspot - cant connect due to wrong password - problems with adjusting ssid and password wifi ssid and password being set accordinglu connected to wifi hotspot with dhpcd - made some changes to nuttx to only build for SoftAP mode, however this was effectivelyy removing the ifdef for STATION mode. Should investigate the coexist option again added ifdef to not use timer 0 when wifi enabled - reverted esp32 rt_timer to make use of timer 0 by default fix setting incorrect bit in hrt timer register - hrt running as expected, but on startup the pwm_out driver starts up at about 200Hz and then rises over a minute or so 250Hz. Not sure if this was present previously, and could be due to Wifi running at time priority on timer 0 pull xtensa compilers in setup.ubuntu.sh revert logger stacksize and cmake argument esp32 chip revision and PX4 UUID implemented spi board reset implemented, formatting checked devkit acts on startup as a wifi bridge for comms - the most usefull setting for the general developer when buying a esp32 devkit - testing Mavlink shell using ./Tools/mavlink_shell.py - todo: Test mavlink messages being forward improve wifi telemetry by increasing prio - Remove power save mode on wifi - increased daemon thread schedule priority to 50 compiles without Nuttx changes - updated compiler settings to match those of nuttx on px4 side add espressif_esp32 to excluded boards ci: allow docker to find xtensa compilers | 1 年前 | |
fix(boards): remove default SYS_AUTOSTART from generic autopilot boards (#27052) These are generic flight controller boards (not drone-specific products), so they should not come with a pre-selected airframe like every other PX4 board. Drop the SYS_AUTOSTART default, matching the convention used across the rest of the tree. Drone-specific products (bitcraze/crazyflie, atl/mantis-edu) retain their default airframe. | 6 个月前 | |
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 | 5 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
fix(boards): save a of flash on the KakuteF7 (#27504) | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
fix(boards/modalai/voxl2): add shebang from #!/usr/bin/env bash to #!/bin/bash | 5 个月前 | |
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 | 5 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
fixes(board): canhubk3 default RC uart swapped with telem4, move to sbus rc from monolithic rc_input (#27524) Signed-off-by: dirksavage88 <dirksavage88@gmail.com> | 4 个月前 | |
update all px4board kconfig | 1 年前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
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 | 5 个月前 | |
update all px4board kconfig | 1 年前 | |
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 | 5 个月前 | |
fix(temperature_compensation): remove temp compensation from enclosed autopilots (#27015) * fix(temperature_compensation): remove temp compensation from enclosed autopilots Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from 3dr/mro Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove manually from 6x default kconfig Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from modalai fc-vx boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * fix(temperature_compensation): remove from all other boards Signed-off-by: dirksavage88 <dirksavage88@gmail.com> * Update boards/px4/sitl/default.px4board --------- Signed-off-by: dirksavage88 <dirksavage88@gmail.com> Co-authored-by: Jacob Dahl <37091262+dakejahl@users.noreply.github.com> | 6 个月前 | |
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 | 5 个月前 | |
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 | 5 个月前 | |
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 | 5 个月前 | |
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 | 5 个月前 | |
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 | 5 个月前 | |
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 | 5 个月前 | |
feat(bootloader): Revive secure-boot with example, docs, and various fixes (#27237) * feat(secure_bootloader): add ed25519 key and signing helpers Scaffolding for PX4 secure-boot firmware signing, split into two self-contained scripts: - generate_signing_keys.py: produces <name>.json (private+public hex) for use by sign_firmware.py and <name>.pub (C-array public key) for inclusion in the bootloader build via CONFIG_PUBLIC_KEYn. Refuses to overwrite existing private-key files. - sign_firmware.py: pads an input .bin to a 4-byte boundary and appends a 64-byte ed25519 signature, producing a file that drops directly into the flash slot described by the image TOC. Optionally appends an R&D certificate binary after the signature. Replaces the signing path of the old Tools/cryptotools.py that was removed along with the log-encryption cleanup; the new layout keeps bootloader-signing tooling separate from log encryption to avoid confusing the two independent crypto surfaces. * fix(bootloader): panic if px4_get_secure_random is ever called sw_crypto's crypto_open() unconditionally references px4_get_secure_random from its XCHACHA20 path, so even a bootloader that only performs ed25519 signature verification (and never touches stream ciphers) pulls in an undefined symbol at link time. The app build resolves it through nuttx_random.c, which is gated behind CONFIG_CRYPTO_RANDOM_POOL and only compiled in when the NuttX random pool is enabled. That config isn't on in the tiny bootloader NuttX defconfig, and enabling it would pull in a pile of kernel code the bootloader doesn't need. Supply the symbol locally, but make it call up_assert() instead of returning zeros. Silently handing out predictable bytes would be a serious security bug if anyone later enables the XCHACHA20 path in the bootloader without wiring up a real RNG. Aborting makes the mistake impossible to miss. * fix(bootloader): add PROTO_VERIFY_SIG opcode for upload-time signature check Today a signed-boot failure is invisible to the uploader: verify_app() runs inside jump_to_app() after PROTO_BOOT has already rebooted the chip, so the host sees a successful upload followed by the device silently staying in the bootloader. There is no protocol-level signal that the image that was just written is not going to run. Add PROTO_VERIFY_SIG (0x39) so the host can ask the bootloader to run find_toc() + verify_app(0) *before* the reboot and get a concrete OK / FAILED / INVALID answer back over the still-open USB connection. The new opcode is gated on BOOTLOADER_USE_SECURITY: bootloaders built without secure boot return cmd_bad (INSYNC/INVALID) so an uploader can tell "I don't know this command" apart from "verification failed". Two subtleties required care: 1. PROG_MULTI deliberately defers the very first word of the app image to a RAM variable (first_word) and only commits it to flash inside PROTO_BOOT, so a partial upload can never become bootable. But verify_app() reads directly from flash, so if we verified before committing first_word, even a valid image would always fail (the first four bytes at APP_LOAD_ADDRESS would still be 0xffffffff). The handler therefore mirrors the first half of the PROTO_BOOT handler: gate on STATE_ALLOWS_REBOOT, program the deferred first word, then run the crypto check. 2. On failure we deliberately do not try to "undo" the first-word write — H7 flash programming granularity makes it impossible to revert in place, and the device was going to end up in the same reject state at the next boot either way. The improvement is purely that the uploader sees the failure before REBOOT instead of after. Chose opcode 0x39 to stay clear of ArduPilot's 0x28 (READ_MULTI) and 0x40 (CHIP_FULL_ERASE), which PX4 does not currently use but which an AP-compatible uploader might. ArduPilot also has bootloader secure boot (monocypher ed25519, like us) but their verification runs at boot time, not upload time — so neither project currently solves the "upload silently wrote a bad image" problem. This puts PX4 ahead on that. * feat(Tools): add --image_signed to mark signed firmware for uploader px_uploader.py only needs to run signature verification over USB for images that actually carry a signature — asking the bootloader to verify an unsigned image would always fail, and the extra round trip is wasted time for the common unsigned case. It therefore needs a reliable way to tell the two apart. We cannot tell by inspecting the bytes: a sign_firmware.py output is just the raw .bin with 64 bytes of ed25519 signature glued on the end, indistinguishable in content from an unsigned image of the same padded length. The natural place to put the flag is the .px4 JSON envelope, which already carries board_id / version / summary / etc. Add --image_signed to px_mkfw.py, which sets "image_signed": true in the emitted JSON. The flag has no effect on what bytes actually end up on the device — it just tells the uploader "this blob has a signature, please verify it before booting". * feat(Tools): verify firmware signature before reboot After PROG_MULTI + GET_CRC, send a new VERIFY_SIG opcode (0x39) to the bootloader to check the ed25519 signature over the freshly flashed image *before* sending REBOOT. This way a signature failure is reported as a clean error from the uploader script, instead of a silent "device stays in bootloader after reboot" that leaves the user guessing. The uploader always probes VERIFY_SIG. The bootloader is the source of truth for whether secure boot is enabled: - INSYNC/OK -> verification passed, proceed to REBOOT - INSYNC/FAILED -> raise; "Signature does not verify against any trusted key" if the firmware claims to be signed, "Secure bootloader rejected an unsigned image" otherwise (= helpful guidance for the common misconfiguration of uploading default firmware to a secureboot bootloader) - INSYNC/INVALID -> bootloader has no secure boot. Quietly proceed unless the firmware metadata says image_signed, in which case raise. - recv timeout -> assume a pre-VERIFY_SIG bootloader, proceed. Surfaces a "Verifying image signature... passed" line on the upload status path when the firmware is marked signed, so users get a clear positive signal that the secure-boot pipeline ran end-to-end. Also drop the redundant logger.error in the upload() loop, which was duplicating the error message printed by the top-level handler in main() for every UploadError path (not specific to verify_signature, but only became obvious once these clean error messages started firing in normal usage). * fix(cmake): fix .px4board variant resolution to require exact match px4_config.cmake matched the requested CONFIG against each candidate .px4board with MATCHES, which is a regex partial match. For a config like px4_fmu-v6x_bootloader_secureboot, the iteration over .px4board files (alphabetical glob order) would match bootloader.px4board first — because "px4_fmu-v6x_bootloader" is a prefix of "px4_fmu-v6x_bootloader_secureboot" — and stop, silently selecting the wrong board config. Use STREQUAL instead so each candidate has to match the full requested CONFIG. Existing single-label cases (e.g. exact match on px4_fmu-v2_default or px4_fmu-v2) are unaffected because they were already exact in practice; this just plugs the prefix-match hole that any future <label>_<suffix> variant would trip over. * fix(nuttx): support bootloader_<variant> labels Boards can ship bootloader variants beyond the default bootloader label — e.g. a bootloader_secureboot that adds crypto + keystore Kconfig on top of the same source tree. Two pieces of build glue were hardcoded to the exact label bootloader and need to relax to match any bootloader_* label: 1. platforms/nuttx/CMakeLists.txt picked the bootloader linker script and bootloader-specific library list only when the label was exactly bootloader. Any other label (including bootloader_secureboot) silently fell through to the app build, producing nonsensical link flags. Match ^bootloader instead, and explicitly set SCRIPT_PREFIX to bootloader_ so all bootloader variants share the single existing linker script regardless of their full label. 2. platforms/nuttx/cmake/px4_impl_os.cmake selects the NuttX config subdirectory by exact label match, falling back to nsh when no matching directory exists. For bootloader_secureboot that fell through to nsh, dragging in a full app-style NuttX with cromfs, networking, and the full heap subsystem — a 128 KB bootloader sector overflowed by ~50 KB. Add an intermediate fallback: if the label starts with bootloader and a bootloader/ subdir exists, use that instead of nsh. Both changes are backward-compatible: existing single-label bootloader builds take exactly the same path as before. They only gain the ability for boards to add bootloader_<suffix>.px4board files without duplicating bootloader build wiring. * feat(build): auto-sign secure-boot images via BOARD_SECUREBOOT Add a Kconfig pair that boards can opt into: CONFIG_BOARD_SECUREBOOT -- bool: sign the .px4 with ed25519 CONFIG_BOARD_SECUREBOOT_KEY -- string: path to JSON private key (default: Tools/test_keys/test_keys.json) When set, the .px4 build rule inserts a Tools/secure_bootloader/sign_firmware.py step between the unsigned .bin and px_mkfw.py, and passes --image_signed so the .px4 envelope's metadata flags it for the uploader's VERIFY_SIG step. The unsigned .bin is still produced alongside the .px4, so users can sign with their own key out-of-tree if they prefer. A BOARD_SECUREBOOT_KEY environment variable overrides the Kconfig path at build time, mirroring the override pattern used for CONFIG_PUBLIC_KEYn in stub_keystore. This makes release builds practical: BOARD_SECUREBOOT_KEY=/secure/path/release.json make px4_<board>_secureboot Relative paths in the Kconfig are resolved against the repo root (not the build directory) so the same value works regardless of where the build runs from. Default builds are byte-identical to before; the new code path is gated on CONFIG_BOARD_SECUREBOOT being set. * feat(boards): add secureboot demo variant + docs Two coordinated build variants demonstrate end-to-end secure boot on px4_fmu-v6x without touching the default builds: px4_fmu-v6x_secureboot -- the app, with TOC + signing px4_fmu-v6x_bootloader_secureboot -- the matching secure bootloader App side (secureboot.px4board): - Selects nuttx-config/scripts/secureboot-script.ld via CONFIG_BOARD_LINKER_PREFIX. The script is a copy of the default layout plus a fixed 0x800 reservation past the vector table for the image TOC, and an empty .signature section at end-of-FLASH so sign_firmware.py knows where the appended ed25519 signature will land. - Compiles src/toc.c (a four-entry IMAGE_MAIN_TOC matching the layout used elsewhere in the tree) into drivers_board, gated on PX4_BOARD_LABEL == secureboot so the default build still produces the existing layout. - Sets CONFIG_BOARD_SECUREBOOT=y so the .px4 build rule signs the image with the upstream test key by default. Bootloader side (bootloader_secureboot.px4board): - Enables CONFIG_BOARD_CRYPTO + DRIVERS_SW_CRYPTO + DRIVERS_STUB_KEYSTORE, which links monocypher and the stub keystore into the bootloader. - Bakes Tools/test_keys/key0.pub in as CONFIG_PUBLIC_KEY0, paired with the test_keys.json the app variant signs with. - hw_config.h gates BOOTLOADER_USE_SECURITY, BOOTLOADER_SIGNING_ALGORITHM (CRYPTO_ED25519), and BOARD_IMAGE_TOC_OFFSET (0x800) on PX4_CRYPTO, so they only activate in this variant. Together the two variants implement the workflow: make px4_fmu-v6x_bootloader_secureboot # build + flash via SWD once make px4_fmu-v6x_secureboot upload # signs with test key, verifies Bootloader fits in 128 KB (~57 KB used) thanks to --gc-sections stripping the unused libtomcrypt code; nothing in the bootloader binary depends on monocypher beyond the ed25519 verifier. Replace the bundled test key for production with Tools/secure_bootloader/generate_signing_keys.py output and update both .px4board files (or set BOARD_SECUREBOOT_KEY at build time) — see docs/en/advanced_config/bootloader_secure_boot.md. * fix(boards): cap H7 bootloader linker scripts at 128 KB Roughly half of the H7 boards in tree had LENGTH = 2048K for the bootloader sector in their bootloader_script.ld, even though the matching app linker script places APP_LOAD_ADDRESS at 0x08020000 — i.e. the bootloader actually only owns the first 128 KB sector. The 2048K constraint is wrong: it lets a bootloader that grew past the 128 KB sector silently overflow into the app sector at link time and corrupt the start of the app on flash. The linker should fail the build instead. The current default bootloader is ~46 KB, well under 128 KB on every affected board, so this change is a no-op for default builds. It just plugs a footgun for anyone adding bootloader features (secure boot, extra UI, network boot, ...) that would have otherwise silently grown into the app's flash range. Boards fixed: 3dr-style H7 reference boards: cubepilot/cubeorange, cubepilot/cubeorangeplus, holybro/durandal-v1, narinfc/h7 vendor variants: corvon/743v1, cuav/nora, cuav/x7pro, gearup/airbrainh743, hkust/nxt-dual, hkust/nxt-v1, matek/h743, matek/h743-mini, matek/h743-slim, micoair/h743, micoair/h743-aio, micoair/h743-lite, micoair/h743-v2, x-mav/ap-h743r1, x-mav/ap-h743v2 Boards already correct (LENGTH = 128K) are unchanged. * fix(ci): add pynacl to Python requirements Tools/secure_bootloader/sign_firmware.py uses PyNaCl for ed25519 signing, and the .px4 build rule for boards with CONFIG_BOARD_SECUREBOOT calls it as part of the normal build (e.g. px4_fmu-v6x_secureboot). Without pynacl in the dev requirements, those builds fail in CI and fresh dev setups. * docs(update): Subedit * docs(update): Fix example error I made * fix(docs): document BOOT and SIG1 regions * fix(platforms): style fix * fix(ci): workaround to get pip dependency * fix(ci): fall back to plain pip on older build containers The voxl2 build image ships a pip that predates --break-system-packages (added in pip 23.0.1), so the install step blew up with "no such option". Modern containers enforce PEP 668 and need the flag; older ones don't support it but also don't enforce PEP 668, so plain pip works there. Try the modern flag first, fall back if pip rejects it. Signed-off-by: Julian Oes <julian@oes.ch> * fix(build): strip BUILD_DIR_SUFFIX from CONFIG in cmake-build cmake-build was passing the full build-dir name (including any BUILD_DIR_SUFFIX like _replay or _failsafe_web) as -DCONFIG=, which the board-lookup in cmake/px4_config.cmake then tried to match against <vendor>_<model>_<label> .px4board files. That used to work by accident because px4_config.cmake matched with regex MATCHES, but since the switch to STREQUAL (needed to disambiguate bootloader_secureboot from bootloader) the suffixed CONFIG no longer matches anything and LABEL ends up empty, tripping a CMake error in kconfig.cmake. Pass the bare CONFIG and keep the suffix only on the build dir so both concerns are independent. Signed-off-by: Julian Oes <julian@oes.ch> --------- Signed-off-by: Julian Oes <julian@oes.ch> Co-authored-by: Hamish Willee <hamishwillee@gmail.com> | 4 个月前 | |
feat(boards/zeroone): Add IIM42652 and BMP581 support for ZeroOneX6 Series V2 (#27475) * Add TDK IIM42652 IMU and Bosch BMP581 Baro support for ZeroOneX6 Series V2 board | 4 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 5 个月前 | ||
| 5 个月前 | ||
| 4 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 6 个月前 | ||
| 5 个月前 | ||
| 6 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 6 个月前 | ||
| 6 个月前 | ||
| 1 年前 | ||
| 6 个月前 | ||
| 5 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 1 年前 | ||
| 4 个月前 | ||
| 5 个月前 | ||
| 1 年前 | ||
| 5 个月前 | ||
| 6 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 5 个月前 | ||
| 4 个月前 | ||
| 4 个月前 |