mirror of https://github.com/wolfSSL/wolfBoot.git
724 lines
30 KiB
Bash
Executable File
724 lines
30 KiB
Bash
Executable File
#!/bin/bash
|
|
# Build, flash QSPI, and boot VMK180 - all in one script
|
|
#
|
|
# Usage:
|
|
# ./versal_test.sh # Full build, flash, and boot wolfBoot
|
|
# ./versal_test.sh --test-app # Full build + flash test app to boot partition
|
|
# ./versal_test.sh --test-update # Full build + flash test app v2 to update partition
|
|
# ./versal_test.sh --boot-sdcard # Test SD card boot mode only
|
|
# ./versal_test.sh --boot-qspi # Test QSPI boot mode only
|
|
#
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WOLFBOOT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
cd "$WOLFBOOT_ROOT"
|
|
|
|
# Config
|
|
UART_PORT="${UART_PORT:-/dev/ttyUSB2}"
|
|
UART_BAUD="${UART_BAUD:-115200}"
|
|
SERVER_IP="${SERVER_IP:-10.0.4.24}"
|
|
BOARD_IP="${BOARD_IP:-10.0.4.90}"
|
|
TFTP_DIR="${TFTP_DIR:-/srv/tftp}"
|
|
VITIS_PATH="${VITIS_PATH:-/opt/Xilinx/Vitis/2024.2}"
|
|
RELAY_PORT="${RELAY_PORT:-/dev/ttyACM1}"
|
|
UART_LOG="${UART_LOG:-${WOLFBOOT_ROOT}/uart_log.txt}"
|
|
LINUX_IMAGES_DIR="${LINUX_IMAGES_DIR:-}"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
|
|
|
# Check for required tools
|
|
for cmd in expect socat; do
|
|
command -v "$cmd" &>/dev/null || { log_error "$cmd not found - install with: sudo apt install $cmd"; exit 1; }
|
|
done
|
|
|
|
# Load configuration from .config file
|
|
load_config() {
|
|
local config_file="${1:-.config}"
|
|
[ ! -f "$config_file" ] && { log_error "Config file not found: $config_file"; return 1; }
|
|
|
|
while IFS= read -r line; do
|
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
[[ -z "${line// }" ]] && continue
|
|
if [[ "$line" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*(\?)?=[[:space:]]*(.*)$ ]]; then
|
|
local key="${BASH_REMATCH[1]}" conditional="${BASH_REMATCH[2]}" value="${BASH_REMATCH[3]}"
|
|
value="${value#\"}"; value="${value%\"}"; value="${value%"${value##*[![:space:]]}"}"
|
|
if [ -n "$conditional" ]; then
|
|
[ -z "${!key:-}" ] && declare -g "${key}=${value}"
|
|
else
|
|
declare -g "${key}=${value}"
|
|
fi
|
|
fi
|
|
done < <(grep -E '^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*[[:space:]]*(\?)?=' "$config_file" 2>/dev/null || true)
|
|
|
|
export IMAGE_HEADER_SIZE SIGN HASH SECONDARY_SIGN_OPTIONS SECONDARY_PRIVATE_KEY
|
|
|
|
case "${SIGN:-}" in
|
|
ECC256) IMAGE_SIGNATURE_SIZE=64 ;;
|
|
ECC384) IMAGE_SIGNATURE_SIZE=96 ;;
|
|
ECC521) IMAGE_SIGNATURE_SIZE=132 ;;
|
|
ED25519) IMAGE_SIGNATURE_SIZE=64 ;;
|
|
ED448) IMAGE_SIGNATURE_SIZE=114 ;;
|
|
RSA2048) IMAGE_SIGNATURE_SIZE=256 ;;
|
|
RSA3072) IMAGE_SIGNATURE_SIZE=384 ;;
|
|
RSA4096) IMAGE_SIGNATURE_SIZE=512 ;;
|
|
*) IMAGE_SIGNATURE_SIZE=96 ;;
|
|
esac
|
|
export IMAGE_SIGNATURE_SIZE
|
|
|
|
SIGN_OPTIONS=""
|
|
case "${SIGN:-}" in
|
|
ECC256) SIGN_OPTIONS="--ecc256" ;; ECC384) SIGN_OPTIONS="--ecc384" ;;
|
|
ECC521) SIGN_OPTIONS="--ecc521" ;; ED25519) SIGN_OPTIONS="--ed25519" ;;
|
|
ED448) SIGN_OPTIONS="--ed448" ;; RSA2048) SIGN_OPTIONS="--rsa2048" ;;
|
|
RSA3072) SIGN_OPTIONS="--rsa3072" ;; RSA4096) SIGN_OPTIONS="--rsa4096" ;;
|
|
esac
|
|
case "${HASH:-}" in
|
|
SHA256) SIGN_OPTIONS="$SIGN_OPTIONS --sha256" ;;
|
|
SHA384) SIGN_OPTIONS="$SIGN_OPTIONS --sha384" ;;
|
|
SHA3) SIGN_OPTIONS="$SIGN_OPTIONS --sha3" ;;
|
|
esac
|
|
export SIGN_OPTIONS
|
|
}
|
|
|
|
# Initialize UART capture variables
|
|
UART_PIDS=()
|
|
UART_PTY=""
|
|
KEEP_UART_CAPTURE=false
|
|
|
|
# Relay control
|
|
relay_set_mode() {
|
|
local pattern=$1 port="${2:-$RELAY_PORT}"
|
|
[ ${#pattern} -ne 4 ] && { log_error "Pattern must be 4 binary digits"; return 1; }
|
|
echo "$pattern" | grep -qE '^[01]{4}$' || { log_error "Pattern must contain only 0s and 1s"; return 1; }
|
|
|
|
stty -F "$port" 115200 raw -echo -echoe -echok -echoctl -echoke cs8 -cstopb -parenb 2>/dev/null || {
|
|
log_error "Failed to configure serial port $port"; return 1;
|
|
}
|
|
sleep 0.1
|
|
exec 3<>"$port" || { log_error "Failed to open serial port $port"; return 1; }
|
|
|
|
log_info "Setting relay pattern: $pattern"
|
|
for i in 0 1 2 3; do
|
|
local bit="${pattern:$i:1}"
|
|
local relay_num=$((i + 1))
|
|
local state=$([ "$bit" = "1" ] && echo 1 || echo 0)
|
|
local checksum=$(( (0xA0 + relay_num + state) & 0xFF ))
|
|
echo " Relay $relay_num: $( [ $state -eq 1 ] && echo ON || echo OFF ) (pattern[$i]=$bit) -> [0xA0, $relay_num, $state, 0x$(printf "%02x" $checksum)]"
|
|
printf "%b" "\x$(printf "%02x" 0xA0)\x$(printf "%02x" $relay_num)\x$(printf "%02x" $state)\x$(printf "%02x" $checksum)" >&3
|
|
sync; sleep 0.05
|
|
done
|
|
exec 3<&-; exec 3>&-
|
|
}
|
|
|
|
boot_sdcard() {
|
|
log_info "Booting from SD card..."
|
|
# Set boot mode pins for SD boot (MODE3:0 = 0b1110 = 0xE)
|
|
# Hold reset for 1 second to ensure clean reset
|
|
relay_set_mode "1000" && sleep 0.2 && relay_set_mode "1000" && sleep 1.0 && relay_set_mode "0000" && sleep 0.5
|
|
log_ok "SD card boot mode set, reset released"
|
|
}
|
|
|
|
boot_qspi() {
|
|
log_info "Booting from QSPI..."
|
|
# Set boot mode pins for QSPI boot (MODE3:0 = 0b0011 = 0x3)
|
|
# Hold reset for 1 second to ensure clean reset
|
|
relay_set_mode "1000" && sleep 0.2 && relay_set_mode "1011" && sleep 1.0 && relay_set_mode "0011" && sleep 0.5
|
|
log_ok "QSPI boot mode set, reset released"
|
|
}
|
|
|
|
# UART capture functions
|
|
kill_existing_uart_processes() {
|
|
local pids=$(lsof -t "$UART_PORT" 2>/dev/null || true)
|
|
[ -n "$pids" ] && {
|
|
log_info "Killing existing processes using $UART_PORT: $pids"
|
|
for pid in $pids; do kill "$pid" 2>/dev/null || true; sleep 0.2; kill -9 "$pid" 2>/dev/null || true; done
|
|
sleep 0.5
|
|
}
|
|
}
|
|
|
|
start_uart_capture() {
|
|
log_info "Starting UART capture: $UART_PORT -> $UART_LOG"
|
|
UART_PTY=$(mktemp -u /tmp/vmk180_uart_XXXXXX)
|
|
[ ! -e "$UART_PORT" ] && { log_error "Serial port not found: $UART_PORT"; exit 1; }
|
|
[ ! -r "$UART_PORT" ] || [ ! -w "$UART_PORT" ] && { log_error "No read/write access to $UART_PORT"; exit 1; }
|
|
lsof "$UART_PORT" >/dev/null 2>&1 && { kill_existing_uart_processes; lsof "$UART_PORT" >/dev/null 2>&1 && { log_error "Failed to free serial port"; exit 1; }; }
|
|
[ -e "$UART_PTY" ] && rm -f "$UART_PTY"
|
|
stty -F "$UART_PORT" "$UART_BAUD" raw -echo -echoe -echok -echoctl -echoke cs8 -cstopb -parenb 2>/dev/null || { log_error "Failed to configure serial port"; exit 1; }
|
|
|
|
socat_err=$(mktemp /tmp/socat_err_XXXXXX)
|
|
log_info "Creating PTY bridge: $UART_PTY <-> $UART_PORT @ ${UART_BAUD}bps"
|
|
socat PTY,link="$UART_PTY",raw,echo=0 "GOPEN:$UART_PORT" >/dev/null 2>"$socat_err" &
|
|
socat_pid=$!; UART_PIDS+=($socat_pid)
|
|
|
|
for i in {1..10}; do
|
|
sleep 0.2; [ -e "$UART_PTY" ] && break
|
|
kill -0 "$socat_pid" 2>/dev/null || { log_error "socat process died:"; cat "$socat_err" >&2; rm -f "$socat_err"; exit 1; }
|
|
done
|
|
[ -s "$socat_err" ] && { log_error "socat errors:"; cat "$socat_err" >&2; }
|
|
rm -f "$socat_err"
|
|
[ ! -e "$UART_PTY" ] && { log_error "Failed to create PTY after 2 seconds"; exit 1; }
|
|
log_ok "UART PTY created: $UART_PTY"
|
|
}
|
|
|
|
stop_uart_capture() {
|
|
for pid in "${UART_PIDS[@]}"; do kill "$pid" 2>/dev/null || true; sleep 0.1; kill -9 "$pid" 2>/dev/null || true; done
|
|
[ -n "$UART_PTY" ] && [ -e "$UART_PTY" ] && rm -f "$UART_PTY"
|
|
}
|
|
|
|
cleanup() { [ "$KEEP_UART_CAPTURE" = "false" ] && { log_info "Cleaning up..."; stop_uart_capture; kill_existing_uart_processes; }; }
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# SD card image configuration
|
|
SDCARD_IMG="${SDCARD_IMG:-${WOLFBOOT_ROOT}/sdcard.img}"
|
|
SDCARD_SIZE_MB="${SDCARD_SIZE_MB:-1024}"
|
|
SDCARD_BOOT_SIZE_MB="${SDCARD_BOOT_SIZE_MB:-128}"
|
|
SDCARD_OFP_SIZE_MB="${SDCARD_OFP_SIZE_MB:-200}"
|
|
|
|
# Helper: Create SD card image with MBR partitions
|
|
# Layout:
|
|
# Partition 1: boot (128MB, FAT32 LBA, bootable) - BOOT.BIN
|
|
# Partition 2: OFP_A (200MB, Linux) - Primary signed FIT image
|
|
# Partition 3: OFP_B (200MB, Linux) - Update signed FIT image
|
|
# Partition 4: rootfs (remainder) - Linux root filesystem
|
|
# Note: Versal boot ROM requires MBR (does not support GPT)
|
|
create_sdcard_image() {
|
|
local img="$1" size_mb="${2:-$SDCARD_SIZE_MB}"
|
|
|
|
log_info "Creating ${size_mb}MB SD card image: $img"
|
|
dd if=/dev/zero of="$img" bs=1M count="$size_mb" status=progress 2>/dev/null || { log_error "Failed to create image"; return 1; }
|
|
|
|
log_info "Creating MBR partition table..."
|
|
sfdisk "$img" <<EOF
|
|
label: dos
|
|
unit: sectors
|
|
|
|
1 : start=2048, size=${SDCARD_BOOT_SIZE_MB}M, type=c, bootable
|
|
2 : size=${SDCARD_OFP_SIZE_MB}M, type=83
|
|
3 : size=${SDCARD_OFP_SIZE_MB}M, type=83
|
|
4 : type=83
|
|
EOF
|
|
|
|
if [ $? -ne 0 ]; then
|
|
log_error "Failed to create MBR partitions"
|
|
return 1
|
|
fi
|
|
|
|
log_ok "MBR partition table created"
|
|
fdisk -l "$img"
|
|
}
|
|
|
|
# Helper: Get partition offset in bytes from MBR
|
|
get_partition_offset() {
|
|
local img="$1" part="$2"
|
|
local sector
|
|
# Parse sfdisk dump for partition start sector
|
|
sector=$(sfdisk -d "$img" 2>/dev/null | grep "^${img}${part}" | sed 's/.*start=[[:space:]]*\([0-9]*\).*/\1/')
|
|
if [ -z "$sector" ]; then
|
|
# Fallback: parse fdisk output
|
|
sector=$(fdisk -l "$img" 2>/dev/null | grep "^${img}${part}" | awk '{print $2}')
|
|
[ "$sector" = "*" ] && sector=$(fdisk -l "$img" 2>/dev/null | grep "^${img}${part}" | awk '{print $3}')
|
|
fi
|
|
if [ -z "$sector" ] || [ "$sector" -eq 0 ] 2>/dev/null; then
|
|
log_error "Failed to read partition $part offset"
|
|
echo 0
|
|
return
|
|
fi
|
|
echo $((sector * 512))
|
|
}
|
|
|
|
# Helper: Write file to partition in SD card image
|
|
write_to_partition() {
|
|
local img="$1" part="$2" file="$3"
|
|
local offset_bytes=$(get_partition_offset "$img" "$part")
|
|
local offset_blocks=$((offset_bytes / 512))
|
|
|
|
if [ -z "$offset_blocks" ] || [ "$offset_blocks" -eq 0 ]; then
|
|
log_error "Failed to get partition $part offset"
|
|
return 1
|
|
fi
|
|
|
|
local file_size=$(stat -c%s "$file")
|
|
local part_size=$(sfdisk -d "$img" 2>/dev/null | grep "^${img}${part}" | sed 's/.*size=[[:space:]]*\([0-9]*\).*/\1/')
|
|
[ -n "$part_size" ] && [ "$file_size" -gt $((part_size * 512)) ] && { log_error "File $file (${file_size}B) exceeds partition $part size ($((part_size * 512))B)"; return 1; }
|
|
|
|
log_info "Writing $file to partition $part (offset: ${offset_bytes} bytes, sector: ${offset_blocks})"
|
|
dd if="$file" of="$img" bs=512 seek="$offset_blocks" conv=notrunc status=progress 2>/dev/null || {
|
|
log_error "Failed to write $file to partition $part"
|
|
return 1
|
|
}
|
|
log_ok "Written $(stat -c%s "$file") bytes to partition $part"
|
|
}
|
|
|
|
# Helper: Check Linux images directory
|
|
check_linux_images() {
|
|
local required_files="$1"
|
|
[ -z "$LINUX_IMAGES_DIR" ] && { log_error "LINUX_IMAGES_DIR not set."; log_info "Example: LINUX_IMAGES_DIR=/path/to/images/linux $0 $2"; exit 1; }
|
|
[ ! -d "$LINUX_IMAGES_DIR" ] && { log_error "Linux images directory not found: $LINUX_IMAGES_DIR"; exit 1; }
|
|
for f in $required_files; do
|
|
[ ! -f "${LINUX_IMAGES_DIR}/${f}" ] && { log_error "Required file not found: ${LINUX_IMAGES_DIR}/${f}"; exit 1; }
|
|
done
|
|
log_ok "All required Linux files found in $LINUX_IMAGES_DIR"
|
|
}
|
|
|
|
# Helper: Copy PDI file (from Linux images or soc-prebuilt-firmware)
|
|
copy_pdi() {
|
|
if [ -f "${LINUX_IMAGES_DIR}/project_1.pdi" ]; then
|
|
cp "${LINUX_IMAGES_DIR}/project_1.pdi" .
|
|
else
|
|
export PREBUILT_DIR="${WOLFBOOT_ROOT}/../soc-prebuilt-firmware/vmk180-versal"
|
|
[ ! -f "${PREBUILT_DIR}/project_1.pdi" ] && { log_error "project_1.pdi not found in Linux images or soc-prebuilt-firmware"; exit 1; }
|
|
cp "${PREBUILT_DIR}/project_1.pdi" .
|
|
fi
|
|
}
|
|
|
|
# Helper: Flash QSPI via U-Boot and capture boot output
|
|
# Args: $1=files_to_flash (space-separated: "file1:addr1 file2:addr2 ...")
|
|
# $2=capture_time (seconds)
|
|
# $3=description
|
|
flash_and_boot() {
|
|
local flash_items="$1" capture_time="${2:-30}" desc="${3:-Boot}"
|
|
|
|
# Build expect script dynamically
|
|
local expect_script="
|
|
set timeout 120
|
|
set pty \"$UART_PTY\"
|
|
set board_ip \"$BOARD_IP\"
|
|
set server_ip \"$SERVER_IP\"
|
|
|
|
spawn -open [open \$pty r+]
|
|
stty raw < \$pty
|
|
log_user 0
|
|
log_file -a \"$UART_LOG\"
|
|
|
|
send_user \"Waiting for autoboot prompt...\\n\"
|
|
expect {
|
|
\"Hit any key to stop autoboot\" { send_user \"Autoboot prompt detected, sending Enter...\\n\"; send \"\\r\" }
|
|
\"Versal>\" { send_user \"U-Boot prompt found\\n\" }
|
|
timeout { send_user \"Timeout waiting for U-Boot prompt\\n\"; exit 1 }
|
|
}
|
|
expect \"Versal>\"
|
|
send_user \"At U-Boot prompt, configuring network...\\n\"
|
|
sleep 0.5
|
|
|
|
send \"setenv ipaddr \$board_ip\\r\"; expect \"Versal>\"
|
|
send \"setenv serverip \$server_ip\\r\"; expect \"Versal>\"
|
|
send \"setenv netmask 255.255.255.0\\r\"; expect \"Versal>\"
|
|
|
|
send_user \"Probing SPI flash...\\n\"
|
|
send \"sf probe 0\\r\"; expect \"Versal>\"
|
|
"
|
|
# Add flash operations for each file
|
|
for item in $flash_items; do
|
|
local file="${item%%:*}" addr="${item##*:}"
|
|
local size=$(stat -c%s "${TFTP_DIR}/${file}")
|
|
local size_hex=$(printf "0x%x" $size)
|
|
expect_script+="
|
|
send_user \"Downloading ${file} via TFTP...\\n\"
|
|
send \"tftpboot 0x10000000 ${file}\\r\"
|
|
expect {
|
|
-re \"Bytes transferred.*Versal>\" { send_user \"TFTP download successful\\n\" }
|
|
\"Error\" { send_user \"TFTP download failed\\n\"; exit 1 }
|
|
timeout { send_user \"TFTP timeout\\n\"; exit 1 }
|
|
}
|
|
|
|
send_user \"Erasing and writing ${file} to flash at ${addr}...\\n\"
|
|
send \"sf update 0x10000000 ${addr} ${size_hex}\\r\"
|
|
expect {
|
|
-re \"Versal>\" { send_user \"${file} flash complete\\n\" }
|
|
timeout { send_user \"Flash timeout\\n\"; exit 1 }
|
|
}
|
|
"
|
|
done
|
|
|
|
expect_script+="
|
|
send_user \"\\n\"
|
|
send_user \"All flash operations complete!\\n\"
|
|
close
|
|
"
|
|
boot_sdcard
|
|
echo "$expect_script" | expect
|
|
log_ok "Flash operations complete!"
|
|
|
|
# Restart UART logging and boot from QSPI
|
|
log_info "Restarting continuous UART logging..."
|
|
cat "$UART_PTY" >> "$UART_LOG" 2>&1 &
|
|
UART_PIDS+=($!)
|
|
sleep 1
|
|
|
|
log_info "Switching to QSPI boot mode..."
|
|
boot_qspi
|
|
log_ok "Board booting from QSPI"
|
|
|
|
log_info "Capturing UART output for ${capture_time} seconds (${desc})..."
|
|
log_info "Watch live: tail -f $UART_LOG"
|
|
sleep "$capture_time"
|
|
|
|
log_ok "Capture complete"
|
|
log_info "UART log saved to: $UART_LOG"
|
|
KEEP_UART_CAPTURE=true
|
|
log_info "UART capture still active in background (PID: ${UART_PIDS[*]})"
|
|
log_info "To stop: kill ${UART_PIDS[*]}"
|
|
}
|
|
|
|
# Show help message
|
|
show_help() {
|
|
cat <<EOF
|
|
Build, flash QSPI, and boot VMK180 - all in one script
|
|
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Options:
|
|
(none) Full build, flash, and boot wolfBoot
|
|
--test-app Full build + flash test app to boot partition
|
|
--test-update Full build + flash test app v2 to update partition
|
|
--linux Build wolfBoot + signed Linux FIT image and boot (QSPI)
|
|
--linux-sdcard Build wolfBoot + signed Linux FIT image for SD card boot
|
|
--linux-uboot Build BOOT.BIN with U-Boot and flash Linux FIT image
|
|
--sdcard Build wolfBoot with SD card config and create SD card image
|
|
--boot-sdcard Test SD card boot mode only (no build/flash)
|
|
--boot-qspi Test QSPI boot mode only (no build/flash)
|
|
--skipuart Skip UART capture (use with --boot-sdcard/--boot-qspi)
|
|
-h, --help Show this help message
|
|
|
|
Environment Variables:
|
|
UART_PORT Serial port for UART capture (default: /dev/ttyUSB2)
|
|
SERVER_IP TFTP server IP address (default: 10.0.4.24)
|
|
BOARD_IP Board IP address (default: 10.0.4.90)
|
|
TFTP_DIR TFTP directory path (default: /srv/tftp)
|
|
VITIS_PATH Xilinx Vitis installation path (default: /opt/Xilinx/Vitis/2024.2)
|
|
LINUX_IMAGES_DIR Path to PetaLinux images directory (for --linux, --linux-sdcard, --linux-uboot)
|
|
SDCARD_IMG SD card image output path (default: sdcard.img)
|
|
SDCARD_SIZE_MB SD card image size in MB (default: 1024)
|
|
|
|
Examples:
|
|
$0 --boot-sdcard --skipuart # Reset to SD boot without UART capture
|
|
$0 --boot-qspi --skipuart # Reset to QSPI boot without UART capture
|
|
$0 --sdcard # Build with SD card config and create SD card image
|
|
LINUX_IMAGES_DIR=/path/to/images/linux $0 --linux-sdcard # PetaLinux SD card boot
|
|
EOF
|
|
}
|
|
|
|
# Check for --skipuart flag or modes that don't need UART before starting UART capture
|
|
SKIP_UART=false
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--skipuart|--sdcard|--linux-sdcard) SKIP_UART=true ;;
|
|
esac
|
|
done
|
|
|
|
# Check for help option before starting UART capture
|
|
case "${1:-}" in -h|--help) show_help; exit 0 ;; esac
|
|
|
|
# Start UART capture immediately (unless --skipuart specified)
|
|
if [ "$SKIP_UART" = "false" ]; then
|
|
log_info "Starting UART capture..."
|
|
start_uart_capture || { log_error "Failed to start UART capture"; exit 1; }
|
|
log_info "UART capture active, PIDs: ${UART_PIDS[*]}"
|
|
else
|
|
log_info "Skipping UART capture (--skipuart specified)"
|
|
fi
|
|
|
|
# Test boot helper
|
|
test_boot() {
|
|
local boot_func=$1 mode_name=$2
|
|
log_info "=== Testing $mode_name relay sequence ==="
|
|
|
|
# If UART capture is skipped, just run relay and exit
|
|
if [ "$SKIP_UART" = "true" ]; then
|
|
$boot_func || { log_error "$mode_name failed"; exit 1; }
|
|
log_ok "Board reset to $mode_name mode"
|
|
log_info "Monitor console manually: picocom -b 115200 $UART_PORT"
|
|
exit 0
|
|
fi
|
|
|
|
[ ${#UART_PIDS[@]} -eq 0 ] && { log_error "UART capture not running!"; exit 1; }
|
|
[ -z "$UART_PTY" ] || [ ! -e "$UART_PTY" ] && { log_error "UART PTY not available: $UART_PTY"; exit 1; }
|
|
|
|
cat "$UART_PTY" >> "$UART_LOG" 2>&1 &
|
|
UART_PIDS+=($!); sleep 0.5
|
|
$boot_func || { log_error "$mode_name failed"; exit 1; }
|
|
|
|
log_info "Monitoring UART for 30 seconds..."
|
|
trap 'log_info "Interrupted"; KEEP_UART_CAPTURE=true; exit 0' INT
|
|
sleep 30 || true
|
|
KEEP_UART_CAPTURE=true; exit 0
|
|
}
|
|
|
|
# Parse options
|
|
FLASH_TEST_APP=false
|
|
FLASH_UPDATE_APP=false
|
|
case "${1:-}" in
|
|
test-boot|--boot-sdcard) test_boot boot_sdcard "boot-sdcard" ;;
|
|
--boot-qspi) test_boot boot_qspi "boot-qspi" ;;
|
|
--test-app) FLASH_TEST_APP=true ;;
|
|
--test-update) FLASH_TEST_APP=true; FLASH_UPDATE_APP=true ;;
|
|
--linux-uboot)
|
|
log_info "=== Linux U-Boot Mode ==="
|
|
check_linux_images "plm.elf psmfw.elf bl31.elf u-boot.elf system-default.dtb image.ub" "--linux-uboot"
|
|
|
|
log_info "Copying Linux boot files..."
|
|
for f in plm.elf psmfw.elf bl31.elf u-boot.elf system-default.dtb image.ub; do cp "${LINUX_IMAGES_DIR}/${f}" .; done
|
|
copy_pdi
|
|
|
|
log_info "Generating BOOT.BIN with U-Boot..."
|
|
source "${VITIS_PATH}/settings64.sh"
|
|
rm -f BOOT.BIN
|
|
bootgen -arch versal -image ./tools/scripts/versal_uboot_linux.bif -w -o BOOT.BIN || { log_error "bootgen failed"; exit 1; }
|
|
|
|
cp BOOT.BIN "${TFTP_DIR}/"
|
|
cp image.ub "${TFTP_DIR}/"
|
|
log_ok "BOOT.BIN size: $(stat -c%s BOOT.BIN) bytes"
|
|
log_ok "image.ub size: $(stat -c%s image.ub) bytes"
|
|
|
|
flash_and_boot "BOOT.BIN:0x0 image.ub:0xF40000" 90 "Linux boot"
|
|
exit 0
|
|
;;
|
|
--linux)
|
|
log_info "=== Linux wolfBoot Mode ==="
|
|
check_linux_images "plm.elf psmfw.elf bl31.elf Image system-default.dtb" "--linux"
|
|
command -v mkimage &>/dev/null || { log_error "mkimage not found - install with: sudo apt install u-boot-tools"; exit 1; }
|
|
|
|
log_info "Copying Linux boot files..."
|
|
for f in plm.elf psmfw.elf bl31.elf Image system-default.dtb; do cp "${LINUX_IMAGES_DIR}/${f}" .; done
|
|
copy_pdi
|
|
|
|
log_info "Building wolfBoot..."
|
|
cp config/examples/versal_vmk180.config .config
|
|
make clean && make || { log_error "Failed to build wolfBoot"; exit 1; }
|
|
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found"; exit 1; }
|
|
load_config .config
|
|
|
|
log_info "Creating FIT image..."
|
|
mkimage -f ./hal/versal.its fitImage || { log_error "mkimage failed"; exit 1; }
|
|
log_ok "FIT image created: fitImage"
|
|
|
|
log_info "Signing FIT image..."
|
|
export IMAGE_HEADER_SIZE IMAGE_SIGNATURE_SIZE
|
|
./tools/keytools/sign $SIGN_OPTIONS fitImage "${PRIVATE_KEY:-wolfboot_signing_private_key.der}" 1 || { log_error "Signing failed"; exit 1; }
|
|
log_ok "Signed FIT image: fitImage_v1_signed.bin"
|
|
|
|
log_info "Generating BOOT.BIN with wolfBoot..."
|
|
source "${VITIS_PATH}/settings64.sh"
|
|
rm -f BOOT.BIN
|
|
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || { log_error "bootgen failed"; exit 1; }
|
|
|
|
cp BOOT.BIN "${TFTP_DIR}/"
|
|
cp fitImage_v1_signed.bin "${TFTP_DIR}/"
|
|
log_ok "BOOT.BIN size: $(stat -c%s BOOT.BIN) bytes"
|
|
log_ok "Signed FIT size: $(stat -c%s fitImage_v1_signed.bin) bytes"
|
|
|
|
flash_and_boot "BOOT.BIN:0x0 fitImage_v1_signed.bin:0x800000" 90 "wolfBoot + Linux boot"
|
|
exit 0
|
|
;;
|
|
--linux-sdcard)
|
|
log_info "=== Linux SD Card Boot Mode ==="
|
|
check_linux_images "plm.elf psmfw.elf bl31.elf Image system-default.dtb" "--linux-sdcard"
|
|
command -v mkimage &>/dev/null || { log_error "mkimage not found - install with: sudo apt install u-boot-tools"; exit 1; }
|
|
|
|
log_info "Copying Linux boot files..."
|
|
for f in plm.elf psmfw.elf bl31.elf Image system-default.dtb; do cp "${LINUX_IMAGES_DIR}/${f}" .; done
|
|
copy_pdi
|
|
|
|
# Build wolfBoot with SD card configuration
|
|
log_info "Building wolfBoot with SD card config..."
|
|
cp config/examples/versal_vmk180_sdcard.config .config
|
|
make clean && make || { log_error "Failed to build wolfBoot"; exit 1; }
|
|
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found"; exit 1; }
|
|
load_config .config
|
|
|
|
# Create FIT image from Linux kernel + DTB
|
|
log_info "Creating FIT image..."
|
|
mkimage -f ./hal/versal.its fitImage || { log_error "mkimage failed"; exit 1; }
|
|
log_ok "FIT image created: fitImage ($(stat -c%s fitImage) bytes)"
|
|
|
|
# Sign FIT image
|
|
log_info "Signing FIT image..."
|
|
export IMAGE_HEADER_SIZE IMAGE_SIGNATURE_SIZE
|
|
PRIVATE_KEY="${PRIVATE_KEY:-wolfboot_signing_private_key.der}"
|
|
./tools/keytools/sign $SIGN_OPTIONS fitImage "$PRIVATE_KEY" 1 || { log_error "Signing v1 failed"; exit 1; }
|
|
./tools/keytools/sign $SIGN_OPTIONS fitImage "$PRIVATE_KEY" 2 || { log_error "Signing v2 failed"; exit 1; }
|
|
log_ok "Signed FIT images: fitImage_v1_signed.bin, fitImage_v2_signed.bin"
|
|
|
|
# Create SD card image with MBR partitions
|
|
create_sdcard_image "$SDCARD_IMG" "$SDCARD_SIZE_MB" || exit 1
|
|
|
|
# Write signed FIT images to partitions (OFP_A=2, OFP_B=3)
|
|
log_info "Writing signed FIT images to SD card partitions..."
|
|
write_to_partition "$SDCARD_IMG" 2 fitImage_v1_signed.bin || exit 1
|
|
write_to_partition "$SDCARD_IMG" 3 fitImage_v2_signed.bin || exit 1
|
|
|
|
# Write rootfs filesystem image to partition 4 if available
|
|
if [ -f "${LINUX_IMAGES_DIR}/rootfs.ext4" ]; then
|
|
log_info "Writing rootfs to partition 4..."
|
|
write_to_partition "$SDCARD_IMG" 4 "${LINUX_IMAGES_DIR}/rootfs.ext4" || exit 1
|
|
log_ok "rootfs written ($(stat -c%s "${LINUX_IMAGES_DIR}/rootfs.ext4") bytes)"
|
|
else
|
|
log_info "No rootfs.ext4 found in $LINUX_IMAGES_DIR"
|
|
log_info "You can write a rootfs filesystem image to partition 4 manually"
|
|
fi
|
|
|
|
log_ok "SD card image created: $SDCARD_IMG"
|
|
|
|
# Generate BOOT.BIN
|
|
log_info ""
|
|
log_info "Generating BOOT.BIN with wolfBoot..."
|
|
source "${VITIS_PATH}/settings64.sh" 2>/dev/null || true
|
|
if command -v bootgen &>/dev/null; then
|
|
rm -f BOOT.BIN
|
|
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || log_error "bootgen failed"
|
|
[ -f BOOT.BIN ] && {
|
|
log_ok "BOOT.BIN size: $(stat -c%s BOOT.BIN) bytes"
|
|
cp BOOT.BIN "${TFTP_DIR}/" 2>/dev/null && log_ok "BOOT.BIN copied to TFTP"
|
|
}
|
|
else
|
|
log_error "bootgen not found - source Vitis settings or set VITIS_PATH"
|
|
fi
|
|
|
|
log_info ""
|
|
log_info "SD Card Partition Layout:"
|
|
log_info " Partition 1 (boot): FAT32 - BOOT.BIN (PLM + PSM + BL31 + wolfBoot)"
|
|
log_info " Partition 2 (OFP_A): Signed Linux FIT image v1 (primary)"
|
|
log_info " Partition 3 (OFP_B): Signed Linux FIT image v2 (update)"
|
|
log_info " Partition 4 (rootfs): Linux root filesystem"
|
|
log_info ""
|
|
log_info "Provision SD card manually:"
|
|
log_info " sudo dd if=$SDCARD_IMG of=/dev/sdX bs=4M status=progress conv=fsync"
|
|
log_info " sync"
|
|
log_info " sudo mkfs.vfat -F 32 -n BOOT /dev/sdX1"
|
|
log_info " sudo mount /dev/sdX1 /mnt && sudo cp BOOT.BIN /mnt/ && sudo umount /mnt"
|
|
|
|
exit 0
|
|
;;
|
|
--sdcard)
|
|
log_info "=== SD Card Boot Mode ==="
|
|
|
|
# Build wolfBoot with SD card configuration
|
|
log_info "Building wolfBoot with SD card config..."
|
|
cp config/examples/versal_vmk180_sdcard.config .config
|
|
make clean && make || { log_error "Failed to build wolfBoot"; exit 1; }
|
|
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found"; exit 1; }
|
|
load_config .config
|
|
|
|
# Build and sign test application
|
|
log_info "Building and signing test application..."
|
|
make test-app/image.bin || { log_error "Failed to build test app"; exit 1; }
|
|
export IMAGE_HEADER_SIZE IMAGE_SIGNATURE_SIZE
|
|
PRIVATE_KEY="${PRIVATE_KEY:-wolfboot_signing_private_key.der}"
|
|
./tools/keytools/sign $SIGN_OPTIONS test-app/image.bin "$PRIVATE_KEY" 1 || { log_error "Signing v1 failed"; exit 1; }
|
|
./tools/keytools/sign $SIGN_OPTIONS test-app/image.bin "$PRIVATE_KEY" 2 || { log_error "Signing v2 failed"; exit 1; }
|
|
log_ok "Signed test applications: image_v1_signed.bin, image_v2_signed.bin"
|
|
|
|
# Create SD card image with MBR (DOS) partition table
|
|
create_sdcard_image "$SDCARD_IMG" "$SDCARD_SIZE_MB" || exit 1
|
|
|
|
# Write signed images to partitions (OFP_A=2, OFP_B=3)
|
|
log_info "Writing signed images to SD card partitions..."
|
|
write_to_partition "$SDCARD_IMG" 2 test-app/image_v1_signed.bin || exit 1
|
|
write_to_partition "$SDCARD_IMG" 3 test-app/image_v2_signed.bin || exit 1
|
|
|
|
log_ok "SD card image created: $SDCARD_IMG"
|
|
|
|
# Generate BOOT.BIN if prebuilt files are available
|
|
export PREBUILT_DIR="${WOLFBOOT_ROOT}/../soc-prebuilt-firmware/vmk180-versal"
|
|
if [ -d "${PREBUILT_DIR}" ]; then
|
|
log_info ""
|
|
log_info "Generating BOOT.BIN with wolfBoot..."
|
|
for f in project_1.pdi plm.elf psmfw.elf bl31.elf system-default.dtb; do
|
|
[ -f "${PREBUILT_DIR}/${f}" ] && cp "${PREBUILT_DIR}/${f}" .
|
|
done
|
|
source "${VITIS_PATH}/settings64.sh" 2>/dev/null || true
|
|
if command -v bootgen &>/dev/null; then
|
|
rm -f BOOT.BIN
|
|
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || log_error "bootgen failed"
|
|
[ -f BOOT.BIN ] && {
|
|
log_ok "BOOT.BIN size: $(stat -c%s BOOT.BIN) bytes"
|
|
cp BOOT.BIN "${TFTP_DIR}/" 2>/dev/null && log_ok "BOOT.BIN copied to TFTP"
|
|
}
|
|
fi
|
|
fi
|
|
|
|
log_info ""
|
|
log_info "SD Card Partition Layout:"
|
|
log_info " Partition 1 (boot): FAT32 - BOOT.BIN goes here"
|
|
log_info " Partition 2 (OFP_A): Primary signed FIT image (written)"
|
|
log_info " Partition 3 (OFP_B): Update signed FIT image (written)"
|
|
log_info " Partition 4 (rootfs): Linux root filesystem"
|
|
log_info ""
|
|
log_info "To write to physical SD card (replace /dev/sdX):"
|
|
log_info " sudo dd if=$SDCARD_IMG of=/dev/sdX bs=4M status=progress conv=fsync"
|
|
log_info " sync"
|
|
log_info ""
|
|
log_info "Then format partition 1 as FAT32 and copy BOOT.BIN:"
|
|
log_info " sudo mkfs.vfat -F 32 -n BOOT /dev/sdX1"
|
|
log_info " sudo mount /dev/sdX1 /mnt"
|
|
log_info " sudo cp BOOT.BIN /mnt/"
|
|
log_info " sudo umount /mnt"
|
|
|
|
exit 0
|
|
;;
|
|
"")
|
|
;; # Default mode - continue below
|
|
*)
|
|
log_error "Unknown option: $1"; echo ""; show_help; exit 1
|
|
;;
|
|
esac
|
|
|
|
# Default mode: Build wolfBoot and optionally test app
|
|
log_info "Building wolfBoot..."
|
|
cp config/examples/versal_vmk180.config .config
|
|
make clean && make || { log_error "Failed to build wolfBoot"; exit 1; }
|
|
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found"; exit 1; }
|
|
|
|
# Build test app if requested
|
|
if [ "$FLASH_TEST_APP" = "true" ]; then
|
|
load_config .config
|
|
export IMAGE_HEADER_SIZE IMAGE_SIGNATURE_SIZE
|
|
PRIVATE_KEY="${PRIVATE_KEY:-wolfboot_signing_private_key.der}"
|
|
|
|
if [ "$FLASH_UPDATE_APP" = "true" ]; then
|
|
log_info "Building and signing test application version 2..."
|
|
make test-app/image.bin
|
|
./tools/keytools/sign $SIGN_OPTIONS test-app/image.bin "$PRIVATE_KEY" 2 || { log_error "Signing failed"; exit 1; }
|
|
cp test-app/image_v2_signed.bin "${TFTP_DIR}/"
|
|
log_ok "Test app v2 copied to TFTP"
|
|
else
|
|
log_info "Building and signing test application version 1..."
|
|
make test-app/image.bin
|
|
make test-app/image_v1_signed.bin
|
|
cp test-app/image_v1_signed.bin "${TFTP_DIR}/"
|
|
log_ok "Test app copied to TFTP"
|
|
fi
|
|
fi
|
|
|
|
# Generate BOOT.BIN
|
|
log_info "Generating BOOT.BIN..."
|
|
export PREBUILT_DIR="${WOLFBOOT_ROOT}/../soc-prebuilt-firmware/vmk180-versal"
|
|
[ ! -d "${PREBUILT_DIR}" ] && { log_error "Prebuilt firmware directory not found: ${PREBUILT_DIR}"; exit 1; }
|
|
|
|
for f in project_1.pdi plm.elf psmfw.elf bl31.elf system-default.dtb; do cp "${PREBUILT_DIR}/${f}" .; done
|
|
|
|
source "${VITIS_PATH}/settings64.sh"
|
|
rm -f BOOT.BIN
|
|
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || { log_error "bootgen failed"; exit 1; }
|
|
cp BOOT.BIN "${TFTP_DIR}/"
|
|
|
|
# Build flash items list
|
|
FLASH_ITEMS="BOOT.BIN:0x0"
|
|
if [ "$FLASH_TEST_APP" = "true" ]; then
|
|
if [ "$FLASH_UPDATE_APP" = "true" ]; then
|
|
FLASH_ITEMS="$FLASH_ITEMS image_v2_signed.bin:0x3400000"
|
|
else
|
|
FLASH_ITEMS="$FLASH_ITEMS image_v1_signed.bin:0x800000"
|
|
fi
|
|
fi
|
|
|
|
flash_and_boot "$FLASH_ITEMS" 30 "wolfBoot boot"
|