SchOS/docs/Website/index.html
Nexoniarz c9790df04c site, branding: skeuomorphic marks, and the new Niveus components
The marks are now drawn the way Niveus draws its keys: one light from the
upper left, gloss on the faces that catch it, a specular line on the edges
that face it, and soft contact shadows.

- Shift: shaded slabs, each casting onto the one below. shift-mask.svg is
  untouched, so the kernel's logo.h coverage mask is unchanged.
- Uberblock: bevelled slots in a groove; the newest slot and the root glow.
- USB stick: moulded body, steel connector, a lit activity LED.
- Pride flag: cloth folds and a hem over the flag's own colours.

The pages use the components the new Niveus added: both terminals are
.nv-window frames, the origin and first-boot sequences are .nv-steps, the
numbers are a .nv-stat-group, and each feature card has an .nv-tile glyph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-23 15:17:34 +02:00

694 lines
33 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SchOS — a 64-bit operating system written from scratch</title>
<meta name="description" content="SchOS is a from-scratch x86-64 operating system: the SchIFT kernel, the SchFS copy-on-write filesystem, a UEFI loader, and a userland that runs unmodified musl and toybox.">
<link rel="icon" href="Assets/shift.svg" type="image/svg+xml">
<!-- Niveus, and its optional continuity helpers. -->
<link rel="stylesheet" href="niveus/dist/niveus.css">
<script src="niveus/niveus/niveus.js" defer></script>
<!-- This site's own layout. No colours, no shadows, no type sizes. -->
<link rel="stylesheet" href="app.css">
<script>
/* Before first paint, so the page never renders in one appearance and then
corrects itself. Dark is the default because the OS is dark; the toggle
is real, and what it chooses is remembered. */
try {
var saved = localStorage.getItem("schos-theme");
if (saved === "system") document.documentElement.removeAttribute("data-theme");
else if (saved) document.documentElement.setAttribute("data-theme", saved);
} catch (e) { /* storage unavailable — keep the default */ }
</script>
<!-- The whole identity, and it is not a design decision: SCH_ACCENT, copied
from include/gfx/theme.h. A site describing an operating system should look
like the operating system. -->
<style>
:root { --nv-brand: #7C5CFF; }
</style>
</head>
<body>
<nav class="nv-nav" id="topnav" aria-label="Main" style="--nv-selection-name: nv-schos-nav">
<a class="nv-nav__brand" href="#top">
<img class="nv-nav__icon" src="Assets/shift.svg" alt="">
SchOS
</a>
<ul class="nv-nav__list">
<li><a class="nv-nav__item" href="#origin">Origin</a></li>
<li><a class="nv-nav__item" href="#stack">The stack</a></li>
<li><a class="nv-nav__item" href="#what">What it has</a></li>
<li><a class="nv-nav__item" href="#hybrid">Hybrid</a></li>
<li><a class="nv-nav__item" href="#numbers">Numbers</a></li>
</ul>
<span class="nv-nav__spacer"></span>
<a class="pride" href="#pride-note"
title="SchOS stands with the LGBTQIAP+ community — every month of the year">
<img src="Assets/pride.svg" alt="Progress Pride flag">
</a>
<div class="nv-button-group appearance" role="group" aria-label="Appearance">
<button class="nv-button nv-button--sm" data-nv-theme="light" aria-pressed="false">Light</button>
<button class="nv-button nv-button--sm" data-nv-theme="dark" aria-pressed="true">Dark</button>
<button class="nv-button nv-button--sm" data-nv-theme="system" aria-pressed="false">Auto</button>
</div>
<a class="nv-button nv-button--sm" href="docs.html">Docs</a>
<a class="nv-button nv-button--sm nv-button--primary" href="download.html">Download</a>
</nav>
<main id="top">
<!-- ====================================================================== -->
<header class="shell hero">
<div class="hero__copy">
<span class="nv-badge nv-badge--accent">
<span class="nv-badge__dot"></span>
SchIFT 0.1.0 · boots on real hardware
</span>
<h1 class="nv-display hero__title">
<img class="hero__mark" src="Assets/shift.svg" alt="">SchOS
</h1>
<p class="nv-prose">
A 64-bit operating system written from scratch — its own kernel, its own
filesystem, its own bootloader. It boots on UEFI, drives real hardware,
and runs unmodified <code class="nv-code">musl</code> and
<code class="nv-code">toybox</code> on top.
</p>
<div class="nv-cluster">
<a class="nv-button nv-button--primary nv-button--lg" href="download.html">Download it</a>
<a class="nv-button nv-button--lg" href="#what">What it has</a>
</div>
<p class="nv-caption">GPL-2.0-or-later · runs from RAM · writes nothing to your disks</p>
</div>
<div class="nv-window console" aria-label="Boot log">
<div class="nv-window__titlebar">
<span class="nv-window__controls" aria-hidden="true">
<span class="nv-window__control nv-window__control--close"></span>
<span class="nv-window__control nv-window__control--minimize"></span>
<span class="nv-window__control nv-window__control--zoom"></span>
</span>
<span class="nv-window__title">SchIFT — ttyS0</span>
<span class="nv-window__actions">
<span class="nv-badge nv-badge--success"><span class="nv-badge__dot"></span>live</span>
</span>
</div>
<pre class="nv-window__body nv-code console__log" id="bootlog" aria-live="polite"></pre>
</div>
</header>
<!-- ====================================================================== -->
<section id="origin" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Origin</p>
<h2 class="nv-heading">It started as a teaching kernel and stopped being one</h2>
<p class="nv-prose nv-text-secondary">
SchOS began as <a href="https://github.com/mit-pdos/xv6-public">xv6</a>, MIT's
teaching operating system: 32-bit, single core, one filesystem, a few dozen
syscalls. Almost none of that survives. What follows is what replaced it.
</p>
</div>
<!-- A timeline, not a grid: these happened in this order, and the order is
the point. The rail is what carries that; the labels are its steps. -->
<ol class="nv-steps nv-steps--vertical origin">
<li class="nv-steps__item" data-state="done">
<span class="nv-steps__marker">1</span>
<div class="nv-steps__body">
<span class="nv-overline nv-text-tertiary">First</span>
<h3 class="nv-steps__title">64-bit, and more than one core</h3>
<p class="nv-steps__text">
Four-level paging, a real SMP bring-up, per-CPU state and a trap path
that survives both. This is the part that invalidates most of what a
32-bit uniprocessor kernel assumes.
</p>
</div>
</li>
<li class="nv-steps__item" data-state="done">
<span class="nv-steps__marker">2</span>
<div class="nv-steps__body">
<span class="nv-overline nv-text-tertiary">Then</span>
<h3 class="nv-steps__title">Its own filesystem</h3>
<p class="nv-steps__text">
xv6's log-structured filesystem was replaced by <b>SchFS</b>: a
copy-on-write B-tree with an uberblock ring, extents and checksummed
metadata. A crash leaves either the old tree or the new one.
</p>
</div>
</li>
<li class="nv-steps__item" data-state="done">
<span class="nv-steps__marker">3</span>
<div class="nv-steps__body">
<span class="nv-overline nv-text-tertiary">Then</span>
<h3 class="nv-steps__title">A Linux-shaped ABI</h3>
<p class="nv-steps__text">
The syscall table adopted Linux numbering, which is what makes an
unmodified musl and an unmodified toybox run. The table is one
<code class="nv-code">.inc</code> file, and it is the seam the whole
system is built around.
</p>
</div>
</li>
<li class="nv-steps__item" data-state="done">
<span class="nv-steps__marker">4</span>
<div class="nv-steps__body">
<span class="nv-overline nv-text-tertiary">Then</span>
<h3 class="nv-steps__title">Hardware, not emulation</h3>
<p class="nv-steps__text">
A UEFI loader, xHCI and USB storage, an e1000 with a real TCP/IP stack,
virtio-gpu and VBE framebuffers, and a device model where a driver never
names its consumer.
</p>
</div>
</li>
<li class="nv-steps__item" aria-current="step">
<span class="nv-steps__marker">5</span>
<div class="nv-steps__body">
<span class="nv-overline nv-text-tertiary">Now</span>
<h3 class="nv-steps__title">Drivers that are not in the kernel</h3>
<p class="nv-steps__text">
A process can be handed a PCI device — its registers, its memory, its
interrupts — and drive it. The GPU driver already runs that way. Nobody
writes a driver for every device that exists; the answer is to stop
requiring that they live inside.
</p>
</div>
</li>
</ol>
</section>
<!-- ====================================================================== -->
<section id="stack" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Architecture</p>
<h2 class="nv-heading">Three seams hold the whole thing together</h2>
<p class="nv-prose nv-text-secondary">
Above the syscall table, software is ordinary and portable. Below the device
model, a driver never names its consumer and a consumer never names a driver.
And at <code class="nv-code">/dev/pci</code>, a driver stops needing to be in
the kernel at all. Everything else is arrangement.
</p>
</div>
<div class="nv-card nv-card--flush stack">
<div class="stack__layer">
<span class="nv-label stack__name">userland</span>
<span class="nv-body nv-text-secondary">toybox, mksh, zsh, musl, and the first-party programs in <code class="nv-code">cmd/</code></span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">userspace drivers</span>
<span class="nv-body nv-text-secondary"><code class="nv-code">vgpud</code> — a driver that is an ordinary process</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">schinit</span>
<span class="nv-body nv-text-secondary">PID 1 — job manifests, supervision, reincarnation</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">syscall table<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">Linux numbering, one <code class="nv-code">.inc</code> file — the ABI seam</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">kernel services</span>
<span class="nv-body nv-text-secondary">VFS, sockets and <code class="nv-code">SCM_RIGHTS</code>, signals, mmap, poll, procfs</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">subsystems</span>
<span class="nv-body nv-text-secondary">SchFS, lwIP, virtual terminals, graphics, the buffer cache</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">device model<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">class vtables and bus binding — the driver seam</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">/dev/pci<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">registers, DMA and interrupts to a process — the eviction seam</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">drivers</span>
<span class="nv-body nv-text-secondary">xHCI, e1000, virtio-gpu, VBE, IDE, PS/2</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">SchIFT core</span>
<span class="nv-body nv-text-secondary">scheduler, paging, traps, IRQ, SMP, DMA</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">boot</span>
<span class="nv-body nv-text-secondary">the UEFI loader in <code class="nv-code">boot/uefi</code></span>
</div>
</div>
<p class="nv-body nv-text-tertiary section__note">
<code class="nv-code">uname -s</code> reports <b>SchIFT</b> — the kernel — the
way every Unix reports its kernel rather than its distribution.
</p>
</section>
<!-- ====================================================================== -->
<section id="what" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">What it has</p>
<h2 class="nv-heading">Built and running, and honest about the rest</h2>
<p class="nv-prose nv-text-secondary">
Every card marked <b>runs</b> is in the tree and works today. The tags are
not aspirational; the things that are not finished say so.
</p>
</div>
<!-- A rail rather than a grid. Eleven cards stacked into a wall is a list
you skim and stop reading; a row you move through is one you go along.
The section is a survey, not a comparison -- nothing here needs to be
read beside anything else, which is the test for whether a grid was
carrying information or just filling space. -->
<div class="nv-scroller-frame" data-nv-scroller>
<div class="nv-scroller features">
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><img src="Assets/uberblock.svg" alt=""></span>SchFS</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Copy-on-write B-tree, a 128-slot uberblock ring, extents with refcounts
and reflink, CRC32c on metadata, and free space derived from the tree
rather than stored beside it — so there is no second structure to
disagree with the first. There is nothing to repair after a crash.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4"/></svg></span>SMP x86-64 kernel</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Four-level paging, multiple cores, preemptive scheduling, a calibrated
LAPIC timer, real signal delivery and job control. 207 syscalls on
Linux numbering.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3.5 3 14.5 0 18M12 3c-3 3.5-3 14.5 0 18"/></svg></span>Networking</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
An e1000 driver under lwIP, with sockets for AF_INET, AF_UNIX and
AF_NETLINK. DHCP brings the interface up at boot;
<code class="nv-code">ping</code> reaches the outside world.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v8"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></span>UEFI boot</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
A PE/COFF loader built with clang and lld-link that sets up its own page
tables and hands the kernel a framebuffer. No BIOS path, no chainloading.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 21V4M12 4l-2.5 3M12 4l2.5 3M12 16l-5-3V10M12 14l5-3V9"/><circle cx="7" cy="9" r="1.5"/><rect x="15.5" y="7" width="3" height="3"/></svg></span>USB</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
xHCI, hubs, HID and mass storage — a keyboard and a USB disk that the
kernel can mount, through the same device model as everything else.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M12 15h5"/></svg></span>Virtual terminals</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Six of them, each with its own cell grid, scrollback and foreground
job — switched with <code class="nv-code">AltGr+F1</code>…<code class="nv-code">F6</code>,
which is the one chord a Linux host does not take for itself. The console
draws to whichever framebuffer is present, from the kernel's first line.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="5" r="2"/><circle cx="6" cy="19" r="2"/><circle cx="18" cy="19" r="2"/><path d="M12 7v5M12 12l-6 5M12 12l6 5"/></svg></span>schinit</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
PID 1 does almost nothing: it forks a supervisor, spawns jobs on its
behalf, and reaps. The supervisor holds the manifests and the respawn
policy, and if it dies PID 1 replaces it and hands back the children it
was already watching. PID 1 can re-exec itself without dropping them.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l8 4.5v9L12 21l-8-4.5v-9z"/><path d="M4 7.5l8 4.5 8-4.5M12 12v9"/></svg></span>A real userland</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
musl and toybox, both unmodified, plus mksh as <code class="nv-code">/bin/sh</code>.
<b>fastfetch</b> builds from upstream source with an empty
<code class="nv-code">patches/</code> directory — when it could not detect
something, the answer was to give the kernel what it was looking for.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="7" width="10" height="10" rx="1.5"/><path d="M6 4v3M10 4v3M6 17v3M10 17v3M16 12h5M18.5 9.5L21 12l-2.5 2.5"/></svg></span>Drivers outside the kernel</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">/dev/pci</code> hands a process a device: its
registers by <code class="nv-code">mmap</code>, physically contiguous
memory it can point the device at, and interrupts as something to
<code class="nv-code">read()</code>. The virtio-gpu driver already lives
out there.
</div>
<div class="nv-card__footer nv-card__footer--plain">
<a class="nv-button nv-button--ghost nv-button--sm" href="#hybrid">How that works →</a>
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm" style="--nv-tile-tint: var(--nv-color-warning)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="13" height="10" rx="1.5"/><rect x="8" y="10" width="13" height="10" rx="1.5"/></svg></span>Schcom</h3>
<span class="nv-badge nv-badge--warning">in progress</span>
</div>
<div class="nv-card__body nv-text-secondary">
The compositor that will own the display. v0 runs, and descriptor
passing — the one thing a Wayland client cannot do without — now
exists. What a buffer still needs is a shareable memory object.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><span class="nv-tile nv-tile--sm" style="--nv-tile-tint: var(--nv-color-text-tertiary)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 4c-2 0-3 1-3 3v2c0 1.5-1 3-2 3 1 0 2 1.5 2 3v2c0 2 1 3 3 3M16 4c2 0 3 1 3 3v2c0 1.5 1 3 2 3-1 0-2 1.5-2 3v2c0 2-1 3-3 3"/></svg></span>SchAPI</h3>
<span class="nv-badge">designed</span>
</div>
<div class="nv-card__body nv-text-secondary">
The native programming interface — specified, not built, and deliberately
so. It should be designed <i>from</i> the compositor's experience rather
than before it.
</div>
</article>
</div>
<button class="nv-button nv-button--icon nv-button--float" data-nv-scroll="prev" aria-label="Previous">
<svg class="nv-button__icon" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M14 6l-6 6 6 6" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button class="nv-button nv-button--icon nv-button--float" data-nv-scroll="next" aria-label="Next">
<svg class="nv-button__icon" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M10 6l6 6-6 6" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</section>
<!-- ====================================================================== -->
<section id="hybrid" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Hybrid</p>
<h2 class="nv-heading">A driver can leave the kernel</h2>
<p class="nv-prose nv-text-secondary">
Nobody writes a driver for every device that exists — not a project this
size, and not any project. So the interesting question is not how to write
more of them, but what a driver actually needs from a kernel, and whether it
can have that from outside.
</p>
</div>
<div class="needs">
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">Its registers</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">mmap</code> on <code class="nv-code">/dev/pci</code>,
where the offset is the physical address of a BAR. The kernel refuses any
offset that is not inside a BAR of a device this process was given, which
is what stops it being <code class="nv-code">/dev/mem</code> with extra steps.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">Memory the device can reach</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
Physically contiguous, and the process is told the physical address —
which is the whole reason it cannot do this for itself. The arena is
reserved at boot, before the general allocator gets anything.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">To be told when to look</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
Interrupts arrive by <code class="nv-code">read()</code>, so they compose
with <code class="nv-code">poll</code>. The kernel masks the line and
leaves it masked until the driver writes back — because a PCI interrupt is
level-triggered, and nobody but the driver knows how to clear it at the device.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">A descriptor to arrive</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">sendmsg</code> with <code class="nv-code">SCM_RIGHTS</code>.
Handing a process the device it is allowed to touch and handing a
compositor a buffer turned out to be the same act, which is why one
primitive answered both.
</div>
</article>
</div>
<div class="nv-window console" aria-label="Evicting the GPU driver to userspace">
<div class="nv-window__titlebar">
<span class="nv-window__controls" aria-hidden="true">
<span class="nv-window__control nv-window__control--close"></span>
<span class="nv-window__control nv-window__control--minimize"></span>
<span class="nv-window__control nv-window__control--zoom"></span>
</span>
<span class="nv-window__title">vgpud — tty1</span>
</div>
<pre class="nv-window__body nv-code console__log"><span class="nv-text-tertiary">$ </span>vgpud
<span class="nv-text-accent">vgpud</span>: virtio-gpu at 00:03.0, currently held by virtio-gpu
<span class="nv-text-accent">virtio-gpu</span>: released to userspace; screen is the VBE framebuffer
<span class="nv-text-accent">vgpud</span>: claimed
<span class="nv-text-accent">vgpud</span>: display is 1280x800
<span class="nv-text-accent">vgpud</span>: scanout is ours, framebuffer at physical 0x3eceb000
<span class="nv-text-success">vgpud</span>: <span class="nv-text-success">mirroring the console</span>
</pre>
</div>
<p class="nv-body nv-text-tertiary section__note">
<b>No syscall in that transcript knows it is talking about a GPU.</b> The
kernel handed over a PCI device; the process decided what it was. That is
the property that makes the interface general — and the reason SchOS's own
drivers are being moved out through it first, rather than shaping it around
something foreign and hoping it fits.
</p>
</section>
<!-- ====================================================================== -->
<section id="numbers" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Numbers</p>
<h2 class="nv-heading">The size of it</h2>
</div>
<dl class="nv-stat-group">
<div class="nv-stat">
<dt class="nv-stat__label">lines in <code class="nv-code">kernel/</code> and <code class="nv-code">include/</code></dt>
<dd class="nv-stat__value">46,961</dd>
</div>
<div class="nv-stat">
<dt class="nv-stat__label">syscalls, Linux numbering</dt>
<dd class="nv-stat__value">207</dd>
</div>
<div class="nv-stat">
<dt class="nv-stat__label">patches carried against fastfetch</dt>
<dd class="nv-stat__value">0</dd>
</div>
</dl>
</section>
<!-- ======================================================================
PSOGM. The one place this purple is allowed, so it is spelled the one
way the system allows a subtree to carry its own colour: re-derive the
whole set from it, and let every role follow. -->
<section class="shell section" data-reveal>
<div class="nv-bed nv-bed--single crash" data-nv-brand style="--nv-brand: #4B1D9A">
<span class="nv-bed__label">When it stops</span>
<img class="crash__mark" src="Assets/shift.svg"
alt="Shift, the SchOS mark, as the crash screen draws it">
<div class="crash__copy">
<h2 class="nv-heading">PSOGM</h2>
<p class="nv-prose">
When the kernel panics it does not scroll a stack trace past you. It draws
a full-screen report — what failed, where, and the state that mattered —
and encodes the whole thing as a QR code so it can leave the machine
without being retyped. It reaches every display the machine has, including
the ones the kernel has handed to a userspace driver.
</p>
<p class="nv-prose nv-text-secondary">
This purple is <code class="nv-code">#4B1D9A</code>, and the theme reserves
it for exactly this. Normal states are calm and dark; only failure is loud.
It is the one colour in the system that means something, which is why it
appears once on this page and nowhere else.
</p>
</div>
</div>
</section>
<!-- ====================================================================== -->
<section id="docs" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Reading</p>
<h2 class="nv-heading">Where to look</h2>
<p class="nv-prose nv-text-secondary">
The documentation is written to outlive the work. Anything finished is
described in <code class="nv-code">architecture/</code>; anything intended
lives in <code class="nv-code">plan/</code>; and the bugs worth remembering
are kept in <code class="nv-code">history/</code>, in full, including the
wrong turns.
</p>
<p><a class="nv-button nv-button--primary" href="docs.html">Open the docs reader</a></p>
</div>
<div class="nv-card-grid">
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=architecture/README.md">Architecture</a>
</h3>
<p class="nv-card__subtitle">What the system is, layer by layer</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=plan/1.0.md">The 1.0 definition</a>
</h3>
<p class="nv-card__subtitle">What is in, what is out, and why</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=history/kernel.md">Kernel history</a>
</h3>
<p class="nv-card__subtitle">The bugs, and what each one taught</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=guides/building.md">Building it</a>
</h3>
<p class="nv-card__subtitle">Toolchain, ports, and running under QEMU</p>
</div>
</div>
</article>
</div>
</section>
<!-- ====================================================================== -->
<section class="shell section" data-reveal>
<div class="nv-card nv-card--elevated getband">
<img class="getband__mark" src="Assets/usb.svg" alt="">
<div class="getband__copy">
<p class="nv-overline nv-text-accent">Try it</p>
<h2 class="nv-heading">One ISO, one stick, nothing written to your disks</h2>
<p class="nv-prose nv-text-secondary">
It runs from RAM and leaves the machine as it found it. Or skip the
stick entirely — <code class="nv-code">make qemu</code> is the same
system in a window.
</p>
<div class="nv-cluster">
<a class="nv-button nv-button--primary" href="download.html">Download SchOS</a>
<a class="nv-button" href="docs.html?doc=guides/building.md">Build it instead</a>
</div>
</div>
</div>
</section>
</main>
<footer class="shell site-footer">
<div class="nv-divider"></div>
<div class="site-footer__row">
<span class="nv-body">SchOS — kernel <b>SchIFT</b>, filesystem <b>SchFS</b>.</span>
<span class="nv-code nv-text-tertiary">GPL-2.0-or-later, with the xv6-derived core under MIT.</span>
</div>
<p class="nv-body nv-text-secondary pride-note" id="pride-note">
<img src="Assets/pride.svg" alt="">
Built by, and for, people of every orientation and gender identity.
The flag stays up all year.
</p>
<p class="nv-body nv-text-secondary nv-prose" id="ai-note">
<b class="nv-text-primary">On AI.</b>
Parts of SchOS were written with AI assistance, and that is not the measure
of anything. A project is good when the people building it understand what
was built, and bad when nobody does — whoever, or whatever, typed it. Vibe
your way through and you get something no one can fix. Stay in the loop and
you get a system you can explain line by line. The bug writeups in
<a href="docs.html?doc=history/kernel.md">history/</a> are where that gets
checked, including the wrong turns.
</p>
</footer>
<script src="app.js"></script>
</body>
</html>