ajhahn.de
← FlashOS
Shell 117 lines
#!/usr/bin/env bash
# OPERATOR-RUN, DESTRUCTIVE: repartition an SD card as a single whole-disk
# FAT32 BOOT partition (MBR partition table), matching the hardware
# procedure that booted FlashOS off EMMC2 + passed [TEST] emmc2-block
# on real Pi-4 hardware.
#
# Layout:
#   - MBR with one FAT32 primary partition labelled `BOOT`
#   - holds RPi firmware (start4.elf, fixup4.dat, bcm2711-rpi-4-b.dtb,
#     config.txt), kernel8.img, armstub8.bin
#   - plus two FAT32 seed files for [TEST] fs-roundtrip (Variant B):
#     ROUNDTR.DAT (4 KiB of zero) + ROUNDTR.MAG (1 byte of zero).
#     8.3 short names are mandatory — fat32.encode8_3 rejects a
#     basename longer than 8 characters.
#   - the [TEST] emmc2-block target is LBA 2064, in the FAT32
#     reserved-sector window (between the BPB at LBA 2048 and FAT1
#     ~LBA 2080) — no FAT32 driver reads or writes it, so it never
#     collides with file contents
#
# NOTE: the macOS GUI Disk Utility only offers FAT32 for cards ≤32 GB;
# SDXC cards (≥64 GB) need the CLI form below to get FAT32 instead of
# the default ExFAT. The 2-partition (BOOT + SCRATCH) layout earlier
# revisions of this script produced silently fell back to FAT16 for
# the 16 MiB BOOT partition (diskutil's FAT32 floor is ~256 MiB) and
# did not match the hardware path the driver was verified against.
#
# Usage:
#   scripts/format_sd.sh /dev/diskN          # macOS
#   scripts/format_sd.sh /dev/mmcblkN        # Linux SD reader
#   scripts/format_sd.sh /dev/sdX            # Linux USB SD adapter
#
# Refuses to operate without explicit "ja" confirmation. Refuses
# device paths that don't match the expected SD-reader patterns.
# Not invoked by build.sh; this is a one-shot operator command.
set -eu

if [ -z "$1" ]; then
    echo "usage: $0 <device>" >&2
    echo "  e.g. $0 /dev/disk4         # macOS" >&2
    echo "       $0 /dev/mmcblk0       # Linux" >&2
    exit 2
fi

DEV="$1"

case "$DEV" in
    /dev/disk[0-9]|/dev/disk[0-9][0-9]|/dev/sd[a-z]|/dev/mmcblk[0-9])
        ;;
    *)
        echo "refusing to operate on $DEV" >&2
        echo "expected /dev/diskN, /dev/sdX, or /dev/mmcblkN" >&2
        exit 2
        ;;
esac

if [ ! -b "$DEV" ] && [ ! -e "$DEV" ]; then
    echo "$DEV does not exist" >&2
    exit 2
fi

echo "================================================================"
echo "ABOUT TO REPARTITION $DEV"
echo "ALL DATA ON THIS DEVICE WILL BE LOST PERMANENTLY."
echo "================================================================"
echo "Type 'ja' (exact, lowercase) to proceed:"
read -r REPLY
if [ "$REPLY" != "ja" ]; then
    echo "aborted." >&2
    exit 1
fi

case "$(uname -s)" in
    Darwin)
        diskutil unmountDisk "$DEV"
        # Whole-disk single FAT32 BOOT partition with MBR partition table.
        # Equivalent to `diskutil eraseDisk FAT32 BOOT MBRFormat $DEV`,
        # but spelled via partitionDisk for symmetry with the Linux path.
        diskutil partitionDisk "$DEV" 1 MBR \
            "MS-DOS FAT32" BOOT R
        ;;
    Linux)
        # Unmount any auto-mounted partitions first.
        for part in "${DEV}"*; do
            [ "$part" = "$DEV" ] && continue
            sudo umount "$part" 2>/dev/null || true
        done
        # MBR, single FAT32-LBA (type 0x0c) partition spanning the disk
        # starting at LBA 2048.
        sudo sfdisk "$DEV" <<EOF
label: dos
start=2048,type=c
EOF
        # Linux device-node suffix differs: /dev/sdX1 vs /dev/mmcblkNp1.
        case "$DEV" in
            /dev/mmcblk*) P1="${DEV}p1" ;;
            *)            P1="${DEV}1"  ;;
        esac
        sudo mkfs.vfat -F32 -n BOOT "$P1"
        ;;
    *)
        echo "unsupported platform $(uname -s)" >&2
        exit 2
        ;;
esac

echo
echo "Repartition done. Next steps (operator):"
echo "  1. Copy RPi firmware blobs (start4.elf, fixup4.dat, bcm2711-rpi-4-b.dtb,"
echo "     config.txt) to the BOOT partition."
echo "  2. Run ./build.sh and copy zig-out/kernel8.img + zig-out/armstub8.bin"
echo "     to the BOOT partition."
echo "  3. Seed the two [TEST] fs-roundtrip files into the FAT32 root"
echo "     (8.3 short names are mandatory):"
echo "       dd if=/dev/zero of=<mnt>/ROUNDTR.DAT bs=4096 count=1"
echo "       dd if=/dev/zero of=<mnt>/ROUNDTR.MAG bs=1    count=1"
echo "  4. Eject the SD card; insert into the Pi; run picapture."