Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
status: open
kind: finding
opened: 2026-11-11
---

# A namespace is a kernel object, and service lookup is kept out of the kernel

An open design question, the orchestrator's to resolve. Found by the
inventory in
`issues/the-kernel-is-small-interrupts-post-and-threads-wait.md`.

The kernel holds a table of service names to connectors per namespace
(`kernel/src/object/namespace.rs`) and three calls over it,
`SYS_NAMESPACE_BUILD`, `SYS_NAMESPACE_OPEN` and `SYS_NAMESPACE_NAMES`
(`kernel/src/syscall/ipc.rs`), about 215 lines: it copies name text of up
to 64 KiB (`SYS_NAMESPACE_OPEN`, through `user_str`), compares it and lists
it. The design keeps a namespace as an immutable kernel object and, in its
statement of what stays out of the kernel, names service lookup. Both
cannot be the whole truth of this code.

The two readings: the object is the mechanism and "lookup" means a global
registry, which the kernel has none of, so nothing moves; or name text is
userland's, a process is endowed connectors and its parent's library maps
names to them, and the kernel's table and three calls go. The second is an
inference, not a design anyone wrote.

**Exit**: one reading is chosen and the design says it in one place; under
the first this file is deleted, under the second it becomes a stage of the
track.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
status: open
kind: finding
opened: 2026-11-11
---

# The kernel decides who is asked to quit and who is killed

An open design question, the orchestrator's to resolve, and an inference:
raised by the review of #1208, of the inventory in
`issues/the-kernel-is-small-interrupts-post-and-threads-wait.md`.

`SYS_PROCESS_QUIT` walks the subtree in the kernel, puts the reason in the
notice of each process that listens and kills each that does not
(`kernel/proclife/src/quit.rs`, 216 lines; `quit_process` in
`kernel/src/process.rs`; `kernel/src/object/notice.rs`, 61). The design
reads both ways: quitting gracefully is the parent's job, and interrupt,
hang-up and terminate requests are native events a program receives. Under
the first a parent would ask its children over its own protocol and the
kernel would keep only the kill; under the second the kernel's walk is the
mechanism those events need.
`issues/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`
built it as its stage 6.

**Exit**: the design says which reading holds; this file is deleted, or the
walk's removal becomes a stage of the track.
121 changes: 121 additions & 0 deletions issues/the-kernel-is-small-interrupts-post-and-threads-wait.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,127 @@ Beside that order, each waiting on something outside it:
`a_stream_truncated_at_any_offset_resyncs_within_two_packets`.
**Done** (#899).

## What the kernel still holds

An inventory at `9349705ce` (main, 2026-11-10): `git ls-files
'kernel/src/*.rs'` is 215 files and 55,378 lines by `wc -l`. Each file is
counted once, in the area of its main responsibility. "Kept" is the design
read against the code; "inferred" marks a reading the design does not
state. Nothing here is ruled, and the ranking is a proposal.

| Area | Files | Lines | Kept by the design |
|---|---|---|---|
| Memory: page tables, address spaces, frames, heap, TLB, user copies, shared memory | 27 | 7,975 | yes |
| CPU bring-up, per-CPU state, control registers, microcode, FPU state, the boot handoff | 24 | 6,304 | yes |
| IOMMU: VT-d, AMD-Vi, SMMUv3, domains, faults | 19 | 6,126 | yes |
| Objects, handles and IPC: pipes, messages, ports, namespaces, events, inboxes, the watch | 22 | 5,751 | yes, but the TTY mark (below) |
| Device claims: PCI enumeration, config space, MSI, BARs, hot-plug, `isa` rows, the framebuffer | 18 | 5,585 | yes, but the OpRegion's lookup (below) |
| Interrupt controllers, vectors, traps | 10 | 3,970 | yes |
| Log ring, console UART, panic console, panic capture, own symbols | 17 | 3,517 | yes |
| Scheduling: the core's driver, context switch, idle states, jobs, preemption | 20 | 3,160 | yes |
| Firmware tables, ACPI mode, reset and power-off, the machine's stop, what the loader named | 12 | 3,099 | yes for the tables, the `acpi` row and power; the rest below |
| Processes, threads, spawn | 8 | 2,736 | yes, less the userland text a spawn carries (below) |
| Clocks: TSC and generic timer, the wall clock, typed durations | 7 | 1,847 | the clock yes; the CMOS driver is a recorded defect (below) |
| Counters, the diary, IRQ census, mask windows, boot deadline, hard lockup, chipset watchdog | 14 | 1,844 | counters and diary yes; the three bounds are unnamed and inferred to be the kernel's, since they bound the kernel |
| Paged objects and their pager calls | 2 | 1,325 | yes |
| Syscall entry and argument decode | 3 | 806 | yes |
| Test-only: actuators, `SYS_DEBUG`, the IOMMU test device, the log storm | 6 | 668 | behind `boot-actuators` or `test-actuators` |
| Locks, seqlock, hasher, random | 6 | 665 | yes |

The kernel also links the crates beside it, whose lines carry their host
tests: `kernel/pure` (49 files, 26,108, the scheduler core 15,570 of it),
`kernel/proclife` (3,550), `kernel/pci` (2,211), `kernel/smmu` (1,463),
`kernel/its` (985), `kernel/amdvi` (902) and three under 200. `kernel/sim`
(10,242), `kernel/loom` (6,088) and `kernel/copies` (73) are harnesses no
kernel links.

Observed: no filesystem, storage, input, network, audio or USB driver, no
ELF or AML parser and no virtio is left in `kernel/src`. What it parses is
firmware's static tables (`toyos-acpi`), the build's own table
(`toyos-kimage`), the vendor's microcode container, and, below, a UEFI
device path.

### Userland's, by the design, and still here

Sizes are of `kernel/src` and read off the functions, so estimates but for
the first.

| What | Size | Dependents | Owner in the design, and what blocks it |
|---|---|---|---|
| A child's arguments and environment | about 140, by #1200's count | std, libc, `toyos::startup` | the parent's startup block: #1200 |
| Endowment labels: a blob per process for its life, answered by `SYS_ENDOWMENTS`, of which the kernel compares three (`JOB_LABEL`, `SELF_LABEL`, `QUIT_LABEL`) and writes three more for the supervisor | ~130 | `toyos::endow`, the supervisor's table | the startup block (inferred); needs the child's handle numbers known to its parent and the three compared labels as typed spawn fields; after #1200 |
| The TTY mark on a pipe end (`SYS_MARK_TTY`, `FileType::Tty`) | ~40 | std's spawn, libc's `isatty` and stdio, std's stdio | a fact about a stream that only libc and std read; a label or the block could carry it (inferred); after the labels |
| The main thread's stack: 8 MiB and a guard the kernel chooses and reserves | ~30 | `SYS_STACK_INFO`, which only a guest test calls | its creator's, since the design gives a thread's stack a caller-chosen size; after #1200, when a child's stack starts empty |
| What the loader named: partition GUIDs by role, in the inventory, and the boot sources `SYS_BOOT_SOURCES` answers, whose device paths `loaded.rs` parses (`toyos-devicepath`) only to refuse the loader's own bytes | ~95, and the kernel's link to a 324-line parser | the supervisor, `toyos::syscap`, the manifest's inventory reader | the design gives the kernel a typed description of what was loaded and keeps a partition GUID out of it; passing the description on unread, as a read-only boot image as ROOT is, fits both (inferred) and waits on no other change |
| The IGD OpRegion's lookup: a firmware window is a granted privilege the design keeps, but `SYS_DEVICE_FIRMWARE_WINDOW` finds it by reading Intel graphics' `ASLS` | ~90 and ~30 of `pcidev` | tgl-display, the supervisor, the manifest | the lookup is device knowledge; a window the ACPI service names for a claim would be generic (inferred); needs a design |
| The supervisor's last words, userland text written into the kernel's ring (`SYS_LOG_LAST_WORDS`) | ~20 | the supervisor | the design keeps userland output out of the kernel's ring and names no exception; this is one |

Changes of the design, each inferred and none of them work until resolved:

- **The program's path**, up to 64 KiB of text per process (~40 lines),
which the kernel writes into a killed program's report as its file. The
design reports a killed program by file, offset and build-id, so removing
the path changes that. It needs a frame named by build-id alone and
something in userland that maps a build-id to a file; neither is built.
- **Namespaces**:
`issues/a-namespace-is-a-kernel-object-and-service-lookup-is-kept-out-of-the-kernel.md`.
- **The stop's sweep of userland threads**:
`issues/the-kernel-stops-every-userland-thread-at-a-stop-the-supervisor-orders.md`.
- **The quit's walk**:
`issues/the-kernel-decides-who-is-asked-to-quit-and-who-is-killed.md`.

Already a defect with its exit: the x86-64 CMOS driver and its IRQ8 (285
lines), `issues/x86-64-reads-the-cmos-for-a-wall-clock-the-loader-already-hands-it.md`.

### The next removals, ranked (a proposal)

By mechanisms eliminated:

1. #1200: `SYS_GET_ENV`, the environment kept per process, the kernel's
write onto a child's stack.
2. Endowment labels, after #1200: `SYS_ENDOWMENTS`, the per-process blob
and its charge, and label text the kernel compares.
3. What the loader named, independent of the others: `SYS_BOOT_SOURCES`,
the inventory's partition records, the device-path parser.
4. The TTY mark, with or after 2: `SYS_MARK_TTY`. It meets
`issues/a-received-handle-has-no-knowable-type.md`, which wants
`SYS_FSTAT` to answer more, so the two are designed together.
5. The main thread's stack, after #1200: `SYS_STACK_INFO` and the kernel's
two stack constants.

By lines: none is large. The five ranked are about 435 of 55,378; with the
OpRegion's lookup (~120, which needs a design) and the last words (~20),
the table's rows are about 575. What the design gives userland is nearly
out, and a larger number needs one of the design changes above.

### Dead or nearly so, recorded and not deleted

- `SYS_STACK_INFO` is called by `tests/guest/rust-tests/src/bin/std_threads.rs`
alone, and `SYS_VM_DECOMMIT` by two guest tests alone (`mmap_stress`,
`starveling`).
- `KernelArgs::boot_partition_start_lba` and `boot_partition_blocks` are
read by one log line (`kernel/src/main.rs`), and `wall_clock_*` by no
x86-64 code.
- `KernelStack::heap` (`kernel/src/loader/start.rs`) charges every thread
two strings at 64 KiB and a page, "as a rename's paths". No rename is
left: a spawn's path and arguments are the two strings today. After #1200
no call copies two, and one string of that bound remains for as long as
a spawn's path or `SYS_NAMESPACE_OPEN`'s name, which nothing bounds below
64 KiB, is copied; the page is the namespace names'.
- `FileType::File`, `Directory` and `Symlink` are answered by no kernel
path: the file protocol's clients (`sdk/toyos/src/files/owner.rs`,
`sdk/libc/src/posix_io.rs`, `sdk/std/sys/fs.rs`) reuse the kernel ABI's
enum for answers the kernel never gives. The kernel's `Stat` answers
`mtime`, `volume` and `node` as zero for every object
(`issues/fstats-answer-is-declared-twice.md` owns its two declarations).
- Stale text: `kernel/Cargo.toml`'s description says "filesystem";
`kernel/CLAUDE.md`'s first caveat is about a filesystem on the idle path;
`quiesce.rs`'s header speaks of the block layer and a USB stop, neither
of which the kernel has; `UserImage`'s doc comment
(`kernel/src/process.rs`) says "the file the kernel opened", and the
kernel opens none; `loaded.rs`'s header says it "interprets no path"
above a function that parses one.

## Standing

No device wait, spin or poll happens while holding a spinlock or inside a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
status: open
kind: finding
opened: 2026-11-11
---

# The kernel stops every userland thread at a stop the supervisor orders

An open design question, the orchestrator's to resolve. Found by the
inventory in
`issues/the-kernel-is-small-interrupts-post-and-threads-wait.md`.

`SYS_SHUTDOWN` and `SYS_REBOOT` first stop every userland thread at its
next return to Ring 3 and wait for them inside a budget
(`kernel/src/quiesce.rs`, 216 lines, deciding by `toyos-quiesce`, 294, and
about 110 of `kernel/src/syscall/machine.rs`), then log the census and end
the machine. The supervisor owns the orderly stop and has already ended or
flushed what it started before it asks
(`issues/the-supervisor-is-host-tested-and-owns-the-stop.md`). The design
names the power-off as the kernel's and does not name this stop of
threads.

What is not established is what the kernel's stop holds that the
supervisor's does not: the census is of a machine that has stopped, and the
console wire is taken from its holder. Whether a supervisor that ends its
subtree before the call makes the kernel's sweep redundant is an inference
nobody has checked against the stop's tests.

**Exit**: what the kernel's sweep establishes that the supervisor's stop
cannot is written at `kernel/src/quiesce.rs`'s header and this file
deleted, or the sweep is removed as a stage of the track.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ two readers of one clock, and on x86-64 the field is written and never read.
Whether the T14's firmware answers `GetTime` from the same CMOS is not
measured.

The wall clock is not the CMOS driver's only reader: x86-64's clock takes
the RTC's update-ended edges, on IRQ8, as the third reference that tells a
TSC step from a stall of the chipset's counters
(`kernel/src/arch/x86_64/clocksource.rs`, `rtc::last_edge`). So the exit
below deletes the wall-clock read and the century register, and
`arch/x86_64/rtc.rs` whole only if that reference goes or moves with it.

Exit condition: x86-64 anchors on the loader's reading, and
`arch/x86_64/rtc.rs`, `acpi::rtc_century_register` and their callers are
deleted with it, against a metal row reading the T14's wall clock; or a
Expand Down