diff --git a/package/secubox/secubox-core/root/usr/sbin/secubox-cloner b/package/secubox/secubox-core/root/usr/sbin/secubox-cloner index 2d50b1f5..0773f52b 100755 --- a/package/secubox/secubox-core/root/usr/sbin/secubox-cloner +++ b/package/secubox/secubox-core/root/usr/sbin/secubox-cloner @@ -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 [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 ;; diff --git a/secubox-tools/secubox-clone-station.sh b/secubox-tools/secubox-clone-station.sh index d668a549..834cc5f3 100755 --- a/secubox-tools/secubox-clone-station.sh +++ b/secubox-tools/secubox-clone-station.sh @@ -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