README: rewritten around what runs (Linux software, Xorg, apk, Linux's drivers), the honest gaps, measured numbers. plan/: 1.0.md is the finish line, where each clause of the acceptance test stands, and the register (one failing clause: a root that survives a reboot); built plans (foundations, hybrid, alpine, xorg) and the decided-against one (wayland) are gone, their content lives in architecture/; roadmap.md is only what is still open. guides: building/layout/testing/adding-a-driver (Linux code may be used). history: four entries (ls -lR, TLB shootdowns, MDIO 0x02460246, netlink MSG_TRUNC). Website: cards, stack, download page, docs index. Code comments that pointed at deleted plan docs point at the architecture docs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
786 lines
38 KiB
HTML
786 lines
38 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 — every layer its own</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>
|
||
<li><a class="nv-nav__item" href="#wallpapers">Wallpapers</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">
|
||
|
||
<!-- ====================================================================== -->
|
||
<!-- The one full-bleed band on the page, lit like the Graphite wallpaper. -->
|
||
<header class="heroband">
|
||
<div 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">
|
||
<span class="nv-tile nv-tile--xl hero__tile"><img src="Assets/shift.svg" alt=""></span>SchOS
|
||
</h1>
|
||
|
||
<p class="nv-heading hero__slogan">Every layer its own — from the first instruction to the last pixel.</p>
|
||
|
||
<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>
|
||
</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">A teaching kernel that outgrew its lessons</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, and everything else is arrangement</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">Running today, 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. Close to two
|
||
hundred 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">Ctrl+Alt+F1</code>…<code class="nv-code">F12</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" ><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>The desktop</h3>
|
||
<span class="nv-badge nv-badge--success">runs</span>
|
||
</div>
|
||
<div class="nv-card__body nv-text-secondary">
|
||
Xorg on the framebuffer with Window Maker, <code class="nv-code">xterm</code> and a few X clients;
|
||
NetSurf for the web. No acceleration yet — the GPU is a plan, and the plan is Linux's own
|
||
<code class="nv-code">amdgpu</code> through LDLS.
|
||
</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 desktop'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">Measured, not marketed</h2>
|
||
</div>
|
||
|
||
<!-- stats:begin -->
|
||
<dl class="nv-stat-group">
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">lines of code in <code class="nv-code">kernel/</code> and <code class="nv-code">include/</code></dt>
|
||
<dd class="nv-stat__value">51,893</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">lines of comments alongside them</dt>
|
||
<dd class="nv-stat__value">17,213</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">first-party lines in all</dt>
|
||
<dd class="nv-stat__value">72,766</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">syscalls, Linux numbering</dt>
|
||
<dd class="nv-stat__value">193</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">drivers in the kernel</dt>
|
||
<dd class="nv-stat__value">15</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">Alpine packages in the live root</dt>
|
||
<dd class="nv-stat__value">179</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">commits</dt>
|
||
<dd class="nv-stat__value">289</dd>
|
||
</div>
|
||
<div class="nv-stat">
|
||
<dt class="nv-stat__label">days since the first one</dt>
|
||
<dd class="nv-stat__value">78</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>
|
||
<!-- stats:end -->
|
||
</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="wallpapers" class="shell section" data-reveal>
|
||
<div class="section__head">
|
||
<p class="nv-overline nv-text-accent">Wallpapers</p>
|
||
<h2 class="nv-heading">Four surfaces to sit on</h2>
|
||
<p class="nv-prose nv-text-secondary">
|
||
Every one is the Shift mark under a different light, generated from the
|
||
same geometry the loader draws — so they change when the mark does.
|
||
3840×2160, free to use under the same licence as the rest of the tree.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="walls">
|
||
<figure class="nv-card wall">
|
||
<img class="wall__img" src="../branding/wallpapers/graphite.jpg" alt="Graphite: Shift on warm graphite, throwing a pool of violet on the surface. The default." loading="lazy" width="3840" height="2160">
|
||
<figcaption class="wall__caption">
|
||
<span class="nv-title">Graphite</span>
|
||
<span class="nv-body nv-text-secondary">Shift on warm graphite, throwing a pool of violet on the surface. The default.</span>
|
||
<span class="nv-cluster">
|
||
<a class="nv-button nv-button--sm" href="../branding/wallpapers/graphite.jpg" download>4K JPEG</a>
|
||
<a class="nv-button nv-button--ghost nv-button--sm" href="../branding/wallpapers/graphite.svg" download>SVG</a>
|
||
</span>
|
||
</figcaption>
|
||
</figure>
|
||
<figure class="nv-card wall">
|
||
<img class="wall__img" src="../branding/wallpapers/strata.jpg" alt="Strata: The slabs repeated into a cascade that recedes into indigo." loading="lazy" width="3840" height="2160">
|
||
<figcaption class="wall__caption">
|
||
<span class="nv-title">Strata</span>
|
||
<span class="nv-body nv-text-secondary">The slabs repeated into a cascade that recedes into indigo.</span>
|
||
<span class="nv-cluster">
|
||
<a class="nv-button nv-button--sm" href="../branding/wallpapers/strata.jpg" download>4K JPEG</a>
|
||
<a class="nv-button nv-button--ghost nv-button--sm" href="../branding/wallpapers/strata.svg" download>SVG</a>
|
||
</span>
|
||
</figcaption>
|
||
</figure>
|
||
<figure class="nv-card wall">
|
||
<img class="wall__img" src="../branding/wallpapers/porcelain.jpg" alt="Porcelain: The light one: glazed porcelain on paper, the top slab in the accent." loading="lazy" width="3840" height="2160">
|
||
<figcaption class="wall__caption">
|
||
<span class="nv-title">Porcelain</span>
|
||
<span class="nv-body nv-text-secondary">The light one: glazed porcelain on paper, the top slab in the accent.</span>
|
||
<span class="nv-cluster">
|
||
<a class="nv-button nv-button--sm" href="../branding/wallpapers/porcelain.jpg" download>4K JPEG</a>
|
||
<a class="nv-button nv-button--ghost nv-button--sm" href="../branding/wallpapers/porcelain.svg" download>SVG</a>
|
||
</span>
|
||
</figcaption>
|
||
</figure>
|
||
<figure class="nv-card wall">
|
||
<img class="wall__img" src="../branding/wallpapers/dial.jpg" alt="Dial: The SchFS uberblock ring as hardware — the newest slot and the root lit." loading="lazy" width="3840" height="2160">
|
||
<figcaption class="wall__caption">
|
||
<span class="nv-title">Dial</span>
|
||
<span class="nv-body nv-text-secondary">The SchFS uberblock ring as hardware — the newest slot and the root lit.</span>
|
||
<span class="nv-cluster">
|
||
<a class="nv-button nv-button--sm" href="../branding/wallpapers/dial.jpg" download>4K JPEG</a>
|
||
<a class="nv-button nv-button--ghost nv-button--sm" href="../branding/wallpapers/dial.svg" download>SVG</a>
|
||
</span>
|
||
</figcaption>
|
||
</figure>
|
||
</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. Your disks untouched.</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 — built from the metal up. 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>
|