feat(cloner): Add U-Boot power-on intercept mode

- Add uboot_poweron_intercept() for aggressive boot interception
- Sends continuous break chars while monitoring for Marvell>> prompt
- Supports modes: break (default), poweron, wait
- Uses Python serial for precise timing and pattern detection
- Updates secubox-cloner with improved serial handling

Usage: ./secubox-clone-station.sh uboot /dev/ttyUSB0 poweron

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-09 16:48:36 +01:00
parent ee9a54b0a5
commit d76e26ed52
2 changed files with 421 additions and 6 deletions

View File

@ -531,7 +531,7 @@ show_status() {
# Build state
echo "Clone Images:"
if [ -d "$CLONE_DIR" ]; then
for img in "$CLONE_DIR"/*.img "$CLONE_DIR"/*.img.gz 2>/dev/null; do
ls "$CLONE_DIR"/*.img "$CLONE_DIR"/*.img.gz 2>/dev/null | while read img; do
[ -f "$img" ] || continue
local size=$(ls -lh "$img" 2>/dev/null | awk '{print $5}')
echo " - $(basename "$img") ($size)"
@ -557,7 +557,7 @@ show_status() {
echo "Clone Tokens:"
local token_count=0
if [ -d "$TOKENS_DIR" ]; then
for tf in "$TOKENS_DIR"/*.json 2>/dev/null; do
ls "$TOKENS_DIR"/*.json 2>/dev/null | while read tf; do
[ -f "$tf" ] || continue
local token=$(jsonfilter -i "$tf" -e '@.token' 2>/dev/null | cut -c1-16)
local used=$(jsonfilter -i "$tf" -e '@.used' 2>/dev/null)
@ -629,6 +629,176 @@ export_image() {
fi
}
# ============================================================================
# Serial Flash Operations
# ============================================================================
SERIAL_PORT="/dev/ttyUSB0"
SERIAL_BAUD="115200"
serial_detect() {
log "Detecting serial ports..."
local found=0
for port in /dev/ttyUSB* /dev/ttyACM*; do
if [ -c "$port" ]; then
echo " Found: $port"
found=1
fi
done
if [ "$found" = "0" ]; then
warn "No serial ports found"
return 1
fi
# Check if default port exists
if [ -c "$SERIAL_PORT" ]; then
log "Default port $SERIAL_PORT is available"
fi
}
serial_configure() {
local port="${1:-$SERIAL_PORT}"
if [ ! -c "$port" ]; then
error "Serial port $port not found"
return 1
fi
# Configure serial port
stty -F "$port" "$SERIAL_BAUD" cs8 -cstopb -parenb raw -echo 2>/dev/null
log "Configured $port at $SERIAL_BAUD baud"
}
serial_send() {
local port="${1:-$SERIAL_PORT}"
local cmd="$2"
local wait="${3:-1}"
echo "$cmd" > "$port"
sleep "$wait"
}
serial_break() {
local port="${1:-$SERIAL_PORT}"
log "Sending break sequence to enter U-Boot..."
serial_configure "$port" || return 1
# Send multiple newlines/breaks to catch U-Boot
for i in 1 2 3 4 5 6 7 8 9 10; do
echo "" > "$port"
sleep 0.1
done
log "Break sequence sent - check for 'Marvell>>' prompt"
log "Use: secubox-cloner flash console"
}
serial_console() {
local port="${1:-$SERIAL_PORT}"
if ! command -v socat >/dev/null 2>&1; then
error "socat not installed. Install with: opkg install socat"
return 1
fi
serial_configure "$port" || return 1
log "Starting interactive console on $port"
log "Press Ctrl+C to exit"
echo ""
socat -,raw,echo=0 "$port,b$SERIAL_BAUD,raw,echo=0"
}
serial_monitor() {
local port="${1:-$SERIAL_PORT}"
serial_configure "$port" || return 1
log "Monitoring $port (Ctrl+C to exit)..."
cat "$port"
}
serial_flash() {
local port="${1:-$SERIAL_PORT}"
local image="${2:-secubox-clone.img}"
local lan_ip=$(get_lan_ip)
# Check prerequisites
if [ ! -c "$port" ]; then
error "Serial port $port not found"
return 1
fi
if [ ! -f "$TFTP_ROOT/$image" ]; then
error "Image not found: $TFTP_ROOT/$image"
error "Run: secubox-cloner build && secubox-cloner serve --start"
return 1
fi
local image_size=$(stat -c%s "$TFTP_ROOT/$image" 2>/dev/null)
local image_blocks=$((image_size / 512))
log "=== SecuBox Serial Flash ==="
log "Port: $port"
log "TFTP Server: $lan_ip"
log "Image: $image ($((image_size / 1024 / 1024)) MB)"
log "Blocks: $image_blocks (0x$(printf '%x' $image_blocks))"
echo ""
serial_configure "$port" || return 1
log "Step 1: Setting up network..."
serial_send "$port" "setenv serverip $lan_ip" 2
serial_send "$port" "setenv ipaddr 192.168.255.100" 2
serial_send "$port" "setenv netmask 255.255.255.0" 1
log "Step 2: Downloading image via TFTP..."
serial_send "$port" "tftpboot 0x6000000 $image" 120
log "Step 3: Writing to MMC..."
serial_send "$port" "mmc dev 1" 3
serial_send "$port" "mmc write 0x6000000 0 0x$(printf '%x' $image_blocks)" 180
log "Step 4: Booting..."
serial_send "$port" "reset" 3
log "Flash commands sent!"
log "Monitor progress: secubox-cloner flash console"
}
serial_uboot_cmds() {
local lan_ip=$(get_lan_ip)
local image="secubox-clone.img"
if [ -f "$TFTP_ROOT/$image" ]; then
local image_size=$(stat -c%s "$TFTP_ROOT/$image" 2>/dev/null)
local image_blocks=$((image_size / 512))
else
local image_blocks="0x100000"
fi
echo ""
echo -e "${BOLD}U-Boot Commands for Manual Flash:${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "# 1. Set network (at Marvell>> prompt)"
echo "setenv serverip $lan_ip"
echo "setenv ipaddr 192.168.255.100"
echo "setenv netmask 255.255.255.0"
echo ""
echo "# 2. Download image"
echo "tftpboot 0x6000000 $image"
echo ""
echo "# 3. Write to eMMC"
echo "mmc dev 1"
echo "mmc write 0x6000000 0 0x$(printf '%x' $image_blocks)"
echo ""
echo "# 4. Boot"
echo "reset"
echo ""
}
# ============================================================================
# Usage
# ============================================================================
@ -647,6 +817,14 @@ Commands:
list List pending and joined clones
export [FILE] Export clone image to file
Serial Flash Commands:
flash detect Detect available serial ports
flash break [PORT] Send break to enter U-Boot
flash console [PORT] Interactive serial console (socat)
flash monitor [PORT] Monitor serial output
flash run [PORT] [IMAGE] Send U-Boot flash commands
flash uboot Print manual U-Boot commands
Options:
--resize SIZE Pre-resize image (e.g., 16G for eMMC)
--auto-approve Token auto-approves clone join (no manual step)
@ -656,6 +834,11 @@ Examples:
secubox-cloner build
secubox-cloner serve --start
# Flash a clone device via serial
secubox-cloner flash break # Enter U-Boot on target
secubox-cloner flash run # Send TFTP flash commands
secubox-cloner flash console # Monitor progress
# Generate auto-approve token
secubox-cloner token --auto-approve
@ -717,6 +900,41 @@ case "${1:-}" in
export_image "$@"
;;
flash)
shift
case "${1:-help}" in
detect)
serial_detect
;;
break)
serial_break "${2:-$SERIAL_PORT}"
;;
console)
serial_console "${2:-$SERIAL_PORT}"
;;
monitor)
serial_monitor "${2:-$SERIAL_PORT}"
;;
run)
serial_flash "${2:-$SERIAL_PORT}" "${3:-secubox-clone.img}"
;;
uboot|commands|cmd)
serial_uboot_cmds
;;
*)
echo "Usage: secubox-cloner flash <command> [port]"
echo ""
echo "Commands:"
echo " detect Detect available serial ports"
echo " break [PORT] Send break to enter U-Boot"
echo " console [PORT] Interactive serial console"
echo " monitor [PORT] Monitor serial output"
echo " run [PORT] [IMAGE] Send U-Boot flash commands"
echo " uboot Print manual U-Boot commands"
;;
esac
;;
help|--help|-h|"")
usage
;;

View File

@ -801,13 +801,192 @@ cmd_console() {
cmd_uboot() {
local device="${1:-}"
local mode="${2:-break}" # break, poweron, or wait
load_detected
[[ -z "$device" ]] && device="${TARGET_DEV:-}"
[[ -z "$device" ]] && { log_error "No device specified"; return 1; }
log_info "Breaking into U-Boot on $device..."
mokatool break --port "$device" --baud "$BAUDRATE"
case "$mode" in
poweron|power)
uboot_poweron_intercept "$device"
;;
wait)
uboot_wait_prompt "$device"
;;
break|*)
log_info "Breaking into U-Boot on $device..."
mokatool break --port "$device" --baud "$BAUDRATE"
;;
esac
}
# Intercept U-Boot at power-on by sending continuous breaks
uboot_poweron_intercept() {
local device="$1"
local timeout="${2:-30}" # 30 second window for power-on
log_step "U-Boot Power-On Intercept: $device"
echo -e "${YELLOW}>>> Power on the target device NOW <<<${NC}"
echo ""
log_info "Sending break characters for ${timeout}s..."
log_info "Watching for U-Boot prompt (Marvell>>, =>, Hit any key)"
echo ""
# Use Python for precise timing and pattern detection
python3 -c "
import serial
import time
import sys
import select
device = '$device'
baudrate = $BAUDRATE
timeout = $timeout
# U-Boot prompt patterns
UBOOT_PATTERNS = [
b'Marvell>>',
b'=>',
b'U-Boot>',
b'Hit any key',
b'autoboot:',
b'starting in',
]
try:
ser = serial.Serial(device, baudrate, timeout=0.1)
ser.reset_input_buffer()
start_time = time.time()
buffer = b''
found_uboot = False
last_send = 0
send_interval = 0.05 # Send break every 50ms
print('Monitoring serial output...')
print('-' * 60)
while time.time() - start_time < timeout:
# Send break characters rapidly
now = time.time()
if now - last_send >= send_interval:
ser.write(b'\r\n\x03') # CR LF + Ctrl-C
last_send = now
# Read any available data
if ser.in_waiting:
data = ser.read(ser.in_waiting)
buffer += data
# Display output (decode safely)
try:
text = data.decode('utf-8', errors='replace')
sys.stdout.write(text)
sys.stdout.flush()
except:
pass
# Check for U-Boot patterns
for pattern in UBOOT_PATTERNS:
if pattern in buffer:
print()
print('-' * 60)
print(f'\\n*** U-Boot detected! Pattern: {pattern.decode()} ***')
found_uboot = True
break
if found_uboot:
# Send a few more breaks to ensure we stopped autoboot
for _ in range(5):
ser.write(b'\\r\\n')
time.sleep(0.1)
break
# Keep buffer from growing too large
if len(buffer) > 4096:
buffer = buffer[-2048:]
time.sleep(0.01)
print()
print('-' * 60)
if found_uboot:
print('SUCCESS: U-Boot prompt intercepted!')
print(f'Device ready at: {device}')
print()
print('Use: ./secubox-clone-station.sh console {}'.format(device))
sys.exit(0)
else:
print('TIMEOUT: U-Boot prompt not detected')
print('Ensure device is powered on and serial is connected')
sys.exit(1)
ser.close()
except serial.SerialException as e:
print(f'Serial error: {e}')
sys.exit(1)
except KeyboardInterrupt:
print('\\nInterrupted')
sys.exit(130)
" 2>&1
return $?
}
# Wait passively for U-Boot prompt (device already booting)
uboot_wait_prompt() {
local device="$1"
local timeout="${2:-60}"
log_step "Waiting for U-Boot prompt on $device..."
python3 -c "
import serial
import time
import sys
device = '$device'
baudrate = $BAUDRATE
timeout = $timeout
UBOOT_PATTERNS = [b'Marvell>>', b'=>', b'U-Boot>', b'Hit any key']
try:
ser = serial.Serial(device, baudrate, timeout=0.5)
start_time = time.time()
buffer = b''
while time.time() - start_time < timeout:
if ser.in_waiting:
data = ser.read(ser.in_waiting)
buffer += data
sys.stdout.write(data.decode('utf-8', errors='replace'))
sys.stdout.flush()
for pattern in UBOOT_PATTERNS:
if pattern in buffer:
print(f'\\n\\n*** U-Boot prompt detected: {pattern.decode()} ***')
# Send break to stop autoboot
ser.write(b'\\r\\n')
time.sleep(0.2)
ser.write(b'\\r\\n')
sys.exit(0)
if len(buffer) > 4096:
buffer = buffer[-2048:]
time.sleep(0.05)
print('\\nTIMEOUT: No U-Boot prompt detected')
sys.exit(1)
except Exception as e:
print(f'Error: {e}')
sys.exit(1)
" 2>&1
}
cmd_env_backup() {
@ -859,7 +1038,10 @@ Commands:
clone Full workflow: detect → pull → flash → verify
console [DEV] Connect to serial console (via MOKATOOL)
uboot [DEV] Break into U-Boot prompt
uboot [DEV] [MODE] Enter U-Boot prompt
break - Send break to running device (default)
poweron - Intercept at power-on (aggressive)
wait - Wait passively for U-Boot output
env-backup [DEV] [FILE] Backup U-Boot environment
Options:
@ -875,11 +1057,16 @@ Examples:
# Auto-detect devices
./secubox-clone-station.sh detect
# Enter U-Boot at power-on (intercept boot)
./secubox-clone-station.sh uboot /dev/ttyUSB1 poweron
# Then power on the target device - script catches U-Boot
# Full clone workflow
./secubox-clone-station.sh clone
# Manual workflow
./secubox-clone-station.sh pull --master /dev/ttyUSB0
./secubox-clone-station.sh uboot /dev/ttyUSB1 poweron # Power on target
./secubox-clone-station.sh flash --target /dev/ttyUSB1
# Interactive console
@ -925,7 +1112,17 @@ case "${1:-}" in
;;
uboot)
shift
cmd_uboot "$@"
# cmd_uboot [device] [mode: break|poweron|wait]
device="${1:-}"
mode="${2:-break}"
# If first arg looks like a mode, shift it
case "$device" in
break|poweron|power|wait)
mode="$device"
device=""
;;
esac
cmd_uboot "$device" "$mode"
;;
env-backup|env-dump)
shift