SchOS/tools/posix/mkdisk.sh
Nexoniarz d7352c0db0 storage: AHCI, GPT/MBR partitions, and a disk a PC can boot
q35 stopped with "no root filesystem" because its disk is SATA, like
every PC since 2008, and SchOS only had IDE. And SchFS could only sit
on a whole raw device, so nothing could boot from a disk that also
carried an ESP.

- include/blkdev.h, kernel/dev/blkdev.c: a registry of block devices
  found at probe time, numbered from 4. A disk's GPT (or MBR) is read
  when it registers, and each partition becomes a device whose block 0
  is the partition's first sector. SchFS needs no format change to live
  in a partition; a Linux SchFS driver will see the same bytes on
  /dev/sdX2. SchFS has its own GPT type:
  47138FA9-B79C-47A6-9F7D-AC1F7F572D5E.
- AHCI driver, written from the AHCI 1.3.1 spec: BIOS handoff,
  COMRESET when the link is down, IDENTIFY, 48-bit DMA read/write,
  FLUSH. Completion is polled, so the root disk does not depend on
  interrupt routing.
- USB sticks also register as usb0, so their partitions are found.
- The root probe tries registered devices between USB and IDE,
  SchFS-typed partitions first.
- make disk / tools/posix/mkdisk.sh: a GPT image with a 64 MB ESP and
  a SchFS partition, ready to dd to a stick or a disk.

Tested in QEMU q35: the old two-disk setup roots on sata1; disk.img as
the only SATA disk roots on sata0p2; disk.img as a USB stick (firmware
boots from it) roots on usb0p2. Writes survive sync in each case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
2026-10-22 10:57:41 +02:00

73 lines
2.7 KiB
Shell

#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Build a partitioned SchOS disk: the image a real machine boots from.
#
# tools/posix/mkdisk.sh <esp-dir> <schfs.img> <output.img>
#
# A GUID partition table with two entries:
#
# 1 EFI system partition FAT, holding <esp-dir> (the loader and kernel)
# 2 SchFS <schfs.img>, byte for byte, typed
# 47138FA9-B79C-47A6-9F7D-AC1F7F572D5E
#
# This is the layout every UEFI machine expects: the firmware finds the ESP by
# its type and runs EFI/BOOT/BOOTX64.EFI from it, and the kernel finds the root
# by scanning the same table -- the SchFS type first, anything else after (see
# rootdev_mount() in kernel/proc/proc.c). Write it to a USB stick or a disk
# with dd and it boots; attach it to QEMU's q35 as its only disk and it boots
# the same way.
#
# The SchFS partition holds the volume unchanged. A filesystem addresses
# blocks from the start of whatever it is on, and the kernel hands a partition
# to it as a device whose block 0 is the partition's first sector -- so the
# image mkschfs writes for a whole disk is already the right content for a
# partition, and so is anything a Linux SchFS driver is given as /dev/sdX2.
#
# Needs sfdisk (util-linux) and mtools. Nothing here needs root or loop
# devices: the FAT is built in a file and copied in at its offset.
set -eu
esp=$1
vol=$2
out=$3
SCHFS_TYPE=47138FA9-B79C-47A6-9F7D-AC1F7F572D5E
ESP_TYPE=C12A7328-F81F-11D2-BA4B-00A0C93EC93B
for t in sfdisk mformat mcopy; do
command -v $t >/dev/null || { echo "mkdisk: needs $t" >&2; exit 1; }
done
# Sizes in 512-byte sectors. The ESP is 64 MB, which leaves room for the
# kernel to grow by an order of magnitude; partitions start on 1 MB
# boundaries, which is what every partitioning tool does and what flash
# media erase in.
esp_mb=64
esp_start=2048
esp_sectors=$((esp_mb * 2048))
vol_bytes=$(wc -c < "$vol")
vol_start=$((esp_start + esp_sectors))
vol_sectors=$(( (vol_bytes + 511) / 512 ))
# 1 MB at the end for the backup GPT, rounded the same way.
total=$((vol_start + vol_sectors + 2048))
rm -f "$out" "$out.esp"
dd if=/dev/zero of="$out" bs=512 count=0 seek=$total 2>/dev/null
sfdisk --quiet --label gpt "$out" <<EOF
start=$esp_start, size=$esp_sectors, type=$ESP_TYPE, name="EFI system"
start=$vol_start, size=$vol_sectors, type=$SCHFS_TYPE, name="SchOS"
EOF
# The ESP, built apart and copied in.
dd if=/dev/zero of="$out.esp" bs=1M count=$esp_mb 2>/dev/null
mformat -i "$out.esp" -F -v SCHOS ::
mcopy -i "$out.esp" -s "$esp"/* ::
dd if="$out.esp" of="$out" bs=512 seek=$esp_start conv=notrunc 2>/dev/null
rm -f "$out.esp"
dd if="$vol" of="$out" bs=512 seek=$vol_start conv=notrunc 2>/dev/null
echo "mkdisk: $out -- ESP ${esp_mb} MB, SchFS $((vol_bytes >> 20)) MB"