docs(v4): the stick, increment 2 plan: the GPT reader
Approved by Captain Bob 2026-10-26, with his ruling on review: a GPT disk is never attached whole -- the identity partition is attached in the raw identity drive's place; a GPT disk with no StarshipOS partition, or a damaged one, is not attached. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a78cc56c31
commit
7f297f4e99
@@ -0,0 +1,132 @@
|
||||
# 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.
|
||||
- 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.
|
||||
Reference in New Issue
Block a user