Files
LithosAnanake/docs/v4.0.0/plans/2026-10-26-stick-2-gpt-reader.md
T
rajamesandClaude Opus 5.5 2e71f7aa0d fix(kernel): a GPT disk with a bad header, or an unreadable first block, is not used
The increment 2 final review's minors 1-4 (Captain Bob, 2026-10-27: "fix 1-4"):
1. A protective MBR with no "EFI PART" header is GPT_BAD, not GPT_NONE: the
   MBR says it is a GPT disk, and a GPT disk is never attached whole.
2. A disk whose block 0 cannot be read is GPT_EIO: "GPT: a USB drive could
   not be read -- not used", nothing attached (it was read raw, attached
   whole, and a raw Zuse drive behind it logged her in).
3. The entry array's LBA is checked against the disk's size directly.
4. gpt_bad_entries: the entry array changed, the header valid -- refused.
Harness modes gpt_no_header, gpt_read_error (blkdebug EIO on sector 0),
gpt_bad_entries. The plan carries the amendment.

Red (amd64): gpt_no_header 070335, gpt_read_error 070717 FAIL;
gpt_bad_entries 070048 PASS (existing check, now pinned). Green: every GPT
mode on amd64 071113-072933; gpt_zuse, gpt_read_error, gpt_no_header on
aarch64 073222-074047 and riscv64 074526-075535; the identity gate's and
increment 1's sessions 080036-082345, emergency 083130 (082635 was run
without EMERGENCY_CONSOLE_ENABLED=1 -- a harness invocation error).
Accepted: suite EXIT 0; 093121, 093352, 093750, POST 538/538, dict_hash
0xfec8c47cfc6f437f; test-32, 0 failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 12:17:00 -04:00

10 KiB

The stick, increment 2: the GPT reader — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans (Captain Bob prefers native execution). Steps use checkbox (- [ ]) syntax for tracking.

Goal: The kernel reads a disk's GPT and makes a block device of each StarshipOS partition on it, on every ISA; the v4 boot recognises Zuse on a GPT drive's identity partition, and raw identity drives are read exactly as now.

Architecture: One kernel file, gpt.c: a CRC-32, a reader that checks the protective MBR, the primary GPT header and its partition-entry array (both CRCs) and lists the partitions, and a thin blkio backend whose block 0 is a partition's first 1 KiB. The v4 boot's drive-arrival path tries GPT first: a disk with a valid GPT is used through its StarshipOS identity partition, and that partition device -- not the disk -- is what the block subsystem is given, in the place a raw identity drive has today (everything past its metadata is the identity's own block storage); a GPT disk with no StarshipOS partition, or a damaged one, is given to nothing; a disk with no GPT is read raw, exactly as today. Artemis from a partition, the boot disk, and genesis are increments 4 and 5; this one only reads.

Tech Stack: freestanding C99 kernel; QEMU (blockdev-add/device_add of a GPT test image); sfdisk + dd to build the test images; scripts/qemu_session.py.

Spec: docs/v4.0.0/STICK.md §3 (GPT for boot media and installed disks, raw identity drives still accepted), §4 (the layout, the GPT reader, partition devices, "the identity and Artemis formats do not change"), §11 increment 2.

Global Constraints

  • As increment 1's plan (2026-10-26-stick-1-screen-and-keyboard.md): branch, commits, strict C99, -Werror, v3 unchanged, QEMU/bare-metal parity, no fix outside the plan, full acceptance on every kernel-affecting task (three clean qemu boots to [zuse@Hera] ok> , POST 538/538, dict_hash 0xfec8c47cfc6f437f equal on all three, make -C v4 test-32 0 failures, logs committed).
  • The two StarshipOS partition type GUIDs (generated 2026-10-26, fixed from here; mkdiskimage.sh uses the same values in increment 3):
    • StarshipOS identity: 23BEBFE1-4817-4CF3-A537-9069BF159788
    • StarshipOS Artemis: BCD7B586-1C8E-4EEF-86A3-273A8D8EE624
  • GPT as UEFI 2.x defines it: protective MBR (type 0xEE at LBA 0), header at LBA 1, signature "EFI PART", revision 0x00010000, header size 92..512, header CRC-32 over HeaderSize bytes with its own CRC field zeroed, entry array CRC-32 over NumberOfPartitionEntries * SizeOfPartitionEntry bytes, entry size a multiple of 128. Little-endian GUIDs on disk (mixed-endian first three fields).
  • 512-byte logical sectors only (USB sticks and the data stick). A disk reporting another sector size is not read as GPT (said once, used raw). 4 KiB-sector disks are INSTALL's, later.
  • A partition is used only if its first LBA and its sector count are both even (it starts and ends on a 1 KiB blkio block); otherwise it is skipped with a message. Every image this project builds starts partitions at 1 MiB.
  • No v3 change: the v3 path does not read GPT (system=v3 is refused on a stick, STICK.md §5, in increment 4).

Ruled (Captain Bob, 2026-10-26, on reviewing this plan): a GPT disk is never attached whole. The identity partition device is attached in the raw identity drive's place; a GPT disk with no StarshipOS partition, or a damaged one, is not attached at all. So a plain GPT data stick does not appear as raw block storage on v4, as it would on v3 -- a change from today, accepted.

Review Focus

  1. A GPT whose header CRC or entry-array CRC is wrong is not used: no partition device, not attached, not read raw either (a damaged stick is not a raw identity drive), one message. Pinned in Task 1 (gpt_bad_crc).
  2. A GPT disk with no StarshipOS partition (an ordinary data stick) gives no identity, is not attached, no fault, no prompt. Pinned in Task 1 (gpt_foreign).
  3. A partition device reading past its end is refused (BLKIO_EINVAL), never reaching the neighbouring partition. Covered by the backend's bound and by gpt_zuse's identity check, which reads offsets taken from the drive.
  4. Raw identity drives (disk/zuse-scratch/) still work: the identity gate's sessions all pass.
  5. The partition device detaches with its disk: pulling a GPT Zuse drive ends her session exactly as pulling a raw one does. Pinned in Task 1 (gpt_hotplug).

Task 1: The GPT reader, and Zuse from a GPT identity partition

Files:

  • Create: kernel/src/gpt.c, kernel/include/starkernel/gpt.h
  • Modify: kernel/Makefile (add $(KERNEL_SRC)/gpt.c beside homeblocks_sig.c in both source lists)
  • Modify: kernel/src/v4/sk_v4_identity.c (sk_v4_drive_arrived / sk_v4_drive_left)
  • Modify: scripts/qemu_session.py (modes below; it builds the GPT test images)

Interfaces (produces):

  • extern const uint8_t gpt_type_starship_identity[16], gpt_type_starship_artemis[16]; — the on-disk (mixed-endian) bytes of the two GUIDs above.
  • typedef struct { uint8_t type[16]; uint64_t first_lba; uint64_t last_lba; } gpt_part_t;
  • int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count); — returns GPT_OK (0, a valid GPT; *count partitions with a non-zero type, at most max), GPT_NONE (no protective MBR or no "EFI PART": not a GPT disk), or GPT_BAD (a GPT, but a CRC, the revision, the sizes or the geometry is wrong). Reads only; uses blkio_read.
  • int gpt_find(const gpt_part_t *parts, unsigned count, const uint8_t type[16]); — the index of the first partition of that type, or -1.
  • typedef struct { blkio_dev_t *disk; uint32_t first_fblock; uint32_t fblocks; } gpt_part_dev_t;
  • int gpt_part_open(blkio_dev_t *dev, gpt_part_dev_t *st, blkio_dev_t *disk, const gpt_part_t *p); — opens dev as that partition: fblock n is the disk's first_lba/2 + n; total_blocks is the sector count / 2; reads and writes past the end are BLKIO_EINVAL; flush/info pass through. BLKIO_EINVAL for an odd first LBA or sector count.
  • uint32_t gpt_crc32(const void *buf, size_t len); — IEEE 802.3, reflected, poly 0xEDB88320, init and final XOR 0xFFFFFFFF (gpt_crc32("123456789", 9) == 0xCBF43926).

Interfaces (the v4 drive path, sk_v4_identity.c): on arrival, after blkio_usb_open_msc, gpt_read on the raw device:

  • GPT_OK with a StarshipOS identity partition: open the partition device (kept per slot beside the raw blkio_dev_t); give the partition device to the block subsystem (blk_subsys_attach_device), never the raw disk; run the signature check and capsule_zuse_boot_check on the partition device; the device remembered as Zuse's is the partition device.
  • GPT_OK with no StarshipOS partition: nothing attached, no identity check, no message.
  • GPT_BAD: "GPT: a USB drive has a damaged partition table -- not used"; nothing attached.
  • GPT_NONE: exactly today's raw path.

Amended (Captain Bob, 2026-10-27, after the final review: "fix 1-4"): a disk with a protective MBR but no "EFI PART" header is GPT_BAD, not GPT_NONE -- the MBR already says it is a GPT disk, and a GPT disk is never attached whole. A disk whose block 0 cannot be read is GPT_EIO (3): "GPT: a USB drive could not be read -- not used", nothing attached. The entry array's LBA is checked against the disk's size directly. Pinned by gpt_no_header, gpt_read_error and gpt_bad_entries (the entry array's CRC, the header intact).

  • On detach (sk_v4_drive_left, called with the raw slot): if that slot has an open partition device, it is the partition device that is detached from the block subsystem and compared with Zuse's; the raw device otherwise, as today. A slot that was never attached detaches nothing.

  • Step 1: Failing tests — the harness gains make_gpt_image(path, parts) (truncate, sfdisk with the type GUIDs above, dd a payload into a partition at its start) and these modes (amd64; then gpt_zuse on aarch64 and riscv64):

    • gpt_zuse: no drive at boot; hot-add a 72 MiB GPT image whose partition 1 (LBA 2048, 131072 sectors, type StarshipOS identity) holds disk/zuse-scratch/zuse-thumb-ident.img; expect "Zuse: identity confirmed from attached thumbdrive", [zuse@Hera] ok> , 3 4 + . gives 7 ok. Booted with KERNEL_ARGS=--log-level=info, the block subsystem's attach line for the partition (blk: disk ... LBN ..., 64 MiB) appears -- the positive control for the two modes below. Today: FAIL (the raw check at the disk's devblock 1 finds partition entries, not LAHB).
    • gpt_hotplug: as gpt_zuse, then device_del → "Zuse: session ended"; re-add → prompt. Today: FAIL.
    • gpt_foreign: hot-add a GPT image with one Linux-filesystem partition (0FC63DAF-…) holding the Zuse image; no identity, no ok> for 30 s, no fault, and -- booted with KERNEL_ARGS=--log-level=info, since the attach line is an INFO message the v4 boot otherwise hides after POST -- no block-subsystem attach line for it (the log's blk: disk ... LBN lines do not grow). Today: FAIL on the attach (the raw disk is attached).
    • gpt_bad_crc: the gpt_zuse image with one byte of the primary header's CRC field flipped; no identity, no ok> for 30 s, the log says the table is damaged, and (booted with KERNEL_ARGS=--log-level=info) no attach line for it. Today: FAIL on the message and the attach.
  • Step 2: Run each; record the failures.

  • Step 3: Implement gpt.c and the drive-path change as above.

  • Step 4: Every mode passes (gpt_zuse on all three ISAs); the identity gate's sessions (headless, zuse, hotplug, midpull, waitpull, typeahead, emergency) and increment 1's (screen_dark_until_login, screen_dark_after_logout, kbd_typeahead) still pass.

  • Step 5: Suite; full acceptance; commit feat(kernel): the GPT reader, and Zuse from a GPT identity partition with the logs.