Skip to content

system/fastboot: Add serial (UART) transport backend - #3760

Open
fangpeina wants to merge 5 commits into
apache:masterfrom
fangpeina:fastboot-serial-new
Open

system/fastboot: Add serial (UART) transport backend#3760
fangpeina wants to merge 5 commits into
apache:masterfrom
fangpeina:fastboot-serial-new

Conversation

@fangpeina

Copy link
Copy Markdown
Contributor

Summary

Add a serial (UART) transport backend to the fastboot daemon, alongside
the existing USB and TCP transports. This enables fastboot on devices
where neither USB nor network is available — only a UART port is needed.

The serial backend reuses the TCP v1 wire framing (FB01 handshake +
8-byte big-endian length prefix), so the host side needs no new tool:
socat bridges the UART to a TCP socket and the standard fastboot client
connects via tcp:.

Changes

  • fix a bug where read_all did not advance the buffer pointer.
  • allow individual transport enable/disable (SYSTEM_FASTBOOTD_USB, SYSTEM_FASTBOOTD_TCP).
  • factor out the 8-byte length-prefix frame parsing shared by TCP and Serial.
  • the new serial transport implementation

Impact

  • Features: New serial transport for fastboot; USB and TCP transports can now be individually enabled/disabled via Kconfig
  • User Experience: Enables fastboot on UART-only devices
  • Build: New Kconfig options (SYSTEM_FASTBOOTD_SERIAL, SYSTEM_FASTBOOTD_USB, SYSTEM_FASTBOOTD_TCP); no breaking changes to existing configs
  • Compatibility: Fully backward compatible; existing USB/TCP behavior unchanged

Testing

All tests based on sim:nsh.

cmake -B build -DBOARD_CONFIG=sim:nsh -GNinja
# Apply transport-specific configs via menuconfig
cmake --build build

Configuration

Core

CONFIG_SYSTEM_FASTBOOTD=y
CONFIG_SYSTEM_FASTBOOTD_DOWNLOAD_MAX=65536

Flash Support (enabled on sim:nsh)

CONFIG_FS_FAT=y
CONFIG_ETC_ROMFS=y               # auto-creates /dev/ram0/1/2
CONFIG_ETC_ROMFSDEVNO=1          # /dev/ram1
CONFIG_ETC_FATDEVNO=2            # /dev/ram2 (usable for flash test)

Transport Layer (Select one from USB, TCP, or Serial; multiple selections allowed)

── Serial ──
CONFIG_SYSTEM_FASTBOOTD_SERIAL=y
CONFIG_SYSTEM_FASTBOOTD_SERIAL_PORT="/dev/ttyFB"
CONFIG_SERIAL_TERMIOS=y
CONFIG_SIM_UART_NUMBER=1
CONFIG_SIM_UART_PTY=y
CONFIG_SIM_UART0_NAME="/dev/ttyFB"

── TCP ──
CONFIG_SYSTEM_FASTBOOTD_TCP=y
CONFIG_NET=y
CONFIG_NET_TCP=y
CONFIG_NET_TCPBACKLOG=y
CONFIG_SYSTEM_FASTBOOTD_NET_INIT=y
CONFIG_SIM_NETDEV=y
CONFIG_SIM_NETDEV_TAP=y
CONFIG_NETINIT_IPADDR=0x0a000002             # 10.0.0.2
CONFIG_NETINIT_DRIPADDR=0x0a000001           # 10.0.0.1 (host bridge)

── USB ──
CONFIG_SYSTEM_FASTBOOTD_USB=y
CONFIG_USBADB=y
CONFIG_USBFASTBOOT=y
CONFIG_USBDEV_FS=y
CONFIG_USBDEV_DUALSPEED=y
CONFIG_SIM_USB_DEV=y
CONFIG_SIM_USB_RAW_GADGET=y
CONFIG_SIM_LOOP_INTERVAL=1

Verification

1. Serial Transport
Setup:

# Terminal 1: socat bridge (UART PTY ↔ TCP socket)
sudo socat -t 0 PTY,link=/dev/ttyFB,raw,echo=0  TCP-LISTEN:5556,reuseaddr,fork,nodelay &
sudo chmod 777 /dev/ttyFB

# Terminal 2: NuttX sim
cd build_fastboot_serial && sudo ./nuttx
nsh> fastbootd &

Test output

# 1. Query device info
$ fastboot -s tcp:127.0.0.1:5556 getvar version                                       
version: 13.0.1
Finished. Total time: 0.010s
$ fastboot -s tcp:127.0.0.1:5556 getvar max-download-size                             
max-download-size: 65536
Finished. Total time: 0.010s

# 2. Download (within max-download-size)
$ fastboot -s tcp:127.0.0.1:5556 stage /tmp/test_64k.bin                       
Sending '/tmp/test_64k.bin' (64 KB)                OKAY [  0.012s]
Finished. Total time: 0.022s

# 3. Flash with sparse split (payload > max-download-size)
$ fastboot -s tcp:127.0.0.1:5556 flash ram2 /tmp/test_128k.bin                         
Invalid sparse file format at header magic
Sending sparse 'ram2' 1/3 (60 KB)                  OKAY [  0.022s]
Writing 'ram2'                                     OKAY [  0.008s]
Sending sparse 'ram2' 2/3 (60 KB)                  OKAY [  0.030s]
Writing 'ram2'                                     OKAY [  0.010s]
Sending sparse 'ram2' 3/3 (8 KB)                   OKAY [  0.060s]
Writing 'ram2'                                     OKAY [  0.010s]
Finished. Total time: 0.170s

# 4. Erase partition
$ fastboot -s tcp:127.0.0.1:5556 erase ram2                                         
Erasing 'ram2'                                     OKAY [  0.011s]
Finished. Total time: 0.031s

2. TCP Transport
Setup:

# Terminal 1: create host bridge (one-time)
sudo ip link add nuttx0 type bridge
sudo ip addr add 10.0.0.1/24 dev nuttx0
sudo ip link set nuttx0 up

# Terminal 2: NuttX sim (TAP auto-joins bridge on boot)
cd build_fastboot_tcp && sudo ./nuttx
nsh> fastbootd &

Test output

# 1. Query device info
$ fastboot -s tcp:10.0.0.2:5554 getvar version                   
version: 13.0.1
Finished. Total time: 0.060s

$ fastboot -s tcp:10.0.0.2:5554 getvar max-download-size                    
max-download-size: 65536
Finished. Total time: 0.060s

# 2. Download (within max-download-size)
$ fastboot -s tcp:10.0.0.2:5554 stage /tmp/test_64k.bin                           
Sending '/tmp/test_64k.bin' (64 KB)                OKAY [  0.120s]
Finished. Total time: 0.180s

# 3. Flash with sparse split (payload > max-download-size)
$ fastboot -s tcp:10.0.0.2:5554 flash ram2 /tmp/test_128k.bin            
Invalid sparse file format at header magic
Sending sparse 'ram2' 1/3 (60 KB)                  OKAY [  0.120s]
Writing 'ram2'                                     OKAY [  0.060s]
Sending sparse 'ram2' 2/3 (60 KB)                  OKAY [  0.120s]
Writing 'ram2'                                     OKAY [  0.060s]
Sending sparse 'ram2' 3/3 (8 KB)                   OKAY [  0.120s]
Writing 'ram2'                                     OKAY [  0.060s]
Finished. Total time: 0.720s

# 4. Erase partition
$ fastboot -s tcp:10.0.0.2:5554 erase ram2                                
Erasing 'ram2'                                     OKAY [  0.060s]
Finished. Total time: 0.180s

3. USB Transport
Setup:

# Terminal 1: load kernel modules (one-time)
sudo modprobe raw_gadget
sudo modprobe dummy_hcd

# Terminal 2: NuttX sim
cd build_fastboot_usb && sudo ./nuttx
nsh> fastbootd &

Test output

$ fastboot devices                                                                     
1234	fastboot

# 1. Query device info
$ sudo fastboot getvar version                                                   
version: 13.0.1
Finished. Total time: 0.007s

$ sudo fastboot getvar max-download-size                                         
max-download-size: 65536
Finished. Total time: 0.004s

# 2. Download (within max-download-size)
$ sudo fastboot stage /tmp/test_64k.bin                                              
Sending '/tmp/test_64k.bin' (64 KB)                OKAY [  0.650s]
Finished. Total time: 0.653s

# 3. Flash with sparse split (payload > max-download-size)
$ sudo fastboot flash ram2 /tmp/test_128k.bin                                       
Invalid sparse file format at header magic
Sending sparse 'ram2' 1/3 (60 KB)                  OKAY [  0.620s]
Writing 'ram2'                                     OKAY [  0.010s]
Sending sparse 'ram2' 2/3 (60 KB)                  OKAY [  0.620s]
Writing 'ram2'                                     OKAY [  0.010s]
Sending sparse 'ram2' 3/3 (8 KB)                   OKAY [  0.100s]
Writing 'ram2'                                     OKAY [  0.010s]
Finished. Total time: 1.398s

# 4. Erase partition
$ sudo fastboot erase ram2                                                         
Erasing 'ram2'                                     OKAY [  0.011s]
Finished. Total time: 0.026s

The read loop was passing the original buf pointer and full length on
every iteration, causing subsequent reads to overwrite previous data
and potentially request more bytes than the remaining buffer space.

Update buf and len after each successful read to advance through the
buffer correctly.

Signed-off-by: fangpeina <fangpeina@xiaomi.com>
Add SYSTEM_FASTBOOTD_USB (default y) and SYSTEM_FASTBOOTD_TCP
(default y) to allow disabling individual transports independently.

Replace direct CONFIG_USBFASTBOOT / CONFIG_NET_TCP guards in the
transport code with the new fastbootd-level Kconfig symbols.

Signed-off-by: fangpeina <fangpeina@xiaomi.com>
Extract fastboot_framed_read() that handles TCP v1 wire framing:
handshake detection (FB01 exchange) and 8-byte big-endian length
prefix parsing.  Simplify fastboot_tcp_read() to reuse this helper
for both initial handshake and subsequent data frames.

This prepares for adding a serial transport that shares the same
framed protocol.

Signed-off-by: fangpeina <fangpeina@xiaomi.com>
Add a serial transport alongside the existing USB and TCP backends.
The serial backend reuses the TCP v1 wire framing (FB01 handshake
plus an 8-byte big-endian length prefix) so the host side needs no
new tool: socat bridges the UART to a TCP socket and the standard
fastboot tool connects via tcp:.

The serial port path is configured at build time through Kconfig
SYSTEM_FASTBOOTD_SERIAL_PORT.

Signed-off-by: fangpeina <fangpeina@xiaomi.com>
@fangpeina
fangpeina force-pushed the fastboot-serial-new branch from de44917 to 4ff8782 Compare August 28, 2026 08:37
@xiaoxiang781216

Copy link
Copy Markdown
Contributor

please create a new patch to fix the style issue:

Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:350:2: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:360:6: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:407:2: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:532:14: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:547:14: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:696:6: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:854:6: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:1039:6: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:1108:10: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:1118:14: error: Missing blank line after declarations
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:1224:4: error: Bad alignment
Error: /home/runner/work/nuttx-apps/nuttx-apps/apps/system/fastboot/fastboot.c:1226:4: error: Bad alignment

Add missing blank lines after variable declarations and fix
alignment in preprocessor conditionals. These are pre-existing
style issues exposed by the latest nxstyle version.

Signed-off-by: fangpeina <fangpeina@xiaomi.com>
@JianyuWang0623

Copy link
Copy Markdown
Contributor

Testing

Verified the multi-transport fastboot daemon end-to-end on real hardware for both USB and TCP transports. For each transport: getvar control commands, download (bulk data), flash, and a board-side byte-level read-back of the flashed data.

Board: lckfb-szpi-esp32s3 (ESP32-S3, chip MAC a0:85:e3:f4:43:30)
Flash target: a 64 KB RAM disk created on the board (mkrd -m 1 -s 512 128 -> /dev/ram1), since fastboot flash <name> maps to open("/dev/<name>", O_RDWR).
Verification pattern: byte (i*7+3) & 0xff, first 16 bytes 03 0a 11 18 1f 26 2d 34 3b 42 49 50 57 5e 65 6c.

Transport defconfig getvar download flash read-back Result
USB lckfb-szpi-esp32s3:fastboot_usb OK OK OK byte-match PASS
TCP lckfb-szpi-esp32s3:fastboot_tcp OK OK OK byte-match PASS

USB transport

fastbootd is auto-started by init.rc (PID 5 in ps); USB enumerates as 18d1:4e11, fastboot devices shows 1234 fastboot.

$ sudo fastboot getvar product           -> product: NuttX
$ sudo fastboot getvar version           -> version: 13.0.1-RC0
$ sudo fastboot getvar max-download-size -> max-download-size: 40960

$ sudo fastboot flash ram1 fb_test.bin   # 4 KB
Sending 'ram1' (4 KB)   OKAY [ 0.005s]
Writing 'ram1'          OKAY [ 0.001s]

$ sudo fastboot flash ram1 fb_big.bin    # 32 KB
Sending 'ram1' (32 KB)  OKAY [ 0.242s]
Writing 'ram1'          OKAY [ 0.198s]

$ sudo fastboot erase ram1
Erasing 'ram1'          OKAY

Board-side read-back (byte-exact):

nsh> hexdump /dev/ram1 count=16                 # after 4 KB flash
0000: 03 0a 11 18 1f 26 2d 34 3b 42 49 50 57 5e 65 6c   # matches host image

nsh> hexdump /dev/ram1 skip=32512 count=32      # after 32 KB flash, tail @0x7f00
7f00: 05 12 1f 2c 39 46 53 60 6d 7a 87 94 a1 ae bb c8   # full 32 KB landed correctly

nsh> hexdump /dev/ram1 count=32                 # after erase
0000: ff ff ff ff ff ff ff ff ...                       # erased to 0xff

download -> flash -> erase -> re-flash cycle all pass; fastbootd (PID 5) stays alive throughout.

TCP transport

Board joins a WiFi AP and gets 192.168.137.144 (fastbootd listens on 0.0.0.0:5554); host uses fastboot 36.0.0 on the same subnet.

> fastboot -s tcp:192.168.137.144:5554 getvar product           -> product: NuttX
> fastboot -s tcp:192.168.137.144:5554 getvar version           -> version: 13.0.1-RC0
> fastboot -s tcp:192.168.137.144:5554 getvar max-download-size -> max-download-size: 40960

> fastboot -s tcp:192.168.137.144:5554 flash ram1 ./fb_net.bin  # 4 KB
Sending 'ram1' (4 KB)   OKAY [ 0.087s]
Writing 'ram1'          OKAY [ 0.091s]
Finished. Total time: 0.312s

Board-side read-back after flash matches the host (i*7+3) pattern byte-for-byte.

Note: for the TCP defconfig, the RAM-disk flash target also requires CONFIG_BCH=y (opening a block device via open() needs BCH in NuttX; without it open("/dev/ram1") returns -ENXIO and flash fails with Flash open failure). This matches what fastboot_usb already pulls in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants