Skip to content

boot: boot_serial: add raw (non-console) SMP recovery protocol#4

Open
JPHutchins wants to merge 1 commit into
mainfrom
feature-serial-raw-smp
Open

boot: boot_serial: add raw (non-console) SMP recovery protocol#4
JPHutchins wants to merge 1 commit into
mainfrom
feature-serial-raw-smp

Conversation

@JPHutchins
Copy link
Copy Markdown
Collaborator

Summary

Adds the BOOT_SERIAL_RAW_PROTOCOL option to mcuboot serial recovery (the bootloader-side SMP server). In raw mode the SMP packet (nmgr_hdr + payload) is exchanged as plain binary instead of the SMP over console encoding — no base64, no two-byte length prefix, no CRC16, no SHELL_NLIP framing, no \n. Packet boundaries are derived from the length field of the SMP header, so the encoding is transport-agnostic (UART, CDC ACM, CAN, RTT, …) and only requires a binary-capable link.

This mirrors Zephyr's CONFIG_UART_MCUMGR_RAW_PROTOCOL so the same raw mcumgr client talks to both the application and the bootloader. The two encodings are mutually exclusive, selected at build time; in raw mode the base64 and CRC code and libraries are dropped.

Changes

  • boot_serial.c — raw TX in boot_serial_output; console-only boot_serial_in_dec/dec_buf compiled out in raw mode; new boot_serial_input_raw() that drains every complete packet from the receive buffer (by header length) and preserves the residue.
  • serial_adapter.cIS_ENABLED-gated raw paths; binary-safe byte collection (no \n split); console_read_raw() retains an unconsumed fragment tail across calls instead of truncating.
  • Kconfig.serial_recovery — new option; BASE64/CRC selected only for the console encoding.
  • mcuboot_config.hCONFIG_MCUBOOT_SERIAL_RAW_PROTOCOL mapping.
  • Docs (serial_recovery.md + release note) and a serial_recovery_raw.conf sample fragment.

Verification

Built for nrf52840dk/nrf52840 (Zephyr 4.4.0, SDK 0.17.4, -Werror -Wall -Wextra) in both raw and console configurations — each compiles clean and links. Console output is byte-identical to before this change (no regression). Raw mode saves ~1 KiB flash and ~1 KiB RAM vs the console encoding, matching the Zephyr PR's reported win.

Reviewed across two adversarial passes; three issues found and fixed (multi-packet residue handling, the boot_serial_output raw guard, and a fragment-truncation data-loss path).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 1, 2026 23:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a build-time-selectable raw SMP transport (BOOT_SERIAL_RAW_PROTOCOL) to mcuboot's serial recovery, mirroring Zephyr's CONFIG_UART_MCUMGR_RAW_PROTOCOL. In raw mode the SMP header + payload is exchanged as plain binary (no base64, length prefix, CRC16, NLIP framing or \n); packet boundaries come from the SMP header nh_len. The console encoding remains the default; the two modes are mutually exclusive and the base64/CRC libraries are dropped in raw mode.

Changes:

  • New raw TX path in boot_serial_output plus a boot_serial_input_raw reassembler that drains complete packets and keeps residue, with the legacy console decode path #ifdef-gated.
  • serial_adapter.c gains a binary-safe ISR path (no \n split, end-of-IRQ fragment flush) and a console_read_raw reader that retains an unconsumed fragment tail across calls.
  • New BOOT_SERIAL_RAW_PROTOCOL Kconfig (conditionally selects BASE64/CRC), CONFIG_MCUBOOT_SERIAL_RAW_PROTOCOL mapping, a serial_recovery_raw.conf sample, plus docs and a release note.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
boot/boot_serial/src/boot_serial.c Raw TX in boot_serial_output; gates console decode; adds boot_serial_input_raw and raw branch in the read loop.
boot/zephyr/serial_adapter.c Binary-safe ISR fragment delivery and console_read_raw with persistent pending-tail.
boot/zephyr/Kconfig.serial_recovery Adds BOOT_SERIAL_RAW_PROTOCOL; makes BASE64/CRC conditional.
boot/zephyr/include/mcuboot_config/mcuboot_config.h Maps CONFIG_BOOT_SERIAL_RAW_PROTOCOL to MCUBOOT_SERIAL_RAW_PROTOCOL.
boot/zephyr/serial_recovery_raw.conf Sample Kconfig fragment for raw mode.
docs/serial_recovery.md Documents the new transport encoding option.
docs/release-notes.d/serial-recovery-raw-protocol.md Release note for the new option.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JPHutchins JPHutchins force-pushed the feature-serial-raw-smp branch from 77bf50c to acbf7d0 Compare June 1, 2026 23:48
Comment thread boot/zephyr/serial_adapter.c Outdated
Comment on lines +89 to +96
/*
* Raw protocol read: the data is binary, so it is returned without a NUL
* terminator. A fragment may be larger than the caller's buffer, so retain the
* unconsumed tail for the next call rather than dropping it (the fragment's
* buffer is not recycled by boot_uart_fifo_getline() until it is fully consumed
* here). Returns the number of bytes copied into "str".
*/
static int __maybe_unused
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need __maybe_unused, put it in ifdef

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — wrapped console_read_raw in #ifdef CONFIG_BOOT_SERIAL_RAW_PROTOCOL and dropped __maybe_unused (0c95767).

Comment thread boot/zephyr/serial_adapter.c Outdated
Comment on lines +125 to +128
if (IS_ENABLED(CONFIG_BOOT_SERIAL_RAW_PROTOCOL)) {
return console_read_raw(str, str_size, newline);
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use #ifdef else

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — console_read now dispatches with #ifdef ... #else; the line/len locals only exist in the console branch now (0c95767).

Comment thread boot/zephyr/serial_adapter.c Outdated
Comment on lines 196 to 216
if (IS_ENABLED(CONFIG_BOOT_SERIAL_RAW_PROTOCOL)) {
cmd->line[cur++] = byte;
}

if (byte == '\n') {
cmd->len = cur;
sys_slist_append(&lines_queue, &cmd->node);
cur = 0;
cmd = NULL;
if (cur >= CONFIG_BOOT_MAX_LINE_INPUT_LEN) {
cmd->len = cur;
sys_slist_append(&lines_queue, &cmd->node);
cur = 0;
cmd = NULL;
}
} else {
if (cur < CONFIG_BOOT_MAX_LINE_INPUT_LEN) {
cmd->line[cur++] = byte;
}

if (byte == '\n') {
cmd->len = cur;
sys_slist_append(&lines_queue, &cmd->node);
cur = 0;
cmd = NULL;
}
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use #ifdef else

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — converted the in-loop branch and the trailing flush to #ifdef ... #else / #ifdef (0c95767).

Copy link
Copy Markdown
Collaborator Author

@JPHutchins JPHutchins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few cleanups to make the diff better

@JPHutchins JPHutchins force-pushed the feature-serial-raw-smp branch from acbf7d0 to 0c95767 Compare June 2, 2026 00:07
Add the BOOT_SERIAL_RAW_PROTOCOL option, which exchanges SMP packets
over the serial port as raw binary instead of the SMP-over-console
encoding: no base64, no two-byte length prefix, no CRC16 and no
SHELL_NLIP framing. Packet boundaries are derived from the length field
of the SMP header, so the encoding is transport-agnostic (UART, CDC ACM,
CAN, ...) and only requires a binary-capable link. The mcumgr client
must be configured to use a matching raw transport.

This mirrors Zephyr's CONFIG_UART_MCUMGR_RAW_PROTOCOL. The two encodings
are mutually exclusive and selected at build time; in raw mode the
base64 and CRC code and libraries are dropped, saving roughly 1 KiB of
flash and 1 KiB of RAM and increasing transfer speed.

Because the raw encoding has no CRC or framing to detect a truncated
packet, also add BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT (enabled by
default with the raw protocol): a partially received packet is dropped
after BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT_MS without new data so a
stalled transfer cannot wedge recovery. This mirrors Zephyr's
CONFIG_MCUMGR_TRANSPORT_RAW_UART_INPUT_TIMEOUT.

A serial_recovery_raw.conf fragment and a matching Twister build test
(sample.bootloader.mcuboot.serial_recovery_raw) are added so the raw
configuration is built in CI.

Signed-off-by: JP Hutchins <jp@intercreate.io>
Assisted-By: Claude:opus-4.8
@JPHutchins JPHutchins force-pushed the feature-serial-raw-smp branch from 0c95767 to 03bb198 Compare June 2, 2026 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants