#!/usr/bin/env bash # # scripts/mksystem.sh — assemble the single dd-able rs-dos system image # # Replaces the old two-source setup (vvfat `esp/` directory for boot + # separate /tmp/disk.img for data). One FAT32 image holds EVERYTHING: # # \bzImage kernel (rsbl requires this exact path) # \initramfs.cpio.gz empty initramfs (rsbl requires it) # \EFI\BOOT\BOOTX64.EFI boot entry: the kernel (default) or rsboot # \etc\motd.txt seed config # \bin\cli\ \bin\gui\ binary tree (empty until Phase 2/4 migrate tools) # \*.txt seed files (seed/) # # The firmware boots from this image and the kernel mounts the same # volume at /disk// — boot medium and data medium are one disk. # # Usage: # ./scripts/mksystem.sh [options] [output.img] # default /tmp/system.img # # Options: # --force rebuild even if the image exists (Makefile stamps handle # normal freshness; without --force an existing image is kept, # so user files survive across reboots) # --size NM image size in MB (default 64) # --chain \EFI\BOOT\BOOTX64.EFI = rsboot bootloader (full chain: # firmware → rsboot → rsnix). Default is the kernel itself # (direct: firmware → rsnix), matching the old dev loop. # --gpt wrap the FAT volume in a GPT partition table (for dd-ing # to real USB sticks whose firmware refuses superfloppies) # --label NAME FAT volume label (default RSDOS) # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" cd "$PROJECT_DIR" IMG="/tmp/system.img" SIZE_MB=64 FORCE=0 CHAIN=0 GPT=0 LABEL="RSDOS" while [ $# -gt 0 ]; do case "$1" in --force | --fresh) FORCE=1 ;; --size) shift SIZE_MB="$1" ;; --chain) CHAIN=1 ;; --gpt) GPT=1 ;; --label) shift LABEL="$1" ;; --help | -h) head -30 "$0" | grep "^#" | sed 's/^# \?//' exit 0 ;; -*) echo "mksystem: unknown option: $1" >&2 exit 1 ;; *) IMG="$1" ;; esac shift done TARGET=x86_64-unknown-uefi PROFILE=debug OUT_DIR="target/$TARGET/$PROFILE" KERNEL="$OUT_DIR/rsdos.efi" BZIMAGE="esp/bzImage" INITRD="esp/initramfs.cpio.gz" BOOTLOADER="build/bootloader/BOOTX64.EFI" # ---- checks ---- for cmd in mkfs.fat mcopy mmd; do if ! command -v "$cmd" >/dev/null 2>&1; then echo "mksystem: $cmd not found (install dosfstools + mtools)" >&2 exit 1 fi done if [ "$GPT" -eq 1 ]; then for cmd in sfdisk truncate dd; do if ! command -v "$cmd" >/dev/null 2>&1; then echo "mksystem: --gpt needs $cmd" >&2 exit 1 fi done fi if [ -f "$IMG" ] && [ "$FORCE" -eq 0 ]; then echo "mksystem: $IMG already exists (use --force to re-create)" exit 0 fi # ---- build kernel ---- if [ ! -f "$KERNEL" ]; then echo "mksystem: building kernel..." cargo build --package rsdos --target "$TARGET" fi # ---- build bootloader (chain mode only) ---- if [ "$CHAIN" -eq 1 ] && [ ! -f "$BOOTLOADER" ]; then echo "mksystem: building bootloader..." "$SCRIPT_DIR/build-bootloader.sh" fi # ---- deploy kernel artifacts to esp/ (shared with the old layout) ---- mkdir -p esp/EFI/BOOT cp "$KERNEL" "$BZIMAGE" [ -f "$INITRD" ] || printf '' | gzip >"$INITRD" # ---- create the FAT volume ---- rm -f "$IMG" SIZE_BLOCKS=$((SIZE_MB * 1024)) # mkfs.fat counts 1024-byte blocks echo "mksystem: creating $IMG (${SIZE_MB}M FAT32, label $LABEL)" mkfs.fat -C -F 32 -n "$LABEL" "$IMG" "$SIZE_BLOCKS" >/dev/null echo "mksystem: staging system tree" mmd -i "$IMG" ::/EFI ::/EFI/BOOT ::/etc ::/bin ::/bin/cli ::/bin/gui mcopy -i "$IMG" "$BZIMAGE" ::/bzImage mcopy -i "$IMG" "$INITRD" ::/initramfs.cpio.gz if [ "$CHAIN" -eq 1 ]; then mcopy -i "$IMG" "$BOOTLOADER" ::/EFI/BOOT/BOOTX64.EFI echo " \\EFI\\BOOT\\BOOTX64.EFI <- rsboot (full chain)" else mcopy -i "$IMG" "$KERNEL" ::/EFI/BOOT/BOOTX64.EFI echo " \\EFI\\BOOT\\BOOTX64.EFI <- kernel (direct)" fi echo " \\bzImage \\initramfs.cpio.gz \\bin{\\cli,\\gui} \\etc" # Seed files: motd lives in \etc, everything else at the volume root. SEED_DIR="$PROJECT_DIR/seed" if [ -d "$SEED_DIR" ]; then for f in "$SEED_DIR"/*; do [ -f "$f" ] || continue name="$(basename "$f")" if [ "$name" = "motd.txt" ]; then mcopy -i "$IMG" "$f" ::/etc/"$name" echo " \\etc\\$name" else mcopy -i "$IMG" "$f" ::/"$name" echo " \\$name" fi done fi # ---- optional GPT wrapper (real-hardware dd target) ---- if [ "$GPT" -eq 1 ]; then GPT_START=2048 # 1 MiB offset (standard alignment) GPT_IMG="$(mktemp)" truncate -s "${SIZE_MB}M" "$GPT_IMG" dd if="$IMG" of="$GPT_IMG" bs=512 seek="$GPT_START" conv=notrunc 2>/dev/null FINAL="$(mktemp)" truncate -s "$((SIZE_MB + 2))M" "$FINAL" sfdisk --quiet "$FINAL" </dev/null rm -f "$GPT_IMG" mv "$FINAL" "$IMG" echo "mksystem: wrapped in GPT (partition at LBA $GPT_START)" fi echo "" echo "=== Done: $IMG ===" ls -lh "$IMG" echo "Boot with: make run (or: make boot-image)" [ "$GPT" -eq 0 ] && echo "USB dd tip: add --gpt for firmwares that refuse superfloppies" exit 0