diff options
Diffstat (limited to 'scripts/mksystem.sh')
| -rwxr-xr-x | scripts/mksystem.sh | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/scripts/mksystem.sh b/scripts/mksystem.sh new file mode 100755 index 0000000..dfa481c --- /dev/null +++ b/scripts/mksystem.sh | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # | ||
| 3 | # scripts/mksystem.sh — assemble the single dd-able rs-dos system image | ||
| 4 | # | ||
| 5 | # Replaces the old two-source setup (vvfat `esp/` directory for boot + | ||
| 6 | # separate /tmp/disk.img for data). One FAT32 image holds EVERYTHING: | ||
| 7 | # | ||
| 8 | # \bzImage kernel (rsbl requires this exact path) | ||
| 9 | # \initramfs.cpio.gz empty initramfs (rsbl requires it) | ||
| 10 | # \EFI\BOOT\BOOTX64.EFI boot entry: the kernel (default) or rsboot | ||
| 11 | # \etc\motd.txt seed config | ||
| 12 | # \bin\cli\ \bin\gui\ binary tree (empty until Phase 2/4 migrate tools) | ||
| 13 | # \*.txt seed files (seed/) | ||
| 14 | # | ||
| 15 | # The firmware boots from this image and the kernel mounts the same | ||
| 16 | # volume at /disk/<UID>/ — boot medium and data medium are one disk. | ||
| 17 | # | ||
| 18 | # Usage: | ||
| 19 | # ./scripts/mksystem.sh [options] [output.img] # default /tmp/system.img | ||
| 20 | # | ||
| 21 | # Options: | ||
| 22 | # --force rebuild even if the image exists (Makefile stamps handle | ||
| 23 | # normal freshness; without --force an existing image is kept, | ||
| 24 | # so user files survive across reboots) | ||
| 25 | # --size NM image size in MB (default 64) | ||
| 26 | # --chain \EFI\BOOT\BOOTX64.EFI = rsboot bootloader (full chain: | ||
| 27 | # firmware → rsboot → rsnix). Default is the kernel itself | ||
| 28 | # (direct: firmware → rsnix), matching the old dev loop. | ||
| 29 | # --gpt wrap the FAT volume in a GPT partition table (for dd-ing | ||
| 30 | # to real USB sticks whose firmware refuses superfloppies) | ||
| 31 | # --label NAME FAT volume label (default RSDOS) | ||
| 32 | # | ||
| 33 | set -euo pipefail | ||
| 34 | |||
| 35 | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| 36 | PROJECT_DIR="$(dirname "$SCRIPT_DIR")" | ||
| 37 | cd "$PROJECT_DIR" | ||
| 38 | |||
| 39 | IMG="/tmp/system.img" | ||
| 40 | SIZE_MB=64 | ||
| 41 | FORCE=0 | ||
| 42 | CHAIN=0 | ||
| 43 | GPT=0 | ||
| 44 | LABEL="RSDOS" | ||
| 45 | |||
| 46 | while [ $# -gt 0 ]; do | ||
| 47 | case "$1" in | ||
| 48 | --force | --fresh) | ||
| 49 | FORCE=1 | ||
| 50 | ;; | ||
| 51 | --size) | ||
| 52 | shift | ||
| 53 | SIZE_MB="$1" | ||
| 54 | ;; | ||
| 55 | --chain) | ||
| 56 | CHAIN=1 | ||
| 57 | ;; | ||
| 58 | --gpt) | ||
| 59 | GPT=1 | ||
| 60 | ;; | ||
| 61 | --label) | ||
| 62 | shift | ||
| 63 | LABEL="$1" | ||
| 64 | ;; | ||
| 65 | --help | -h) | ||
| 66 | head -30 "$0" | grep "^#" | sed 's/^# \?//' | ||
| 67 | exit 0 | ||
| 68 | ;; | ||
| 69 | -*) | ||
| 70 | echo "mksystem: unknown option: $1" >&2 | ||
| 71 | exit 1 | ||
| 72 | ;; | ||
| 73 | *) | ||
| 74 | IMG="$1" | ||
| 75 | ;; | ||
| 76 | esac | ||
| 77 | shift | ||
| 78 | done | ||
| 79 | |||
| 80 | TARGET=x86_64-unknown-uefi | ||
| 81 | PROFILE=debug | ||
| 82 | OUT_DIR="target/$TARGET/$PROFILE" | ||
| 83 | KERNEL="$OUT_DIR/rsdos.efi" | ||
| 84 | BZIMAGE="esp/bzImage" | ||
| 85 | INITRD="esp/initramfs.cpio.gz" | ||
| 86 | BOOTLOADER="build/bootloader/BOOTX64.EFI" | ||
| 87 | |||
| 88 | # ---- checks ---- | ||
| 89 | for cmd in mkfs.fat mcopy mmd; do | ||
| 90 | if ! command -v "$cmd" >/dev/null 2>&1; then | ||
| 91 | echo "mksystem: $cmd not found (install dosfstools + mtools)" >&2 | ||
| 92 | exit 1 | ||
| 93 | fi | ||
| 94 | done | ||
| 95 | if [ "$GPT" -eq 1 ]; then | ||
| 96 | for cmd in sfdisk truncate dd; do | ||
| 97 | if ! command -v "$cmd" >/dev/null 2>&1; then | ||
| 98 | echo "mksystem: --gpt needs $cmd" >&2 | ||
| 99 | exit 1 | ||
| 100 | fi | ||
| 101 | done | ||
| 102 | fi | ||
| 103 | |||
| 104 | if [ -f "$IMG" ] && [ "$FORCE" -eq 0 ]; then | ||
| 105 | echo "mksystem: $IMG already exists (use --force to re-create)" | ||
| 106 | exit 0 | ||
| 107 | fi | ||
| 108 | |||
| 109 | # ---- build kernel ---- | ||
| 110 | if [ ! -f "$KERNEL" ]; then | ||
| 111 | echo "mksystem: building kernel..." | ||
| 112 | cargo build --package rsdos --target "$TARGET" | ||
| 113 | fi | ||
| 114 | |||
| 115 | # ---- build bootloader (chain mode only) ---- | ||
| 116 | if [ "$CHAIN" -eq 1 ] && [ ! -f "$BOOTLOADER" ]; then | ||
| 117 | echo "mksystem: building bootloader..." | ||
| 118 | "$SCRIPT_DIR/build-bootloader.sh" | ||
| 119 | fi | ||
| 120 | |||
| 121 | # ---- deploy kernel artifacts to esp/ (shared with the old layout) ---- | ||
| 122 | mkdir -p esp/EFI/BOOT | ||
| 123 | cp "$KERNEL" "$BZIMAGE" | ||
| 124 | [ -f "$INITRD" ] || printf '' | gzip >"$INITRD" | ||
| 125 | |||
| 126 | # ---- create the FAT volume ---- | ||
| 127 | rm -f "$IMG" | ||
| 128 | SIZE_BLOCKS=$((SIZE_MB * 1024)) # mkfs.fat counts 1024-byte blocks | ||
| 129 | echo "mksystem: creating $IMG (${SIZE_MB}M FAT32, label $LABEL)" | ||
| 130 | mkfs.fat -C -F 32 -n "$LABEL" "$IMG" "$SIZE_BLOCKS" >/dev/null | ||
| 131 | |||
| 132 | echo "mksystem: staging system tree" | ||
| 133 | mmd -i "$IMG" ::/EFI ::/EFI/BOOT ::/etc ::/bin ::/bin/cli ::/bin/gui | ||
| 134 | mcopy -i "$IMG" "$BZIMAGE" ::/bzImage | ||
| 135 | mcopy -i "$IMG" "$INITRD" ::/initramfs.cpio.gz | ||
| 136 | if [ "$CHAIN" -eq 1 ]; then | ||
| 137 | mcopy -i "$IMG" "$BOOTLOADER" ::/EFI/BOOT/BOOTX64.EFI | ||
| 138 | echo " \\EFI\\BOOT\\BOOTX64.EFI <- rsboot (full chain)" | ||
| 139 | else | ||
| 140 | mcopy -i "$IMG" "$KERNEL" ::/EFI/BOOT/BOOTX64.EFI | ||
| 141 | echo " \\EFI\\BOOT\\BOOTX64.EFI <- kernel (direct)" | ||
| 142 | fi | ||
| 143 | echo " \\bzImage \\initramfs.cpio.gz \\bin{\\cli,\\gui} \\etc" | ||
| 144 | |||
| 145 | # Seed files: motd lives in \etc, everything else at the volume root. | ||
| 146 | SEED_DIR="$PROJECT_DIR/seed" | ||
| 147 | if [ -d "$SEED_DIR" ]; then | ||
| 148 | for f in "$SEED_DIR"/*; do | ||
| 149 | [ -f "$f" ] || continue | ||
| 150 | name="$(basename "$f")" | ||
| 151 | if [ "$name" = "motd.txt" ]; then | ||
| 152 | mcopy -i "$IMG" "$f" ::/etc/"$name" | ||
| 153 | echo " \\etc\\$name" | ||
| 154 | else | ||
| 155 | mcopy -i "$IMG" "$f" ::/"$name" | ||
| 156 | echo " \\$name" | ||
| 157 | fi | ||
| 158 | done | ||
| 159 | fi | ||
| 160 | |||
| 161 | # ---- optional GPT wrapper (real-hardware dd target) ---- | ||
| 162 | if [ "$GPT" -eq 1 ]; then | ||
| 163 | GPT_START=2048 # 1 MiB offset (standard alignment) | ||
| 164 | GPT_IMG="$(mktemp)" | ||
| 165 | truncate -s "${SIZE_MB}M" "$GPT_IMG" | ||
| 166 | dd if="$IMG" of="$GPT_IMG" bs=512 seek="$GPT_START" conv=notrunc 2>/dev/null | ||
| 167 | FINAL="$(mktemp)" | ||
| 168 | truncate -s "$((SIZE_MB + 2))M" "$FINAL" | ||
| 169 | sfdisk --quiet "$FINAL" <<EOF | ||
| 170 | label: gpt | ||
| 171 | type=U, start=$GPT_START, size= | ||
| 172 | EOF | ||
| 173 | dd if="$GPT_IMG" of="$FINAL" bs=512 seek="$GPT_START" conv=notrunc 2>/dev/null | ||
| 174 | rm -f "$GPT_IMG" | ||
| 175 | mv "$FINAL" "$IMG" | ||
| 176 | echo "mksystem: wrapped in GPT (partition at LBA $GPT_START)" | ||
| 177 | fi | ||
| 178 | |||
| 179 | echo "" | ||
| 180 | echo "=== Done: $IMG ===" | ||
| 181 | ls -lh "$IMG" | ||
| 182 | echo "Boot with: make run (or: make boot-image)" | ||
| 183 | [ "$GPT" -eq 0 ] && echo "USB dd tip: add --gpt for firmwares that refuse superfloppies" | ||
| 184 | exit 0 | ||
