Eleven cards in a grid is a list people stop reading somewhere around the
fourth one. A row you move through is one you go along, and the section is a
survey rather than a comparison -- nothing in it needs to be read beside
anything else, which is the test for whether a grid was carrying information
or just filling space.
So it is a `.nv-scroller`: snapping, hidden scrollbar, arrows that appear only
at the end that has something behind it, and an edge fade that says "more this
way" without a scrollbar having to. All of that is the component's.
**This site's part is one declaration.** `--nv-scroller-item: 21rem`, because
18rem is a width for a card carrying a line and these carry a paragraph. I had
also written `align-self: stretch` to make the heights match, then checked:
they already do, because a flex row stretches by default. The rule came back
out -- restating something the system already guarantees is exactly the drift
the split between Niveus and `app.css` exists to prevent.
The honest cost: a reader who does not scroll sees three cards rather than
eleven, and the section's own claim ("every card marked runs is in the tree")
is about all of them. The fade and the arrows are what pay for that, and they
are the reason this is a scroller rather than a row with a scrollbar.
Verified in a browser: 11 items, equal 256px heights with no rule of ours,
`data-nv-at-start` set and `data-nv-at-end` clear on load, and the arrows page
the rail and swap over as it reaches each end.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
668 lines
29 KiB
HTML
668 lines
29 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/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">Apache-2.0 · runs from RAM · writes nothing to your disks</p>
|
|
</div>
|
|
|
|
<div class="nv-card nv-card--flush console" aria-label="Boot log">
|
|
<div class="console__bar">
|
|
<span class="nv-badge nv-badge--success"><span class="nv-badge__dot"></span>ttyS0</span>
|
|
<span class="nv-caption nv-text-tertiary">SchIFT</span>
|
|
</div>
|
|
<pre class="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="timeline">
|
|
<li class="timeline__step">
|
|
<span class="nv-overline timeline__when">First</span>
|
|
<h3 class="nv-title">64-bit, and more than one core</h3>
|
|
<p class="nv-body nv-text-secondary">
|
|
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>
|
|
</li>
|
|
<li class="timeline__step">
|
|
<span class="nv-overline timeline__when">Then</span>
|
|
<h3 class="nv-title">Its own filesystem</h3>
|
|
<p class="nv-body nv-text-secondary">
|
|
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>
|
|
</li>
|
|
<li class="timeline__step">
|
|
<span class="nv-overline timeline__when">Then</span>
|
|
<h3 class="nv-title">A Linux-shaped ABI</h3>
|
|
<p class="nv-body nv-text-secondary">
|
|
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>
|
|
</li>
|
|
<li class="timeline__step">
|
|
<span class="nv-overline timeline__when">Then</span>
|
|
<h3 class="nv-title">Hardware, not emulation</h3>
|
|
<p class="nv-body nv-text-secondary">
|
|
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>
|
|
</li>
|
|
<li class="timeline__step">
|
|
<span class="nv-overline timeline__when">Now</span>
|
|
<h3 class="nv-title">Drivers that are not in the kernel</h3>
|
|
<p class="nv-body nv-text-secondary">
|
|
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>
|
|
</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"><img class="cardmark" src="Assets/uberblock.svg" alt="">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">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">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">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">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">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">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">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">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">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">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-card nv-card--flush console" aria-label="Evicting the GPU driver to userspace">
|
|
<div class="console__bar">
|
|
<span class="nv-badge nv-badge--success"><span class="nv-badge__dot"></span>tty1</span>
|
|
<span class="nv-caption nv-text-tertiary">vgpud</span>
|
|
</div>
|
|
<pre class="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>
|
|
|
|
<div class="figures">
|
|
<div class="nv-card figure">
|
|
<b class="nv-display figure__value">46,961</b>
|
|
<span class="nv-label nv-text-secondary">lines in <code class="nv-code">kernel/</code> and <code class="nv-code">include/</code></span>
|
|
</div>
|
|
<div class="nv-card figure">
|
|
<b class="nv-display figure__value">207</b>
|
|
<span class="nv-label nv-text-secondary">syscalls, Linux numbering</span>
|
|
</div>
|
|
<div class="nv-card figure">
|
|
<b class="nv-display figure__value">0</b>
|
|
<span class="nv-label nv-text-secondary">patches carried against fastfetch</span>
|
|
</div>
|
|
</div>
|
|
</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">Apache-2.0, 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>
|