Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
658fba5
A child's handles are a list its parent names: labels and namespaces …
Japabu Nov 11, 2026
d6b2b30
issues: the records this change completes name #1252
Japabu Nov 11, 2026
b9beddf
sdk: the early lookup's test calls the walk the lookup makes
Japabu Nov 11, 2026
5484de4
sdk: with_prefixed's bound is its buffer
Japabu Nov 11, 2026
1e2723d
Comments name the services and handles the tree has
Japabu Nov 11, 2026
f33dae2
Guest tests compile against the connector API
Japabu Nov 11, 2026
1e40cf9
shell: an interrupt that comes while a -c shell starts its child reac…
Japabu Nov 11, 2026
e06195c
issues: a -c shell cannot tell a child its quit asked from one that l…
Japabu Nov 11, 2026
6d609c8
shell: Asked has a Default beside its const new
Japabu Nov 11, 2026
b175ae1
kernel: SYS_SYSINFO charges its answer to the caller's job while it c…
Japabu Nov 11, 2026
499e340
supervisor: a provided connector reaches only a row that receives its…
Japabu Nov 11, 2026
3cec476
Four texts still described a namespace
Japabu Nov 11, 2026
8e7f862
A malformed table says which, and adopted_services_stay says why it i…
Japabu Nov 11, 2026
576338e
tests: three image comments say services where they said namespace
Japabu Nov 11, 2026
627580c
soundserver: a policy number's comment names one the kernel still has
Japabu Nov 11, 2026
51e4a84
issues: what #1252 owes on metal while the benches are down
Japabu Nov 11, 2026
ed68af9
Review r2 of #1252: the last namespace texts, and two inexact ones
Japabu Nov 11, 2026
f3b0396
kernel: SYS_SYSINFO charges a roster, never the header alone
Japabu Nov 11, 2026
d9339fd
issues: a file server whose pager is refused for memory panics, blami…
Japabu Nov 11, 2026
d3d4000
issues: kernel_objects_refused takes every frame while its own line m…
Japabu Nov 11, 2026
3667db7
Review r3 of #1252: a header alone is never refused, and ps names bot…
Japabu Nov 11, 2026
135fcb4
issues: kernel_objects_refused's control at main passed
Japabu Nov 11, 2026
19efa90
issues: the members #1252 adapted and only compiled are owed on metal
Japabu Nov 12, 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
7 changes: 7 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ members = [
"system/hda/driver",
"system/session",
"system/shell",
"system/shell/copies",
"system/soundserver",
"system/soundserver/mixer",
"system/soundserver/output",
Expand Down
8 changes: 4 additions & 4 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ struct ProgramConfig {
/// hands the connector down to its own children. The supervisor creates nothing and
/// holds nothing for these — `surface` is the whole of this kind.
provides: Vec<String>,
/// Names in this program's namespace, each a *connector*.
/// The services this program is given, each a *connector*.
receives: Vec<String>,
/// Claims the supervisor mints for this row's one process and endows
/// (`toyos_manifest::Program::devices`).
Expand Down Expand Up @@ -760,7 +760,7 @@ fn held_by_their_holders_alone(config: &SystemConfig) -> Result<(), String> {
return Err(format!("`{name}` asks for `slots` and is in `[boot] start`, and the slots are granted to a launch alone"));
}
// A row any login could start would hand every login what it holds,
// and so would a login authority, whose namespace reaches every
// and so would a login authority, whose services reach every
// program a login runs directly: an authorization that changes a
// disk is the image's to grant, to a row that is neither.
for word in &program.authorize {
Expand Down Expand Up @@ -1155,7 +1155,7 @@ fn symlink_target_name(to: &str) -> &str {
}

/// The converse of the crate assertion above: a `bin/` entry no name reaches.
/// A name buys authority — the supervisor builds a `[programs]` row's namespace and
/// A name buys authority — the supervisor gives a `[programs]` row its services and
/// device claims — and a harness binary has none, holding only what its spawner
/// moved in, so it is legal exactly when the config starts something that could
/// spawn it. **An inventory over the `bin/` namespace, not a reachability
Expand Down Expand Up @@ -1183,7 +1183,7 @@ fn unnamed_program(
}
return Err(format!(
"the image carries {name} and no `[programs]` row names it, so the supervisor can build \
it no namespace and no device claim; add a row or take the file out"
it no service and no device claim; add a row or take the file out"
));
}
Ok(())
Expand Down
40 changes: 27 additions & 13 deletions docs/src/architecture/authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
nothing.
- Every system call states the right it needs on each handle it takes.
- Nothing else grants authority: process and thread ids are identities, object
ids for diagnostics reach nothing, and a service name means something only
inside a namespace someone handed you.
ids for diagnostics reach nothing, and a name means something only in the
process whose parent wrote it.

## Rights only narrow

Expand All @@ -37,7 +37,7 @@
## Kernel objects

- A closed set of kinds, among them pipes, connections, service ports,
namespaces, shared memory, paged memory supplied by a userland pager, events,
shared memory, paged memory supplied by a userland pager, events,
inboxes for asynchronous requests, processes, jobs, device claims and the
system capability.
- An object crosses a process boundary in exactly two ways: in a message over a
Expand All @@ -61,9 +61,13 @@

## Creating a process

- A child starts by spawn, never by fork, with an empty handle table.
- It receives exactly one set of endowments, moved out of the parent, all or
nothing (see [The program interface](../using/interface.md)).
- A child starts by spawn, never by fork. Its table starts with its handle to
itself, its notice, then exactly one list of endowments moved out of the
parent, all or nothing, in the order the spawn listed them
(see [The program interface](../using/interface.md)).
- The kernel keeps no name for any handle. What a parent calls each endowment
is bytes it writes into the child's memory, and the child's SDK checks them
once before it looks one up.
- The parent receives a handle to the child's process, with which it waits for
the child's end and can stop it.
- Without any handle a process can act only on itself and read machine facts:
Expand Down Expand Up @@ -91,17 +95,27 @@

## The system capability

- One per machine, held by the supervisor.
- One per machine, held by the supervisor, which the kernel starts holding it
and the images it boots from at handles the interface states, since no
parent names them.
- Every privileged right, such as claiming a device, real-time scheduling,
reading the log, reading counters, listing processes or powering off, is a
narrowed copy the supervisor hands to the programs its manifest grants.

## Namespaces

- A namespace is an immutable kernel object mapping service names to
connectors; a narrower one is a new object.
- A process connects to a service only by looking its name up in a namespace it
holds. There is no global registry.
## Services

- A service is a port. Its server holds the acceptor; a client holds a
connector and connects through it, which takes the right to write on the
connector. A service one program provides to a launch, such as a terminal's
surface, reaches the launched program only where its row receives that
service.
- A process finds a service only among the connectors its parent gave it,
by the name its parent wrote. There is no global registry and no connect by
name.
- A helper a program spawns is given a copy of every service connector its
parent holds, unless the spawn names fewer; a launch is given its row's.
What a process gives itself, as the supervisor does for its own files, no
child inherits.

## Files

Expand Down
7 changes: 4 additions & 3 deletions docs/src/architecture/kernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ The kernel is small, fast and safe, and does what userland cannot:
It holds no filesystem, no storage, input, network, audio or USB driver, no
network protocol, no audio mixing, no login and no naming policy, and parses
nothing one program writes for another. What a parent tells the child it
starts, its arguments and environment, is memory the parent lays out in the
child: the kernel keeps none of it. It knows a process by a short name its
parent gives it, a label that carries no authority. The firmware's AML is
starts, its arguments, its environment and what it calls each handle it
gives, is memory the parent lays out in the child: the kernel keeps none of
it. It knows a process by a short name its parent gives it, a label that
carries no authority. The firmware's AML is
interpreted by a userland ACPI service, which tells the kernel the little it
needs, such as how to power off.

Expand Down
24 changes: 15 additions & 9 deletions docs/src/using/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ boundary: protocols between programs define their own.
## The native SDK

The SDK is the Rust interface to ToyOS: typed handles and rights, endowments a
program was started with, namespaces and service connections, framed messages,
program was started with and what its parent calls each, service connections, framed messages,
pollers, shared memory, files through the program's view, spawning and
launching, device claims for drivers, logging, and windows for programs that
draw. Each service's protocol is a library of its own that owns its message
Expand All @@ -59,21 +59,27 @@ userland library over the SDK.
## How a program starts

```text
endowments ──> standard streams (descriptors 0, 1, 2 and those named)
──> a namespace of services it may connect to
──> directory capabilities: its view
──> anything else its row or its parent gave it
handles ──> itself and its notice, first
──> its endowments, in the order its spawn listed them:
standard streams (descriptors 0, 1, 2 and those named),
connectors to the services it may connect to,
directory capabilities: its view,
anything else its row or its parent gave it

its memory ──> its program, in the ranges its parent laid out
──> a startup block below it: its arguments and its
environment (HOME, the starting directory, ...)
──> a startup block below it: what its parent calls each
endowment, its arguments and its environment
(HOME, the starting directory, ...)
```

A parent reads the child's program and lays out the child's memory, each
range the pages of a memory object or a private copy of them. What it tells
the child goes in the startup block, which the kernel copies and never reads;
the SDK, std and libc read it where it lies. A child whose parent wrote none
starts with no argument and an empty environment.
starts with no argument, an empty environment and no name for anything it
holds. The names are the one part of the block the child checks: one that is
no list of distinct names ends the child before it looks one up, with the
reason on its standard error where the list still names one.

A program holds nothing it was not given. It asks for more only by connecting
to a service in its namespace, whose server decides.
to a service it was given, whose server decides.
2 changes: 1 addition & 1 deletion docs/src/using/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ starting authority from it and from nothing else, and the build refuses a
manifest that contradicts itself, such as two programs claiming one device.

```text
manifest row ──> supervisor ──> spawn with: namespace (services it receives)
manifest row ──> supervisor ──> spawn with: connectors (services it receives)
acceptors (services it serves)
view (directories)
device claims
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
status: open
kind: defect
opened: 2026-11-11
---

# A `-c` shell cannot tell a child its quit asked from one that landed after it

A quit of a `-c` shell asks or ends the children there. A child that lands
after it holds the reason unread, or none if the shell had read it, and that
quit does not ask it (`kernel/proclife/src/quit.rs`). So the shell asks each
child it starts once an interrupt has reached it, right after that child's
spawn (`system/shell/src/quit.rs`, `Asked::landed`).

When the interrupt and the landing both fall within that one spawn, no step
of the shell's tells which came first. A child that listens between its
landing and the shell's look, and has already been asked by the walk or read
the inherited reason, is asked a second time. It is ended if it has not read
the first. `shell-copies`'s model shows exactly those orders. A child that
never listens, such as `cat`, is not affected: it ends in every order.

Exit: the kernel either tells the spawner whether the child landed holding a
reason its parent had not read, so the shell asks only a child nothing asked,
or asks a child that lands under an asked parent itself. Either changes the
quit's rule, which is the kernel's.
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ a signal an event raises (`sdk/libc/src/sigreq.rs`).
session's `logout` acts on every session. An owner's end other than its
sign-out's is a failure, and a login authority whose sessions failed more
than the restart budget's three times in ten seconds is refused its next
open; no other open is counted. Its namespace is
open; no other open is counted. What it holds is
`issues/a-user-is-a-home-tree-and-a-login-row.md`'s login row; the SSH
session's shell holds no host key and no SSH service authority.
*Exit*: ending the desktop's session owner ends every program of that
Expand Down Expand Up @@ -173,7 +173,7 @@ a signal an event raises (`sdk/libc/src/sigreq.rs`).
as the kill does, and the reason is `toyos_abi::quit::Reason`:
interrupt, hang-up or terminate. A quit reaches the process's subtree.
Each process is started holding its notice, the object kind `Notice`
under `QUIT_LABEL` (`quit`), `READ` and `WAIT` alone, readable while a
at `RawHandle::NOTICE`, `READ` and `WAIT` alone, readable while a
reason is asked and not yet read, whose read takes it and an empty read
takes nothing. A process listens from its first read of its notice or
the first readable watch armed on it. A quit kills a process that never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ opened: 2026-10-20
(`sys_device_dma_map`, `kernel/src/syscall/device.rs`), so a handle of another
kind is `HandleError::WrongType`, which ends the caller, exit 139
(`process::handle_fault`). `HandleTable::get_sent` answers `InvalidArgument`
for it instead, and is what `SYS_SPAWN` and `SYS_NAMESPACE_BUILD` take a
for it instead, and is what `SYS_SPAWN` and `SYS_CONNECT` take a
handle a peer sent with (`kernel/src/object/handle.rs`).

The region a holder lends is a peer's by contract: `toyos_pci_claim::lend` maps
Expand All @@ -27,11 +27,11 @@ as a region before the session lends it (`Sessions::open`,

The kernel owns the fix rather than each lender: what a holder lends is a
peer's by `lend`'s contract, and the kernel already answers a peer's handle of
the wrong kind `InvalidArgument` at `SYS_SPAWN` and `SYS_NAMESPACE_BUILD`; a
the wrong kind `InvalidArgument` at `SYS_SPAWN` and `SYS_CONNECT`; a
check before every lend would repeat that in each driver.

Owner: the kernel's device calls (`kernel/src/syscall/device.rs`).

**Exit**: `SYS_DEVICE_DMA_MAP` takes its region through `get_sent`, and
`HandleError::WrongType`'s comment names it beside `SYS_SPAWN` and
`SYS_NAMESPACE_BUILD`.
`SYS_CONNECT`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
status: open
kind: defect
opened: 2026-11-11
---

# A file server whose pager is refused for memory panics, blaming its row

`pager` (`system/fileserver/src/main.rs`) panics whenever
`toyos::paged::Pager::create` is refused, saying "its row is no pager row".
Under memory exhaustion the refusal is `ResourceExhausted`. That is an
expected condition, not a manifest error, so the message is false, and the
server ends instead of reporting it.

Seen in guest run 43092179151 (#1252 at 041f1b81e), `kernel_objects_refused_alone`.
While the test held every frame, the Log file server (pid 9) ended. Each of
the supervisor's next three restarts went the same way:

- it said `fileserver: diskserver would not open the partition: Kernel(ResourceExhausted)`;
- it said `fileserver: Log serving /log — absent`;
- it panicked at `main.rs:290` with
`fileserver: the Log server makes no pager (ResourceExhausted); its row is no pager row`.

The supervisor then closed the role for the rest of the boot:
`supervisor: fileserver log ended 4 times in 10 s; its ports are closed, its
clients answered Gone, and a program started from now on is given none of
its directories`. Main has the same code (e10b6fd49).

Owner: the file server, with the supervisor's restart budget.

Exit: a refused pager is no panic. The file server reports what the kernel
answered, and a role refused its pager for memory ends with a status that the
supervisor reads as want of memory, as it reads a start refused for memory.
A host test of the refusal holds this.

This file was deleted.

2 changes: 1 addition & 1 deletion issues/desktop-window-child-freeze.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ manifest does not carry with nothing.

**The endowment travels with the spawn, and that closed it.**
`tests/desktopcase/system.toml`'s `[programs.shell]` receives `compositor`, and
a child the shell spawns directly inherits the shell's namespace — so the client
a child the shell spawns directly inherits the shell's services — so the client
gets its window from the process that started it, which is the whole of "a
process holds exactly what its parent moved into it". Every probe this test was
written for now runs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ opened: 2026-09-29
`run_one` endows each job it spawns a `SysCap::duplicate` of test-runner's own
capability (`tests/guest/test-runner/src/main.rs`), and a duplicate carries
every right the original does (`sdk/toyos/src/syscap.rs`). The job also
inherits test-runner's whole namespace. On `tests/images/testcases.toml` the
inherits every service test-runner holds. On `tests/images/testcases.toml` the
row grants `device`, `dup`, `logread`, `power`, `roster`, `counters`, `trace`
and `inventory`, so every test binary may mint a device claim, read every
kernel record, reset or power off the machine, list every process, and hand
Expand Down
5 changes: 2 additions & 3 deletions issues/every-program-sees-only-the-files-it-was-given.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ other, with the same per-session isolation (owner, 2026-11-05).
directory where it keeps state (`service = true` or `state = true`: the
daemons' own state is built); `/system` is read-only, `/log` and `/apps`
are read-only to all but one row each, and the rest is read-write. The
storage rows are started outside that
(`issues/storage-rows-start-holding-the-supervisors-whole-tree.md`),
which this stage's exit closes.
storage rows hold no directory at all (#1252): a service the
supervisor adopted for its own files is inherited by no child.
Only the installer service writes `/apps` (owner ruling, 2026-11-05).
Built: `/apps` is read-only in every declared row's view but the row
that declares `installs = true` (`toyos_manifest::Program::installs`),
Expand Down
Loading
Loading