Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3651887
The panic console takes no input, and an isa claim grants a process e…
Japabu Sep 28, 2026
e72cf7f
The track names #592 and its line count; the refusal boot runs nightly
Japabu Sep 28, 2026
4783332
Merge origin/main into wt/toyos-ps2
Japabu Sep 29, 2026
7c13193
The crash report reads user memory through a split window's 4 KiB leaf
Japabu Sep 29, 2026
417313f
Merge origin/main into wt/toyos-ps2
Japabu Sep 29, 2026
f9a2f27
PR #592 round 3: the crash report reads only user memory, the panel s…
Japabu Sep 29, 2026
418df1f
issues: the future i8042 server is ps2server, not ps2d
Japabu Sep 29, 2026
744b782
PR #592 round 4: the quarantine's flood closes to one CPU, the after-…
Japabu Sep 29, 2026
494bfb0
PR #592 round 5: the i8042's flood is taken at most once per boot
Japabu Sep 29, 2026
708738e
Merge origin/main into wt/toyos-ps2
Japabu Sep 29, 2026
51f6faa
Merge remote-tracking branch 'origin/main' into wt/toyos-ps2
Japabu Sep 29, 2026
0d537d7
PR #592 round 6: the i8042's quarantine is taken and let go on IRQ_CP…
Japabu Sep 29, 2026
af11b61
Merge remote-tracking branch 'origin/main' into wt/toyos-ps2
Japabu Sep 29, 2026
cdc0ec1
PR #592 round 7: a late i8042 edge is staged under the holder's byte
Japabu Sep 29, 2026
34ef28c
i8042: the quarantine's ordering claims name the accesses that drive …
Japabu Sep 29, 2026
6e51bfc
Merge origin/main (ec7de748c) into wt/toyos-ps2
Japabu Oct 3, 2026
668cdfd
The isa claim's checks on main's tiers: host tests, T14 rows, no QEMU…
Japabu Oct 3, 2026
3451757
isa_lines: the holder stops the aux port's clock for its exchange
Japabu Oct 3, 2026
6b50eef
isa_lines: the holder's watch is armed before the keyboard is asked
Japabu Oct 3, 2026
48464e1
isa: a claim's end answers the polls on it, and the ports job watches…
Japabu Oct 3, 2026
eed8ee7
screen_fatal_behind_a_painter presses no key, and why is filed
Japabu Oct 3, 2026
88fa312
Merge origin/main (6a6c5faa5: #631) into wt/toyos-ps2
Japabu Oct 3, 2026
eea886e
i8042: a controller this kernel armed is never handed to a claim
Japabu Oct 3, 2026
cccf6a4
isa_grant, isa_lines: a claim that follows a holder asks until it is …
Japabu Oct 3, 2026
d2ee294
The bitmap's SAFETY names the hold its callers have; a closed issue a…
Japabu Oct 3, 2026
314aa61
Record the T14's isa-withheld and testcases boots at d2ee294f0
Japabu Oct 3, 2026
66798c7
issues: the deferred-release issue names isa_row's claim_after as a l…
Japabu Oct 3, 2026
b8680c9
issues: one checkout of one tree builds two kernels
Japabu Oct 3, 2026
b00d9a5
Merge origin/main (c7d26d0dd: #685) into wt/toyos-ps2
Japabu Oct 3, 2026
9389daa
issues: the two-kernels issue's exit is the empty directory's kernel
Japabu Oct 3, 2026
1ce3df4
issues: the two-kernels issue no longer says no machine loads the tables
Japabu Oct 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
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,8 @@ attempt.
![ToyOS booting on a ThinkPad T14](first-boot.jpg)

The screenshot is the laptop's own panel. The machine has no serial port, so
the kernel renders its log and its panics to the framebuffer, and pages them
with PageUp and PageDown polled straight off the keyboard controller after
every CPU has halted. It is reporting a real bug: the page cache sized an index
the kernel renders its log and its panics to the framebuffer. It is reporting a
real bug: the page cache sized an index
from the disk's block count, which fit in QEMU's test image and wanted 238 MB
on a 244 GB drive.

Expand Down
57 changes: 57 additions & 0 deletions issues/build/one-checkout-of-one-tree-builds-two-kernels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
status: open
kind: defect
opened: 2026-10-03
---

# One checkout of one tree builds two kernels

A kernel's bytes depend on what its target directory built before. Measured on
`wt/toyos-ps2`, the tree clean each time, of the x86-64 kernel with
`boot-actuators,test-actuators`, which is built from the same sources at both
heads:

- At `66798c7ed`, read back out of a staged metal image (`toyos/kernel.elf` on
slot A's volume): 3514896 bytes and sha256
`2593c71c4c86f3c03815f08afc6a89eb9832c351e99376ffb4aab7858c8f83c2` when the
build before it had one expression of `kernel/src/arch/x86_64/pio.rs`
patched, since restored; and
`d0c3cbd81729d01f20c772c08203c0bd4a4818b5f3d77d789cc4193104c4dfdd` after
eleven such builds in turn, each of a patch to one of `pio.rs`,
`toyos-userbound/src/port.rs`, `isa.rs`, `percpu.rs`, `panic_reboot.rs`,
`idt/exceptions.rs` with `paging.rs`, and `object/ops.rs`, each restored
before the next. Pull request #592 carries the patches and their order.
- At `b00d9a589`, built into two empty target directories by the cargo line
`src/build.rs` runs for it: 3514808 bytes and sha256
`cb95d0d34ac99148584083e21cbb09edc299e5a94168e8ca71a9d7ef3db8a37b` from
each, where the kernel the worktree's own `kernel/target` had last built was
still `2593c71c…`.

The empty directories' kernel and `2593c71c…` differ in `.symtab` and
`.strtab` and in no other section: 121 of 6419
symbol names, each in its `.llvm.<n>` suffix alone, ten of the 261 suffixes
the kernel carries. It is the suffix
`issues/build/two-checkouts-of-one-tree-build-different-guest-bytes.md`
measures across checkout paths; that issue's exit builds two clean checkouts
and would not see this one.

What moves a suffix is not measured. One of the eleven patches, `pio.rs`'s,
built in a once-empty directory and reversed, left that directory building the
empty one's kernel. `[profile.toyos]` builds with `incremental` on (root
`Cargo.toml`): the suspect, and no build with it off was compared.

What it costs: an image's signed header names the kernel file, symbol table
and all, so a reading taken on a machine names the bytes of one build, and the
next build of the same sources may carry others: a metal reading reaches a
later head by its bytes only where the builds that preceded the booted image
are replayed. `issues/build/toyos-builds-itself.md`'s M4 compares a guest
build against "the host build of the same commit", and of this kernel a host
has built three.

Exit: a target directory builds from a tree the kernel an empty target
directory builds from it, whatever the first built before. A gate reads it: it
builds a kernel into an empty directory and compares it with the one the
checkout's own target directory builds. What that checkout has built is its
"before", so no patch is its input, and on this worktree as it stands it is
red, `2593c71c…` against `cb95d0d3…`. A gate that builds an edit, reverses it
and compares is green on this defect, by the `pio.rs` measurement.
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ console's renderer. Exit: as stage A.
- metal `watchdog_resets`: the TCO ends the machine.
- metal `quiesce_refuses_a_second_shutdown`: the machine has one shutdown, and a second caller is
refused while the first holds it.
- metal `screen_pager_keys`: PageUp pages a halted report.
- host `screen_paged_scrollback`: a report longer than the panel pages with no input.
- host `screen_early_panel`: the panel repaints after each committed record.
- host `screen_log_absent`: a `/log` that did not mount is said on the panel.
- host `screen_blocked_dump`: Ctrl+Alt+D's summary tells the three states apart.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ their clocks, and no `METAL` row judges them.
- **Input.** A boot with no i8042 is no slower than one with it
(`i8042_absent`). The i8042 counters repeat at most once per 10 s and only
when the pin asserted (`i8042_health_cadence`), and the idle loop does not
spin on the controller (`i8042_health`'s idle trips). The fatal path's panel
holds while a key is held (`panic_key_holds`).
spin on the controller (`i8042_health`'s idle trips).
- **USB.** The connect settle ends on the device appearing and not at
`EMPTY_BUS_NS` (`xhci_slow_connect`). A disk call ends inside
`toyos_xhci::call::AFTER_BREAK`, a staged break skips its data-phase wait, the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ kernel arms the chipset's TCO only on the `watchdog` parameter
- A userland `watchdogd` feeds the watchdog on every machine, with no new
syscall; the detector is armed on every boot; nothing ships for tests alone.
- **A panic's panel holds as it does today** and feeds the watchdog while it
holds, after a key too (`panic_console::hold_the_panel`).
holds (`panic_console::hold_the_panel`).
- **`watchdogd` reaches the chipset's timer through the general port claim
#592 brings, its `isa` claim, as the ACPI server will**, and not through a
device class of its own: one way of doing it and not two (2026-10-03). That
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ anything touching the boot path.
these to be read-verified only: TCG reports every CPU feature present, so the
missing-bit path cannot run.
4. **The on-screen console. If this fails, do not flash.** Every screen test.
Confirm the muted profile actually removes the UART, and that the paging test
is driven by a timer rather than a keypress — input may be dead on the
machine. *False pass:* the late-panic gate passes with the capture routine's
Confirm the muted profile actually removes the UART. *False pass:* the late-panic gate passes with the capture routine's
body replaced by a bare return, so these cover rendering, not capture.
5. **Input, which is the milestone and which a verdict once omitted entirely.**
The 2026-08-01 verdict recorded GO over six sections and a seventeen-row
Expand Down
4 changes: 2 additions & 2 deletions issues/hardware/gop-is-not-the-path-every-boot-takes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ opened: 2026-09-03

Until `06ce633` no configuration in this tree produced a UEFI GOP at all:
`kernel/src/drivers/gop.rs` had never executed and `kernel_args.gop_framebuffer`
was zero everywhere. `cargo run --gop` and `BootOptions { profile: Profile::Gop }`
(`-vga std`) fixed that and the path works.
was zero everywhere. `cargo run --gop` (`-vga std`) fixed that and the path
works.

**The owner ruled on 2026-09-01: GOP is the floor, and the mode is the
firmware's.** The mode half has landed. This file is the other half, and it is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
status: open
kind: defect
opened: 2026-09-28
---

# The i8042's holder holds the machine's reset line

An `isa` claim on the i8042 (`kernel/src/arch/x86_64/pio.rs`'s `GRANTABLE`)
opens ports 0x60 and 0x64 to the process that binds it, through the TSS I/O
permission bitmap, and the bitmap grants a port or refuses it: it cannot see
the value written. The controller's command port takes `0xFE`, which pulses the
CPU's reset line, and `0xD1`, which writes its output port, where the same
line lives (IBM PC AT Technical Reference, the 8042's commands). So whichever
process drives the keyboard can reset the machine whenever it likes: no memory
is exposed and the kernel does not crash, but a userland bug in that one
program ends every other one without a word in the log.

Neither way out is free: filtering the command byte means the kernel decoding
the controller's protocol, a syscall or a trapped instruction per access in
place of the bitmap; keeping 0x64 in the kernel means the keyboard driver is
not wholly userland, which the owner ruled it must be.

A recorded weakness of the power broker's track
(`issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md`),
which owns it (owner ruling).

**Exit**: resetting the machine is the power broker's decision alone: the
keyboard's holder reaches the controller's reset line only through the broker,
or not at all.
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ so the native shape is smaller:
Unstaffed until the owner opens it; sequenced naturally with the userland/
product era. What must not happen meanwhile is the accident this track
exists to prevent: `POWER` spreading to more manifest rows.

Its recorded weakness: the i8042's holder resets the machine without it
(`issues/isolation/the-i8042s-holder-holds-the-machines-reset-line.md`).
10 changes: 10 additions & 0 deletions issues/kernel/deferred-release-outlives-its-syscall.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,16 @@ swap's author. Exit condition: this issue closes — the kernel publishes a
process's end only once its deferred releases have run — and `CLAIM_RETURN`
is deleted with it.

**A second loop waits the same release out.**
`tests/toyos-rust-tests/src/isa_row.rs`'s `claim_after` asks for the `isa` row
again while the claim is refused as `AlreadyExists`, for at most five seconds,
wherever `isa_grant` or `isa_lines` claims the row after a holder has exited.
No run was red without it: it rests on the `Device` release measured in this
section. Owner: the `isa` claim's author. Exit condition: the same, and
`claim_after` is deleted with `CLAIM_RETURN` — once the release is no longer
deferred, a claim refused after its holder's exit is a defect that loop would
hide for five seconds.

**Its tests are deleted**: `38a5064b6` took `handle_basic`, `handle_transfer`
and `kill_while_blocked` out, and `009db6db3` retired `SYS_DEBUG` actions 17 and
18, which only `handle_transfer` read. `02c35a85d` then moved `FILL`, which
Expand Down
2 changes: 2 additions & 0 deletions issues/kernel/every-driver-is-still-in-the-kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ What is left of the staged work:
3. Done: **the capability itself** is `DeviceType::PciFunction` plus
`SYS_DEVICE_BAR_MAP` and `SYS_DEVICE_DMA_ALLOC`, with config space readable
and unwritable and the interrupt delivered as a record on the claim.
4. **The i8042 (PS/2)**: staged as stage 7 of
`issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md`.

- **USB HID cannot move to userspace without moving the boot block device or
splitting the controller.** It shares the controller, the event ring and the
Expand Down
18 changes: 18 additions & 0 deletions issues/kernel/the-isa-port-switchs-cost-is-unmeasured.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
status: open
kind: tooling
opened: 2026-09-29
---

# The `isa` port switch's cost on the scheduler hot path is unmeasured

`arch::pio::switch_to` (`kernel/src/arch/x86_64/pio.rs`) runs on every context
switch, from `KernelHw::switch`: per `GRANTABLE` row one `BOUND` load, one
bitmap byte read, and on a change one bitmap write per port. On x86-64 that is
one row on every switch of every CPU, whether or not any process holds a claim.
Nothing has measured what it adds to a switch, and a timing verdict comes only
from metal.

**Exit**: the T14's switch cost with and without the call, from one metal run,
recorded in the commit that closes this; or the switch skips the rows entirely
while no row is bound, with the skip's cost measured the same way.
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ times:
10. **usbd**, stage 5's second half: the whole xHCI moves, HID to the
keyboard claim and mass storage over `toyos-blockring`, and the kernel
USB bridge is deleted. **What must work with no userland stays off
USB**: the panic console pages its report by itself and needs no
keyboard, and steers only from the i8042 it polls; the kernel's one
USB**: the kernel's one
hotkey, Ctrl+Alt+D (`kernel/src/keyboard.rs`, the blocked-task dump),
is recognised on the i8042's transitions and no longer on a USB
keyboard's, which from here reach the kernel only as usbd's keyboard
Expand All @@ -150,7 +149,7 @@ times:
Each step measures the kernel's lines against stage 6's first commit, and
the longest interrupts-off and preemption-off windows against the readings
step 2's exit puts in the tree, by that exit's rule.
Steps 3 and 4 do not land alone: they land with #592's i8042 stage and
Steps 3 and 4 do not land alone: they land with stage 7.2 and
with usbd.
1. **Interrupts post.** A post is legal in a handler: the watches a handler
posts, and the completions of a ring they complete into, sit behind
Expand All @@ -159,7 +158,7 @@ times:
IOMMU's refusal and both audio backends post from the handler, and
`irq_ring`'s `UserDev` and `Audio` and their arms in `drain_irqs` go.
The thread is the holder's: netd's, blockd's, soundd's mix thread, and
the `isa` claim's when #592 lands. **Exit**: `handler_post_without_a_pass`,
an `isa` claim's holder. **Exit**: `handler_post_without_a_pass`,
a vector taken on a CPU holding preemption off, inside a post of its own
watch, inside a completion into a ring polling it, or inside that ring's
own watch, posting once that section lets go and before any pass, red on
Expand All @@ -184,7 +183,7 @@ times:
second bullet). `ring_park_herd` is not that load: its walks start in
`SYS_INBOX_SUBMIT`, which runs with interrupts masked on both arms, and
it reaches no handler step 1 changed.
3. **The i8042's thread is ps2server's** (#592's i8042 stage): `irq_ring`'s
3. **The i8042's thread is ps2server's** (stage 7.2): `irq_ring`'s
`I8042`, `keyboard_controller::service` and the idle loop's
`verdict_due` go with the kernel's driver. **Exit**: that stage's.
4. **xHCI's thread is usbd's** (step 10 above): `Xhci`, `poll_if_pending`
Expand All @@ -201,6 +200,18 @@ times:
and
`issues/kernel/nothing-fails-when-a-devices-release-or-close-stops-answering-its-polls.md`
are met.
7. **The i8042 leaves the kernel.** Owner ruling, 2026-09-28: drivers are
userland, and a dead kernel takes no input, with no emergency way.
1. **The panic console takes no input, and an `isa` claim grants a process
exact ports through the TSS I/O permission bitmap and its ISA lines as
records** (`kernel/src/isa.rs`). **Done** (#592).
2. **ps2server**, the server over that claim, feeding the kernel's keyboard
and mouse streams so Ctrl+Alt+D and the merge with USB HID stay where
they are; the kernel's driver, its vector, its actuators and the
`keyboard_controller` seam deleted. A keyboard claim is refused while no
source exists, which init's order of endowment then decides. **Exit**:
no i8042 code in the kernel, and typing resumes after ps2server is killed
and restarted.

## Standing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ with no fallback by design (`kernel/src/drivers/acpi.rs:277-283`). Where the
table named none, `arm` returns `Bound::Held`
(`kernel/src/panic_reboot.rs:134-145`) and `hold_the_panel` loops
`while bound.is_armed()` (`kernel/src/drivers/panic_console/mod.rs:647-650`),
which never ends. A keypress also retires the bound, which is right for a
machine with somebody in front of it and is exactly wrong for one running
unattended.
which never ends.

**On the T14 that last bound is the one thing already known not to work.**
`issues/hardware/an-armed-tco-has-never-reset-the-t14.md` records that no claim
Expand Down Expand Up @@ -61,5 +59,5 @@ prints it.

**Exit condition**: a boot that takes a fatal event on the T14 with nobody in
front of it either ends itself and leaves a record naming the fault, or the run
shows which of `Bound::Held` and the retired-by-a-keypress path held it — read
off the machine, not argued from the tree.
shows that `Bound::Held` held it — read off the machine, not argued from the
tree.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
status: open
kind: defect
opened: 2026-10-03
---

# A fatal path entered outside a panic holds the panel with interrupts open

`panic::halt_all_cpus` says the machine holds its report "with interrupts
masked" and masks nothing itself: the panic handler and the exception entries
mask before they reach it. Two callers do not, both in the test kernel alone:
the `panel-painter-stalls` actuator, from a scheduler pass
(`kernel/src/drivers/panic_console/mod.rs`'s `stall`), and `SYS_DEBUG`'s
`FATAL_HALT` (`kernel/src/syscall/dispatch.rs`). The CPU that then holds the
panel spins on the reset bound with `IF` set, and every device handler pinned
to it still runs on a kernel that has declared itself dead.

**Evidence**: `screen_fatal_behind_a_painter` on `Profile::Metal` with two
CPUs, QEMU's `info registers -a` read once the report is on the panel: in six
boots of six the spinning CPU's `RFL` has bit 9 set (`0x293`, `0x287`, `0x297`)
and the halted one's has it clear. With `hold_the_panel` patched to poll port
0x60 and a key pressed inside the bound, six boots: the patched poll read the
key in four, each with the panel's CPU cpu1, and never saw it in two. The one
of those two whose console was kept had the panel on cpu0, where the i8042's
handler is pinned.

So that test stages a fatal path no shipping kernel takes. Not measured: that
the handler read the byte in the two boots the poll missed it; the open `IF`
on the handler's own CPU is what would let it.

**Exit**: `halt_all_cpus` masks interrupts itself, or its two callers outside
a fault do, and the same reading shows `IF` clear on the CPU holding the panel.

This file was deleted.

3 changes: 1 addition & 2 deletions issues/panic-path/no-console-between-boot-and-terminal.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ it by saying where the log will be, and cannot put a line in it.
(`kernel/src/drivers/panic_console/mod.rs:639`), and a compositor claiming the
framebuffer sets it. So on `bootable.img` the last kernel screenful ever painted
is the one at `Boot: complete`, the desktop overwrites it a few tens of
milliseconds later, and no key pauses it: `page_forever` is reached only from
`halt_all_cpus`, so a *successful* boot never pages.
milliseconds later, and no key pauses it.

**The durable answer landed and is not this.** "A log sink that survives
userland" is `/system/bin/logd`: the kernel keeps the record ring and the console and
Expand Down
Loading
Loading