Skip to content

A partition is a claimable device, named by its unique GUID: the ABI names one and moves its blocks - #487

Merged
Japabu merged 4 commits into
mainfrom
wt/toyos-partclaim-abi
Sep 24, 2026
Merged

Japabu merged 4 commits into
mainfrom
wt/toyos-partclaim-abi

Conversation

@Japabu

@Japabu Japabu commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

The ABI half of the owner's ruling that a GPT partition is a claimable device, exactly as a PCI function is. The kernel here refuses every new call by name; the implementation, init's live grant and the tests are the stacked second PR (#489).

What changed, per decision

  • Spelling. part:<GUID> names a partition by its unique partition GUID, and that is the only name a partition has: one device class, Partition = 8. The GUID is the uppercase registry form and nothing else — one spelling per partition, as PciId has one per card. DeviceRequest::MAX_NAME 16 -> 48 (part: and a GUID is 41 bytes, rounded up to a multiple of eight). A static row names a slot by its unique GUID because whoever writes the GPT also writes the system.toml that names it and fixes the GUID; a type GUID would not name an A/B slot (both carry TOYOS-ROOT's), and whether one resolved would depend on which other disks are plugged in.
  • PartGuid (toyos-abi/src/part.rs) holds the sixteen bytes a GPT entry stores (UEFI 2.10 §5.3.3); text <-> bytes is the mixed-endian registry mapping.
  • No new claim syscall. SYS_DEVICE_CLAIM already carried a fourth argument word as zero; the GUID's sixteen bytes ride the selector and that word. A selector word a class does not read is refused (InvalidArgument) rather than dropped: both words for a class that names at most one device, the second for pci.
  • Transfers. SYS_PARTITION_READ = 119, SYS_PARTITION_WRITE = 120: (claim, first, buf, count). Block numbers are the partition's own, from 0 — no argument can spell a device block, so a neighbour's blocks are unrepresentable; the end of the partition is the kernel's refusal (InvalidArgument). Buffers are typed [[u8; 4096]], so a partial block is unrepresentable and the count is the slice length. At most 32 blocks per call (MAX_BLOCKS_PER_CALL); a later, larger bound does not break a caller compiled against 32.
  • Durability is SYS_FSYNC on the claim: the same number and the same promise a file has. No new flush syscall.
  • Description. A claim reads once as PartitionInfo { blocks, unique_guid } (24 bytes, no padding, asserted).
  • SDK. SysCap::claim_partition(PartGuid), endow::partition(PartGuid), PartitionDev { describe, read, write, sync }. endow::partition's caller is A partition is claimed by its unique GUID, held by one holder, its blocks move through the claim, and its fsync answers for its own writes #489's guest, which takes the claim init minted from a part: row.
  • Kernel matches. The four exhaustive matches on a device class in object/ops.rs answer the new class (no readiness source; a read is the description; Unknown on stat; always readable) — unreachable until the claim is served.
  • init gains the one match arm the new variant forces (claim_partition), and its refusal lines stop saying "function" and "pcidev:" only.
  • Kernel (this PR). try_claim takes both selector words; the partition class answers NotSupported with a partclaim: line, and 119/120 answer NotSupported naming themselves.
  • toyos-abi 0.6.0 -> 0.7.0, toyos 0.7.0 -> 0.8.0, toyos-window 0.7.0 -> 0.8.0 for its pins; lockfiles follow.

Gates (head 6d030c13, each run once)

  • cargo run -- --build-only --claim-sysroot: EXIT=0
  • cargo test -p toyos-build --lib: EXIT=0
  • cargo test --workspace --exclude toyos-build: EXIT=0 (toyos-abi's partition tests among them)
  • cargo run -- --sdk-version-check: EXIT=0
  • cargo run -- --abi-split-check: EXIT=0
  • cargo run -- --clippy: EXIT=0
  • cargo test (fast tier): EXIT=0 — 356 passed, 8 quarantined and green, 356 total (233.4s). sshd_fail_closed, red once at cb4d26ec beside another worktree's suite, is green in this run.

Oracle

UEFI 2.10 §5.3.3 / Appendix A: the ESP type's registry text C12A7328-F81F-11D2-BA4B-00A0C93EC93B and its on-disk bytes are the test of PartGuid in both directions. The negative controls for the mechanism, and the guest arm that sends the selector words no typed wrapper can spell, are in #489, where the checks they remove live.

Unsure

  • The migration from the stick to the NVMe by whole-disk clone puts every unique GUID on two disks while both are attached, and every part: claim is then refused as ambiguous: that plan has to give the clone's partitions GUIDs of their own.

🤖 Generated with Claude Code

https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK

Japabu and others added 2 commits September 24, 2026 10:33
…ocks

The owner's ruling: a GPT partition is claimed exactly as a PCI function is,
named by its GPT identity in a `devices` entry, minted by init from its
`SysCap` and endowed. This is the half the shared sysroot carries; the kernel
here refuses every new call by name, and the implementation, init's live
grant and the tests are the second branch.

The spelling. `part:<GUID>` names a partition by its unique partition GUID and
`part-type:<GUID>` as the one partition of a type on the machine; a type more
than one entry carries names no partition, refused like two identical NICs.
Two device classes (8 and 9) rather than a flag, because the class is what
says how the selector words are read. The GUID is the uppercase registry form
and nothing else, one spelling per partition as `PciId` has one per card;
`PartGuid` holds the sixteen bytes a GPT entry stores (UEFI 2.10 §5.3.3) and
the ESP type's text and bytes from the specification are its test.
`DeviceRequest::MAX_NAME` goes 16 -> 48 for the longest entry, 46 bytes.

The claim. `SYS_DEVICE_CLAIM` already had a fourth argument word it passed as
zero; the GUID rides the selector and that word, so no claim syscall is added.

The transfers. `SYS_PARTITION_READ` (119) and `SYS_PARTITION_WRITE` (120) take
the claim, the partition's own first block, a buffer and a block count. The
block numbers are the partition's own from 0, so no argument can spell a
device block and a neighbour's blocks have no name; the end is the kernel's
refusal. The buffers are typed `[[u8; 4096]]`, so a partial block has no
spelling and the count is the slice's length. One call carries at most 32
blocks, the run the kernel's own page cache writes back in. Durability is
`SYS_FSYNC` on the claim, the same number and the same promise a file has.

A claim describes itself once as `PartitionInfo`: its length in blocks and
both GUIDs, so a claim named by type can say which partition it got.

`toyos-abi` 0.6.0 -> 0.7.0, `toyos` 0.7.0 -> 0.8.0, and `toyos-window` with
them for its pins.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
The class enum gained two rows and four exhaustive matches in the object
layer did not know them; the kernel did not compile. A partition claim has no
readiness source, answers every read with its description (its bytes move
through the transfer calls, never through a read of the claim), stats as
Unknown and is always readable. None of these is reachable yet: the claim
itself is still refused by name.

`PartitionInfo` gains `unique()` and `of_type()`, the two GUIDs as the
`PartGuid`s a `part:` and a `part-type:` entry spell — what a holder compares
its description against.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
@Japabu

Japabu commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #487 at cb4d26ec, round 1.

CI at cb4d26ec, checked during the review: host SUCCESS, abi-split SUCCESS, gate-stage SUCCESS, toolchain-ready IN_PROGRESS. The brief had me review alongside CI, so I did not wait for it. I ran cargo test -p toyos-abi at cef986e5 (which touches no toyos-abi file): EXIT=0, 34 passed, the three part::tests among them.

BLOCKER

  • toyos-abi/src/syscall.rs:1208: part-type: / PartitionOfType is a second name for the same kind of object, and nothing uses it except the test. The A/B slots share TOYOS-ROOT's type, so it can never name either slot. The one-disk ambiguity refusal is measured green: the guest prints "a type two partitions carry refused with InvalidArgument". Whether a working grant resolves also depends on which other disks are plugged in: a second ToyOS stick, or for EBD0A0A2 nearly any stick, turns it into InvalidArgument at boot. The argument that "a static row cannot name a random GUID" does not hold: src/image.rs and the test's craft() write both the GPT and the system.toml, so each can fix a slot's unique GUID and spell part:. For the updater, grant part:<A> and part:<B>. The mounted slot is refused PermissionDenied by name, and the idle slot is granted. Remove the class and the prefix now, while no class number has shipped.

NOTE

  • toyos-abi/src/part.rs:30: 32 blocks per call is an adequate shape for a slot write. The throughput limit is one synchronous command per call under Handle::lock, plus a 128 KiB bounce, not the count. A later larger bound does not break callers compiled against 32. There is no hardware reading behind any of this; it is an estimate.
  • toyos-abi/src/syscall.rs:979: fsync on the claim is the right shape for marker-last (slot, fsync, marker, fsync), but only when the marker is inside a claimable partition. The ESP is kernel-held (measured PermissionDenied), and the GPT lies outside every partition, so a boot-selection marker in /boot or in GPT attributes is out of this ABI's reach. On a USB disk the promise in this doc line is not kept; see A partition is claimed by its unique GUID, held by one holder, its blocks move through the claim, and its fsync answers for its own writes #489.
  • kernel/src/arch/syscall/dispatch.rs:428: every class except the two partition classes silently ignores the second selector word. A nonzero word for pci: or a bare class should be refused, not dropped.
  • part: across disks: a whole-disk clone (the NVMe taking over from the stick by copying the image) carries every unique GUID twice, so every part: grant is refused InvalidArgument while both disks are attached. The migration plan has to allow for this.
  • toyos/src/endow.rs:214: endow::partition has no caller and no test. The guest mints with claim_partition and never takes the endowment init made. Delete it until the consumer exists, or cover it.
  • The author's fast-tier red sshd_fail_closed (per the body, --known-red says NO) is not adjudicated. I did not re-run it.

REMOVE

  • toyos-abi/src/part.rs:27-29: "the run the kernel's own page cache writes back in, so a claimant holds its disk no longer per call than the kernel does". page_cache.rs Cached::lock holds handle().lock() for the whole sync, and that sync's 32 is its own literal (page_cache.rs:366,376). Nothing ties it to this constant.

SEND BACK

…elector word its class does not read

Round-1 review of #487.

- `part-type:` / `PartitionOfType` is deleted. The A/B slots share
  TOYOS-ROOT's type, so a type names neither slot, and whether a type grant
  resolved depended on which other disks were plugged in. Whoever writes a
  GPT and the `system.toml` that names its slots fixes each slot's unique GUID
  and spells `part:`. `PartitionName` goes with it: a request carries a
  `PartGuid`, `SysCap::claim_partition` and `endow::partition` take one, and
  `PartitionInfo` loses the type GUID only a type-named claim needed (24
  bytes, asserted).
- `SYS_DEVICE_CLAIM` refuses a nonzero selector word its class does not read
  (`InvalidArgument`): both words for a class that names one device, the
  second for `pci`. It used to drop them.
- `MAX_BLOCKS_PER_CALL` loses its rationale: nothing ties it to the page
  cache's own write-back run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
@Japabu Japabu changed the title A partition is a claimable device: the ABI names one and moves its blocks A partition is a claimable device, named by its unique GUID: the ABI names one and moves its blocks Sep 24, 2026
Japabu added a commit that referenced this pull request Sep 24, 2026
…only

The kernel side of the merge: `try_claim` reads the selector as one
partition's unique GUID, `gpt::claimable` looks for that GUID alone (the type
scan and its second lookup go with `part-type:`), and the partition matches
name one class. `PartitionInfo` no longer carries a type GUID. The guest and
its host test still spell `part-type:`; the commits after this rewrite them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
@Japabu

Japabu commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #487 at 6d030c13, round 2.

CI at 6d030c13, checked at 10:51 UTC: host, abi-split and gate-stage SUCCESS; toolchain-ready (the ci workflow) IN_PROGRESS since 10:07. Locally cargo test -p toyos-abi -p toyos-xhci gave EXIT=0: 34 and 114 passed. toyos-abi is identical at 6d030c13 and at #489's fff0a7cf.

Round-1 BLOCKER

  • part-type: / PartitionOfType: CLOSED. rg 'part-type|PartitionOfType|OfType|PART_TYPE' outside issues/ finds one hit, the negative parse test toyos-abi/src/syscall.rs:2246. It asserts that part-type: parses to None. device_classes! ends at Partition = 8, so class 9 never shipped and there is no number to retire. PartitionInfo is 24 bytes, and that is asserted.

BLOCKER

(none)

NOTE

REMOVE

(none)

NOT READY FOR REVIEW

@Japabu
Japabu enabled auto-merge September 24, 2026 10:53
@Japabu
Japabu added this pull request to the merge queue Sep 24, 2026
@Japabu
Japabu removed this pull request from the merge queue due to a manual request Sep 24, 2026
@Japabu
Japabu added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 1fe0a78 Sep 24, 2026
2 checks passed
Japabu added a commit that referenced this pull request Sep 24, 2026
Main carries partition claims (#487), path isolation (#488) and host-only PR CI.
The one conflict was tests/toyos-rust-tests/Cargo.lock: main bumped toyos to
0.8.0 and toyos-abi to 0.7.0; the branch added toyos-i219. Both kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
@Japabu
Japabu deleted the wt/toyos-partclaim-abi branch September 28, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant