97 lines
3.3 KiB
Bash
Executable File
97 lines
3.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# flash-cm4.sh - Flash CM4 eMMC while EMMC_DISABLE jumper is bridged
|
|
# Usage: ./scripts/flash-cm4.sh [/dev/sdX]
|
|
# If no device given, auto-detects the CM4 USB mass storage device.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
BEACON_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
REPO_ROOT="$(cd "$BEACON_DIR/.." && pwd)"
|
|
USBBOOT_DIR="$REPO_ROOT/usbboot"
|
|
MSD_DIR="$USBBOOT_DIR/secure-boot-msd"
|
|
IMAGE="$REPO_ROOT/output/images/sdcard.img.xz"
|
|
PRIVATE_KEY="$REPO_ROOT/private.pem"
|
|
|
|
# Build rpiboot from source if not already compiled
|
|
if [ ! -x "$USBBOOT_DIR/rpiboot" ]; then
|
|
echo "==> Building rpiboot from source..."
|
|
make -C "$USBBOOT_DIR"
|
|
fi
|
|
|
|
# Ensure secure-boot-msd boot.img is signed (required for secure-boot-locked CM4)
|
|
if [ ! -f "$MSD_DIR/boot.sig" ] || [ "$MSD_DIR/boot.img" -nt "$MSD_DIR/boot.sig" ]; then
|
|
echo "==> Signing secure-boot-msd/boot.img with private.pem..."
|
|
"$USBBOOT_DIR/tools/rpi-eeprom-digest" -i "$MSD_DIR/boot.img" \
|
|
-o "$MSD_DIR/boot.sig" -k "$PRIVATE_KEY"
|
|
fi
|
|
|
|
find_removable_sd() {
|
|
lsblk -dno NAME,RM | awk '$2==1{print $1}' | grep '^sd' | head -1
|
|
}
|
|
|
|
# Step 1: Expose CM4 eMMC as USB mass storage (skip if device already present)
|
|
if [ -n "${1:-}" ] && [ -b "${1}" ]; then
|
|
echo "==> $1 already present — skipping rpiboot."
|
|
elif [ -z "${1:-}" ] && [ -n "$(find_removable_sd)" ]; then
|
|
echo "==> Removable block device already present — skipping rpiboot."
|
|
else
|
|
# NOTE: mass-storage-gadget64 is rejected by secure-boot-locked CM4s.
|
|
# Use secure-boot-msd (signed boot.img) instead.
|
|
echo "==> Running rpiboot to expose CM4 eMMC (EMMC_DISABLE jumper must be bridged)..."
|
|
sudo "$USBBOOT_DIR/rpiboot" -d "$MSD_DIR"
|
|
echo "==> rpiboot done."
|
|
fi
|
|
|
|
# Step 2: Find the device (explicit arg or auto-detect)
|
|
if [ -n "${1:-}" ]; then
|
|
DEVICE="$1"
|
|
echo "==> Using device: $DEVICE — waiting for it to appear..."
|
|
for i in $(seq 1 30); do
|
|
[ -b "$DEVICE" ] && break
|
|
sleep 1
|
|
printf " waiting for %s... (%ds)\r" "$DEVICE" "$i"
|
|
done
|
|
if [ ! -b "$DEVICE" ]; then
|
|
echo "ERROR: $DEVICE did not appear as a block device within 30s."
|
|
exit 1
|
|
fi
|
|
else
|
|
DEVICE=""
|
|
echo "==> Waiting for removable block device..."
|
|
for i in $(seq 1 30); do
|
|
DEV=$(find_removable_sd)
|
|
if [ -n "$DEV" ]; then
|
|
DEVICE="/dev/$DEV"
|
|
break
|
|
fi
|
|
sleep 1
|
|
printf " waiting... (%ds)\r" "$i"
|
|
done
|
|
if [ -z "$DEVICE" ]; then
|
|
echo "ERROR: No removable block device found within 30s."
|
|
echo " Run 'lsblk' to find it, then re-run: $0 /dev/sdX"
|
|
exit 1
|
|
fi
|
|
echo "==> Auto-detected CM4 eMMC at $DEVICE"
|
|
fi
|
|
|
|
# Step 3: Safety check - refuse to flash the host NVMe disk
|
|
if echo "$DEVICE" | grep -qE '^/dev/nvme'; then
|
|
echo "ERROR: $DEVICE looks like the host NVMe. Aborting."
|
|
exit 1
|
|
fi
|
|
|
|
# Step 4: Unmount any auto-mounted partitions
|
|
echo "==> Unmounting $DEVICE partitions..."
|
|
sudo umount "${DEVICE}"?* 2>/dev/null || true
|
|
sudo umount "${DEVICE}"[0-9]* 2>/dev/null || true
|
|
|
|
# Step 5: Flash via bmaptool
|
|
echo "==> Flashing $IMAGE -> $DEVICE ..."
|
|
sudo bmaptool copy "$IMAGE" "$DEVICE"
|
|
sudo sync
|
|
|
|
echo ""
|
|
echo "==> Flash complete!"
|
|
echo " Remove the EMMC_DISABLE jumper, then power-cycle the CM4."
|