Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
98ae5a7
WIP: stage B in progress (declaration ABI, _CRS reader, acpiserver de…
Japabu Oct 14, 2026
633c4e1
Merge remote-tracking branch 'origin/main' into wt/toyos-aperture-b
Japabu Oct 14, 2026
cd2c246
Stage B: acpiserver declares each PCI root's _CRS windows; kernel dri…
Japabu Oct 14, 2026
d84d8c3
Fail-closed judge reads a wait under a millisecond
Japabu Oct 14, 2026
401b072
The declaration is per root bridge: segment, buses, _CRS windows and …
Japabu Oct 14, 2026
aad3aea
Functions arrive and leave: the device set, native PCIe hot-plug, Gone
Japabu Oct 14, 2026
4f5142f
Merge remote-tracking branch 'origin/main' into wt/toyos-aperture-b
Japabu Oct 14, 2026
3bbc19d
Merge remote-tracking branch 'origin/main' into wt/toyos-lifecycle-2
Japabu Oct 14, 2026
a6ab756
pcidev: arm slots after the scheduler; an unassigned register sizing …
Japabu Oct 14, 2026
084c7c3
build: hotplugcase.toml is a covered config, and a hot-plug port a de…
Japabu Oct 15, 2026
a51b01c
Merge remote-tracking branch 'origin/main' into wt/toyos-lifecycle-2
Japabu Oct 15, 2026
b710dfd
issues: stage 2 of a device function's lifecycle, and the gaps it rec…
Japabu Oct 15, 2026
927635e
issues: QEMU's hot-plug slot, as measured
Japabu Oct 15, 2026
0a67b01
One window list across roots, bounded by the declaration; a refused d…
Japabu Oct 15, 2026
71bce12
Review round 1: a malformed record refused by name, the root _OSC que…
Japabu Oct 15, 2026
cf31476
Option 1 removed: no identity domain for a kernel driver
Japabu Oct 15, 2026
48af2c2
Merge remote-tracking branch 'origin/main' into wt/toyos-aperture-b
Japabu Oct 15, 2026
de8e988
virt_claim_lpi: VirtIts has two roots, so its root 0 ends at bus 7
Japabu Oct 15, 2026
a18b42b
The per-root record carries the _OSC commit beside the offer
Japabu Oct 15, 2026
a417a64
Merge origin/main (3962d606f) into wt/toyos-aperture-b
Japabu Oct 22, 2026
1ffbdba
Every image whose rows claim a PCI function starts the ACPI server
Japabu Oct 22, 2026
674b636
issues: an aarch64 cargo run boot panics on its console's first queue
Japabu Oct 22, 2026
4e32df6
Merge origin/main (27acd19a6) into wt/toyos-aperture-b
Japabu Oct 22, 2026
2640dbf
Merge wt/toyos-aperture-b (PCI apertures stage B, #935, with main 396…
Japabu Oct 22, 2026
fa0d4f0
Merge wt/toyos-aperture-b (4e32df68c) into wt/toyos-lifecycle-2
Japabu Oct 22, 2026
6c67269
Lifecycle 2 on stage B: the slot's lines name the commit; host checks
Japabu Oct 22, 2026
c5f97d9
SMMUv3 refuses a late arrival alone, and the hot-plug row judges the BAR
Japabu Oct 22, 2026
addf8e9
slot: a port is copied whole, and a BAR's room is one value
Japabu Oct 22, 2026
a6cf5a2
issues: retired grants name no deleted issue
Japabu Oct 22, 2026
47dc013
acpiserver commits no native hot-plug on a root with an external-faci…
Japabu Oct 22, 2026
330a756
Native hot-plug fails closed: committed only where the image declares…
Japabu Oct 22, 2026
e307e60
tests: acpi_server_death is unregistered until its T14 boot has a log
Japabu Oct 22, 2026
3d62570
Merge origin/main (d7f269dbc) into wt/toyos-aperture-b
Japabu Oct 22, 2026
c65ba5d
Merge wt/toyos-aperture-b (main d7f269dbc) into wt/toyos-lifecycle-2
Japabu Oct 22, 2026
e6dd4ad
Review round 2: true comments, acpi_release goes, owners and wording
Japabu Oct 22, 2026
998918f
Merge wt/toyos-aperture-b (e6dd4addf) into wt/toyos-lifecycle-2
Japabu Oct 22, 2026
f9c1654
Review round 1: an armed port is this kernel's, and slots arm after t…
Japabu Oct 22, 2026
f9e44e0
supervisor: every acpi holder starts before the disk drivers, whereve…
Japabu Oct 22, 2026
503620c
Merge wt/toyos-aperture-b (f9e44e0fb) into wt/toyos-lifecycle-2
Japabu Oct 22, 2026
1f8edda
abi: the syscall profile has a bin for 140 and one past it
Japabu Oct 22, 2026
17e7277
object: a device set is no notice to listen to
Japabu Oct 22, 2026
dfce64e
Merge origin/main (190f3b164) into wt/toyos-lifecycle-2
Japabu Nov 1, 2026
4fd9ea2
merge fixups: main's handle, charge and osc interfaces
Japabu Nov 1, 2026
f47e0af
virtio-console: refuse a function the unit would give no memory to
Japabu Nov 1, 2026
52b50f8
issues: the aarch64 boot's claims are handed over, its terminal shows…
Japabu Nov 1, 2026
e5b34b8
review r1 of #934: an arrival is isolated before it is listed
Japabu Nov 1, 2026
97edf39
review r2 of #934: a slot is armed only over functions on their own d…
Japabu Nov 1, 2026
016d626
review r3 of #934: slots arm before the declaration is published
Japabu Nov 1, 2026
06241e9
Merge origin/main into #934: the kernel console is userland's, and th…
Japabu Nov 1, 2026
b89897e
review r4 of #934: a slot carries the windows it was armed under, and…
Japabu Nov 1, 2026
f234a58
images: the five main gave a virtio-console row start the acpi claim'…
Japabu Nov 2, 2026
ded3c60
tests: boots no claim can be made on have no console port, and the ho…
Japabu Nov 2, 2026
4424a76
issues: an aarch64 `cargo run` shows its log on its terminal, and its…
Japabu Nov 2, 2026
cce4128
issues: the owner's ruling that the supervisor times claims, staged o…
Japabu Nov 2, 2026
8388ab8
Merge origin/main into #934: #1137's revocation of what a claim hande…
Japabu Nov 2, 2026
699baad
pcidev: a departed function's apertures are revoked by the set's reader
Japabu Nov 2, 2026
ad70b5b
review r5 of #934: the departure copies what the claim handed out, an…
Japabu Nov 3, 2026
da40835
Merge origin/main into #934: #1063's SYS_TIMING_CONTROL takes 165
Japabu Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3212,6 +3212,55 @@ mod tests {
}
}

/// A config whose rows claim a PCI function starts the `acpi` claim's
/// holder: every such claim waits for the root bridges' memory it declares,
/// and one made on a boot where nothing does is refused, as are all after
/// it. `undeclaredcase` is that boot, booted to judge the refusal. A claim
/// a program makes at run time through a `device` syscap is not a row's
/// and is not seen here: its image's own test meets the refusal.
#[test]
fn every_config_that_claims_a_pci_function_starts_its_declarer() {
const UNDECLARED: &str = "tests/images/undeclaredcase.toml";
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
for config in ALL_CONFIGS {
let parsed = parse_config(&root.join(config));
let claimants: Vec<&String> = parsed
.programs
.iter()
.filter(|(name, program)| {
!program.drives.is_empty()
|| (parsed.boot.start.contains(name) && program.devices.iter().any(|d| d.starts_with("pci:")))
})
.map(|(name, _)| name)
.collect();
let declares = parsed
.boot
.start
.iter()
.any(|name| parsed.programs.get(name).is_some_and(|p| p.devices.iter().any(|d| d == "acpi")));
assert_eq!(
declares || claimants.is_empty(),
*config != UNDECLARED,
"{config}: {claimants:?} claim PCI functions, and starting the `acpi` claim's holder is {declares}",
);
}
}

/// Only the hot-plug test's image declares its hot-plug ports internal to
/// acpiserver: anywhere else it would hand native hot-plug of a port that
/// may face outside the machine to a kernel that refuses no claim behind
/// one yet.
#[test]
fn only_the_hot_plug_test_declares_its_ports_internal() {
const DECLARES: &str = "tests/images/hotplugcase.toml";
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
for config in ALL_CONFIGS {
let parsed = parse_config(&root.join(config));
let declared = parsed.programs.values().any(|p| p.args.iter().any(|a| a == "--hot-plug-ports-internal"));
assert_eq!(declared, *config == DECLARES, "{config} declares its hot-plug ports internal: {declared}");
}
}

/// Every config renders, so a row the manifest refuses — one that serves a
/// port and is not marked `service` — reds here rather than at a build.
#[test]
Expand Down Expand Up @@ -3293,6 +3342,7 @@ mod tests {
"tests/images/designatecase.toml",
"tests/images/drivescase.toml",
"tests/images/hostedclangcase.toml",
"tests/images/hotplugcase.toml",
"tests/images/jobcase.toml",
"tests/images/latencycase.toml",
"tests/images/launchcase.toml",
Expand All @@ -3307,6 +3357,7 @@ mod tests {
"tests/images/proctreecase.toml",
"tests/images/scalecase.toml",
"tests/images/testcases.toml",
"tests/images/undeclaredcase.toml",
"tests/images/virtclaimcase.toml",
"tests/images/virtjobcase.toml",
"tests/images/virtpaniccase.toml",
Expand Down
12 changes: 6 additions & 6 deletions build/licence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,15 +406,15 @@ pub const COMMITTED_FILES: &[(&str, &str, &str, Terms)] = &[
Terms::Spdx("MIT OR Apache-2.0"),
),
(
"lib/acpi/fixtures/qemu-11.1.1-virt-pptt/pptt.bin",
"fff116c865c8081e748e03fee505f2ed4fc1b01b8fbd3b131a8d1720552c86ec",
"ours: QEMU `virt`'s own PPTT, captured by the commit that decodes it",
"lib/acpi/fixtures/qemu-11.1.1-virt/dsdt.bin",
"908d068d6d70db725bd139ac5a8fe9511373ab59a0570a0f285c3c59d60cd227",
"ours: QEMU `virt`'s own DSDT, captured by the commit that declares its root bridge's `_CRS`",
Terms::Spdx("MIT OR Apache-2.0"),
),
(
"lib/acpi/fixtures/ovmf-pure-efi/root-bridge-0.bin",
"eb00e68be746a09ac7f0ce1ca492ce8c858e3af1152112b49ffb4708883acbfb",
"ours: OVMF's answer on a q35 guest, read off that boot's own loader log",
"lib/acpi/fixtures/qemu-11.1.1-virt-pptt/pptt.bin",
"fff116c865c8081e748e03fee505f2ed4fc1b01b8fbd3b131a8d1720552c86ec",
"ours: QEMU `virt`'s own PPTT, captured by the commit that decodes it",
Terms::Spdx("MIT OR Apache-2.0"),
),
// bcachefs volumes upstream's own tools wrote, gzipped. The bytes inside
Expand Down
4 changes: 3 additions & 1 deletion build/sourcegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ const NMI_SILENT: &[&str] =
/// A function handed to a *process* takes the other path: `pcidev` arms bus
/// mastering with `start_bus_mastering`, after the address space that bounds it
/// exists, so `enable_bus_master` stays what a kernel driver calls and the
/// count below stays the census of drivers this kernel has.
/// count below stays the census of drivers this kernel has, and of the one
/// port the kernel takes: a hot-plug slot's, once its message is armed.
const BUS_MASTER_SITES: &[(&str, usize)] = &[
("kernel/src/drivers/pci.rs", 1),
("kernel/src/arch/x86_64/amdvi/mod.rs", 1),
("kernel/src/pcidev/slot.rs", 1),
];

/// The one place in `kernel/` a `!!!` may still appear, and how many times.
Expand Down
4 changes: 3 additions & 1 deletion images/system.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ serves = ["log", "log-carrier"]
# firmware's own access: the kernel makes the AML's reads and writes for it,
# inside the fences of `toyos_userbound::firmware`. `power` is how a press
# stops the machine: through the supervisor, which has `logkeeper` make the
# log whole.
# log whole. It declares the memory the PCI root bridges decode out of each
# root's `_CRS`, which every PCI claim waits for, so the supervisor starts it
# before every other row; an image that claims a PCI function starts it.
[programs.acpiserver]
service = true
devices = ["acpi"]
Expand Down
13 changes: 8 additions & 5 deletions issues/a-bars-mapping-outlives-the-claim-it-was-asked-on.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ already does, so the old process's next access faults:
- when the claim moves, by IPC or a spawn's endowment. The move takes what
the claim handed out under the lock that moves it, so the new holder's
fresh mappings are not taken, and revokes it once that lock is let go.
- when its function departs from behind a hot-plug slot (#934), while its
claim is still held: the device set's reader revokes what the claim handed
out (`slot::refresh`), on its thread with no `MACHINE` or slot lock held,
and only then wakes the holder. The claim keeps the list, and its release
revokes it again before the function is given up, so the next device
behind the port, which may be given the same addresses, is never reached
through it. `a_function_arrives_and_leaves` reads a BAR handle the holder
kept from before the pull mapping `Gone` once its departure woke it.

An aperture's handle is installed only while the caller's table still holds
the claim, under that same lock, so one a sibling thread asks for across a
release or a move is refused `Gone`.

**What is left:**
- **A function's departure.** #934 adds a function leaving (Gone). It calls
`pcidev::revoke_handed(number)` from its refresh loop, never from the
hot-plug interrupt and never with `MACHINE` held. Until then, a mapping of
a function that departs while its claim is held outlives the departure.
The next device behind that port may then be given the same BAR addresses.
- **What no guest test reads.** `bar_map_again` (`tests/toyos.rs`) reads a
BAR handle kept past an IPC move and past the claim's end mapping `Gone`,
and the new holder's fresh mapping reading the device. Still unread: a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
status: open
kind: defect
opened: 2026-11-03
---

# A `cargo run` with no terminal relays nothing of the console port

`cargo run -- --arch aarch64`, launched with stdin on `/dev/null` and
stdout and stderr on a file, at #934's `ded3c605c`, QEMU 11.1.1 under HVF:

- The boot ran. Every PCI claim was handed over: the NVMe, virtio-net and
both virtio-serial functions. The UART's file
(`/tmp/toyos-uart-early.log`) reached
`console: the log is carried elsewhere from here` at 3.437 s, once
logkeeper's carrier had the log.
- The launch's own output then held one kernel line, at 3.451 s, and
nothing more in five minutes. That is everything the console port relays,
so the port relayed nothing of the replay the carrier owes from the
boot's first line.
- The same launch under `script -q` (a pseudo-terminal) showed the whole
log on its terminal: the disk driver serving its partition and
`vdagent: the host announces capabilities`.

The port's chardev is QEMU's `stdio` (`build/vmconsole.rs`, `args`), which
reads the launch's stdin. One unconfirmed explanation is that a stdin at
end of file closes that chardev, and the guest's port with it. Then the
carrier would have nowhere to write, but the UART would have to take the
log back when the carrier goes, and no such line was read. Neither
explanation is established, and x86-64 was not tried the same way.

Logs: ToyOSOrg/evidence `pr-934`
`6e68eedc826f28ff94bf6177631f1773d387d997`,
`combined-r5/arm-cargo-run.log` and `combined-r5/arm-uart-1.log`; the
pseudo-terminal run beside them as `arm-cargo-run-tty.log`.

**Owner**: whoever holds the console, `build/vmconsole.rs`.

**Exit**: a launch with no terminal either shows the log the port carries,
or is refused at the launch by name. The cause is read from QEMU's
`chardev/char-stdio.c` or a run, and stated.
116 changes: 105 additions & 11 deletions issues/a-device-function-is-driven-from-its-arrival-to-its-end.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ started. Nothing reaches userland when a device arrives or leaves.
`DEVICE_DELETED` follows a `device_del` within 6 s.
- With `ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off`, the delete
completes at once.
- **QEMU's `pcie-root-port` slot** (QEMU 11.1.1 q35, OVMF, read from the UEFI
shell; evidence
https://github.com/ToyOSOrg/evidence/tree/f66e82195fdd3e318663530e3d665db1465dc97d/lifecycle-2/slot-qemu):
- One MSI-X entry and no MSI, its hot-plug message entry 0; Slot
Capabilities `0x001a007b`: button, power controller, both indicators,
surprise, hot-plug capable, command completion. Link Changed Enable
does not stick.
- OVMF leaves the empty slot powered off, and a plugged function's
configuration space reads all ones until the slot is powered.
- With the slot powered and its power indicator on, `device_del` presses
the button, and the device stays until the guest powers the slot off.

## Stages

Expand All @@ -111,17 +122,100 @@ started. Nothing reaches userland when a device arrives or leaves.
child's `Process` handle and its waiter threads went; the virtio-serial
driver (`virtio-console`) is a `drives` row. `a_drives_row_holds_one_process_per_function` is the
guest arm, on `Profile::HeadlessTwoEdu`.
2. **Functions arrive and leave.**
- Readers get a device-set object, minted from `DEVICE`.
- The kernel provides native PCIe hot-plug on a port whose host bridge
`_OSC` granted it.
- A removed function's claim answers `Gone`.
- An arrived endpoint's BARs are placed inside its port's window. No
BAR-moving path is left to build on (P1 of `issues/there-is-no-wifi.md`):
`place_unassigned` on `wt/toyos-lifecycle-2` is rewritten as one
assignment inside the port's window with no probe, and an arrived
function's BARs enter `Machine::decoded`, which `pages::of_bar`'s
sharing check reads.
2. **Functions arrive and leave** (#934, which carries the apertures track's
stage B, #935: its declaration carries each root bridge's `_OSC` commit).
- Readers get a device-set object (`toyos_abi::devset`): a
level-triggered snapshot of every PCI function the kernel hands out,
minted from `DEVICE`, carrying `READ` and `WAIT` and neither `DUP` nor
`TRANSFER`, so the supervisor alone holds it. Its header names the time
by which a slot may change with no interrupt; the supervisor waits to it
and reads again.
- The kernel provides native PCIe hot-plug on a port whose root bridge's
`_OSC` commit granted native hot-plug and capability structure control.
acpiserver commits both where the query offered both and the image
declares its ports internal (below). The port is the
kernel's, its MSI-X entry on the claim path's remapped message; its
handler reads and clears Slot Status, takes a lost or button-removed
slot's functions out of the set, makes at most one Slot Control write
and posts the set's watch. Powering a slot, §6.6.1's 100 ms and reading
the functions below it run on the set's reader.
- One record per requester, carrying its live arrival: a device that
returns is a new arrival on the same record and domain. A slot is armed
before the declaration is published, so before any claim runs, and only
where the unit blocks every requester on the port's buses it has not
seen (a VT-d unit including every PCI device or naming a bridge over
those buses, on the enumerated segment; AMD-Vi units serving every
id there, none kept on identity by an IVMD; the IORT routing every id
through the armed SMMUv3), and once every function enumerated behind it
at boot is on a domain of its own. A slot over a function a driver in
this kernel drives, or one the unit cannot isolate, is not armed. So a
card seated behind an armed slot reaches nothing until it is claimed,
but, on VT-d, the regions firmware reserved for its requester, which
its domain maps at their own addresses. A claim of an
older arrival answers `Gone` on every call, and its release asks the
device nothing. The last release behind a removed slot powers it off.
- An arrived endpoint's BARs are assigned once, before it is listed: each
one it leaves unassigned is given the lowest address inside its port's
windows that no other function decodes in and that lies inside the
declared root bridges' memory, kept where the register reads it back,
with no probe through it. They enter `Machine::decoded`, which
`pages::of_bar`'s sharing check reads. No BAR is moved (P1 of
`issues/there-is-no-wifi.md`).
- The supervisor diffs the set (`toyos-supervisor`): a departed arrival
is never started again, and the restart budget is the address's.
- `a_function_arrives_and_leaves` is the guest arm, on
`Profile::HeadlessHotplugPort` (q35, `acpi-pci-hotplug-with-bridge-support=off`,
an `edu` behind the port from boot).

Gaps it records:
- **Physical arrival is QEMU's alone**: no bench has a hot-plug port the
owner lets a driver claim behind, so a metal row reads only the boot set
and each bridge's commit. That comes through
`issues/toyos-supports-thunderbolt-and-usb4.md`.
- QEMU's `device_del` presses the slot's button, so a surprise removal
(presence lost) is reached by `toyos_pci::hotplug`'s host tests and no
guest.
- A machine whose `_OSC` keeps hot-plug for ACPI, q35's default, has no
slot armed, and says so by port.
- acpiserver commits native hot-plug before the kernel knows whether a
slot can be armed; a machine whose units remap no interrupt has its
slots left unserved after firmware gave them up.
- **No machine's hot-plug slot is armed** (orchestrator, 2026-10-22,
holding the owner's "refuse external"): no claim behind an
external-facing port is refused in code yet
(`issues/the-iommu-refuses-nothing-yet.md`), and no firmware signal says
a port is internal. ACPI 6.5 defines none, and Microsoft's
`ExternalFacingPort` `_DSD` property ("Kernel DMA Protection") marks
the external ports alone. So acpiserver commits native hot-plug only
where its image declares every hot-plug port internal
(`--hot-plug-ports-internal`), which only the QEMU hot-plug test's image
does, and even then not on a root with a port marked external or one
whose `_DSD` it cannot read. Exit: claims behind an external-facing port
are refused by name, and a machine's own ports are then armed.
- §6.7.1.5's five seconds in which a second press cancels a removal are
not offered: a press removes at once.
- A bridge below a slot (a switch) is not read: the kernel assigns no bus
numbers.
- A powered, occupied slot whose link never comes up is owed nothing and
says nothing: no settle time asks again, and no line names the stall,
where its port enables no Link Changed interrupt (QEMU's does not).
Exit: such a slot is given a deadline, and its stall is said once the
deadline passes, with the bound cited from PCIe base spec 6.0.
- §6.6.1's 100 ms after the link comes up is waited out on every port;
Readiness Notifications (§6.23), which end it early where a port and
device support them, are not read.
- On AArch64's SMMUv3 a function that arrived after the unit was
programmed is listed and refused a claim by name: its routes are read
for the functions enumerated at boot.
- **Next, by the owner's ruling of 1–2 Nov 2026: claims are the
supervisor's to time.** The kernel's wait at claim time for the root
bridges' declaration goes; the supervisor starts `drives` processes off
the device set once the declaration is in it. That restores
`acpi_server_death` (`issues/the-acpi-servers-death-has-no-readback-on-the-t14.md`)
and the guest arm on a held function's configuration
(`issues/no-guest-reads-a-held-functions-configuration-refused-to-the-acpi-holder.md`),
both lost because a boot whose first `acpi` holder is a job can hold no
claim. Its own PR, after #934.
3. **Drivers leave the shared services.** netstack, soundserver and diskserver
each become a driver per function plus the service its clients use. The
client port carries a per-device source and `gone`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ opened: 2026-10-14
`kernel/src/pcidev/mod.rs`'s `release` resets a function whose holder ended
and parks that holder's grants in `Function::retired`, mapped in its domain
until the reset is quiet, so nothing the function had issued lands in a page
handed on. Only that function's next claim frees them (`finish_retired`). A
function reset, released and never claimed again keeps up to
`MAX_GRANT_TOTAL` (32 MiB) of grant pages for the rest of the boot. Across
the machine that is bounded only by the functions released and not reclaimed.
handed on. A function that leaves the device set has them freed when it is
retired (`retire`): nothing behind a slot that lost it can write any more.
A function that stays, reset, released and never claimed again keeps up to
`MAX_GRANT_TOTAL` (32 MiB) of grant pages for the rest of the boot, since only
its next claim frees them (`finish_retired`). Across the machine that is
bounded only by the functions released and not reclaimed.

Owner: `issues/a-device-function-is-driven-from-its-arrival-to-its-end.md`,
whose stage 2 ends a function's claim with `Gone`.
Freeing them once the reset is quiet is work at a deadline that no thread
of the claim's is left to do, and the kernel runs no work of its own: some
thread that asks the kernel anything about the function, or the device
set's reader, has to be charged with it.

Owner: `issues/a-device-function-is-driven-from-its-arrival-to-its-end.md`.

Exit condition: a released function's retired grants are freed once its
reset is quiet, whether or not it is claimed again, and a test that releases
Expand Down
Loading