Login
Glint working plan
Login

This is the working plan: what Glint is, how it is built, and the order of the work. Each phase has its own document under docs/phases/, with its slices and references. Terms are explained in the glossary. Update this file whenever a decision is made.

Concept

To Linux, Glint looks like a hypervisor. An unmodified Linux kernel boots on Glint as a guest and finds only interfaces it already supports: EFI, devicetree, PSCI/SMCCC, a virtual GIC and timer, and virtio. Glint is the privileged layer underneath. It is portable because it runs on EFI, fast because Zephyr drivers are compiled in, and it gets Linux's drivers by giving devices to the guest. On the smallest targets, Zephyr can take EFI's place.

Glint reaches hardware only through a platform interface shaped like UEFI: the system table, boot/runtime services and protocols looked up by GUID (SIMPLE_TEXT_OUTPUT, SERIAL_IO, BLOCK_IO, SIMPLE_FILE_SYSTEM, GRAPHICS_OUTPUT, SIMPLE_NETWORK, timer events, page allocation). Four kinds of provider stand behind it:

Linux guest (unmodified kernel) its drivers own passed-through devices and serve them back to Glint over virtio   virtual machine: EFI + DT + virtio from Glint Glint (Crystal) scheduler, memory, VFS, hypervisor   EFI-shaped platform interface (2) Zephyr drivers compiled in through compat/zephyr; interrupt- and DMA-driven (1) UEFI firmware any target, polled (3) Linux guest drivers, reached over virtio (4) Zephyr as the EFI provider on MCUs without UEFI
down
Guest: box wid 6.6 ht 0.6 "Linux guest (unmodified kernel)" "its drivers own passed-through devices and serve them back to Glint over virtio"
arrow <-> down 0.5 "  virtual machine: EFI + DT + virtio from Glint" ljust
Glint: box wid 6.6 ht 0.6 "Glint (Crystal)" "scheduler, memory, VFS, hypervisor"
arrow <-> down 0.5 "  EFI-shaped platform interface" ljust
Bus: dot invisible
P2: box wid 1.55 ht 0.95 at Bus + (-0.85, -0.95) "(2) Zephyr drivers" "compiled in through" "compat/zephyr;" "interrupt- and" "DMA-driven"
P1: box same at P2 - (1.7, 0) "(1) UEFI firmware" "any target," "polled"
P3: box same at P2 + (1.7, 0) "(3) Linux guest" "drivers, reached" "over virtio"
P4: box same at P3 + (1.7, 0) "(4) Zephyr as the" "EFI provider on" "MCUs without UEFI"
line from (P1.x, Bus.y) to (P4.x, Bus.y)
line from (P1.x, Bus.y) to P1.n
line from (P2.x, Bus.y) to P2.n
line from (P3.x, Bus.y) to P3.n
line from (P4.x, Bus.y) to P4.n
  1. Firmware (baseline, any target). Glint boots as a PE32+ EFI application and runs on firmware protocols alone, so any EBBR/SystemReady or x86 UEFI machine works with no board code.
  2. Compiled-in Zephyr drivers (performance). Upstream Zephyr C drivers are built against compat/zephyr and wrapped so that each produces the same protocol a firmware driver would. They are interrupt- and DMA-driven, where firmware protocols are polled. Zephyr is Apache-2.0, which can be linked into Glint.
  3. Linux on top (Linux's drivers, unlinked). Glint does not link any Linux code. It runs an unmodified Linux kernel as a guest. Glint provides the guest with a small EFI environment, so Linux boots through its own EFI stub, plus a devicetree and virtio devices. Devices that only Linux can drive are passed through to the guest. Linux serves them back to Glint as virtio devices, acting as a driver domain the way Xen's dom0 does. Since Linux runs as a separate program and is not linked into Glint, its GPL-2.0 license does not apply to Glint.
  4. Zephyr in place of EFI (ultra-small). On microcontrollers without UEFI, a Zephyr-based layer builds the subset of the system table and protocols Glint uses. Glint is linked statically with it, with no PE loader. U-Boot's EFI loader is the precedent: it is EFI on top of its own driver model. The first such target is BeagleConnect Zepto (TI MSPM0L1117: Cortex-M0+, 16 KiB RAM, 128 KiB flash), with UART and I2C.

Run modes

UEFI divides a machine's life at ExitBootServices, and Glint's modes follow that line.

Before the exit (boot services). Firmware owns the machine. The loader may use every boot service: memory (AllocatePages, AllocatePool), protocols found by GUID (console in and out, serial, block, file system, network, graphics), events and timers (CreateEvent, SetTimer, WaitForEvent), Stall, and the watchdog. Firmware owns the interrupt controller, the timers and every device's state, so a loader must not take them over. U-Boot, the firmware Glint is tested on, uses no interrupts at all: "Our timers have to work without interrupts, so we check whenever keyboard input or disk accesses happen" (lib/efi_loader/efi_boottime.c). UEFI also requires firmware to arm a five-minute watchdog when it starts a boot option; U-Boot does (efi_set_watchdog(300)), so a loader that stays in boot services longer must turn it off with SetWatchdogTimer(0).

The exit. ExitBootServices(image, map_key) is all or nothing. The map key proves the caller holds the current memory map; a stale key fails, and the caller reads the map again and retries. On success, U-Boot signals the exit event groups, stops its timers, disables interrupts, quiesces and removes its devices, and sets the system table's ConIn, ConOut, StdErr and BootServices to null. After a failed call the firmware may already be partly shut down, so the only safe calls left are GetMemoryMap and ExitBootServices again.

After the exit (runtime). The caller owns the CPU, the MMU, interrupts, timers and every device, and boot-services memory becomes free memory. What remains is the configuration tables (devicetree, ACPI, SMBIOS) in their reserved memory, and the runtime services the firmware supports. U-Boot 2026.07 advertises GetVariable, GetNextVariableName, SetVirtualAddressMap and ConvertPointer (and QueryVariableInfo with a file store), but not SetVariable, GetTime or ResetSystem; reset comes from PSCI on Arm and ACPI on x86. Nothing that was a boot service survives: after the exit, every device Glint uses needs a Glint or Zephyr driver.

When Glint leaves boot services. This paragraph is the plan's one statement of it. Phase 2 leaves boot services first only as a demonstration, entered with the shell's native command (2.6). From the end of Phase 2 (2.10), and so throughout Phase 3 and after, every boot runs in two steps. It first loads through EFI everything it will need into memory of its own (2.9): the files it will use from the ESP, guest images among them, and, last, the final memory map. It then exits boot services and runs native. Hosted mode remains as the fallback when 2.6's checks fail, and as the mode for machines Glint cannot drive yet. Each boot takes the furthest mode its providers and CPU allow, up to the mode requested (native by default; hypervisor when asked, from 4.3a). The choice is made in one place, before ExitBootServices is attempted, since a failed exit leaves no hosted mode to return to (2.6).

In plain terms. When a computer starts, its firmware already knows how to print, read the disk and use the network, slowly and one thing at a time. Hosted Glint borrows those abilities, so it runs on almost any machine on the first day. Native Glint has its own drivers, so it says goodbye to the firmware and runs the machine itself: faster, and able to do many things at once. Hypervisor Glint is native Glint that also runs other operating systems, chiefly Linux, as guests, each believing it has a machine of its own. Glint is an operating system that can also host guests, as Linux with KVM is, rather than a hypervisor that runs everything, itself included, as a guest, as Xen does. That keeps Glint usable on machines without virtualization support, in native mode, and keeps its own work out of a guest's reach.

What Linux sees

The guest ABI is made only of interfaces upstream Linux already drives, so the guest needs no Glint-specific patches. It looks like a QEMU/KVM virt machine without claiming to be KVM:

Interface Arm64 x86_64
Boot Glint-provided EFI (boot + runtime services) → Linux EFI stub; DT in the config table Glint-provided EFI → EFI stub; ACPI tables
CPU control PSCI 1.x, SMCCC 1.1 via HVC; SMCCC hypervisor UID identifies Glint CPUID hypervisor leaf identifies Glint
Interrupts / time vGIC (GICv3 emulation), virtual generic timer local APIC as x2APIC (MSRs), 8259 and PIT (I/O ports), MSI later; TSC
Devices virtio-mmio console, block, net, vsock, rng; passed-through DT nodes virtio-pci; passed-through PCI functions
Memory stage-2 tables, balloon later EPT/NPT

The plain virt DT and these interfaces should let a stock distro Image or bzImage boot.

x86 guests' interrupts under choice A (decided Nov 11, 2026). The table's x86 row used to list an emulated local APIC, IOAPIC and HPET. All three are reached through memory addresses, and choice A (x86 devices through I/O ports only) rules that out. So x86 guests get the local APIC in x2APIC mode, which Linux reaches through MSRs (model-specific registers that a VM exit reports with their number and value, so no decoding is needed), plus the 8259 interrupt controller and the PIT timer on I/O ports, and no IOAPIC or HPET. Plain MSI comes with several CPUs (Phase 8). The timer's rate is measured against the PIT; if 6.7b shows Linux needs it told instead, that's added then, through CPUID. The maintainer left this design to Glint as long as it crosses neither the I/O-port decision nor adds a decoder (relayed in glint 5c447d1377). What is at stake, in plain words:

Devices and the Linux guest

Linux has drivers for the widest range of devices, so Glint uses Linux for devices it has no driver for. Glint stays in charge, which gives a robustness that Linux, as one large monolithic kernel, cannot give itself: a driver failure in the guest stops at the guest, and Glint can restart it. Some cost is expected, and the design keeps it small. Four device paths are needed:

  1. Pass-through (Glint → Linux, the device itself). Glint hands a peripheral's memory-mapped registers and interrupt to the Linux guest, which drives it as if it were native, while Glint still governs the guest's memory and interrupts (Phase 10).
  2. Bridges (Glint → Linux, as virtio). Where Glint has its own driver (the serial port, EFI-provided networking, a compiled-in Zephyr driver), it offers the device to Linux as a virtio device: console, block or network (Phases 5, 6 and 12).
  3. Return (Linux → Glint). A device Linux drives after pass-through is offered back to Glint, first through simple protocols over a vsock channel (for example, a block protocol), then through a virtio device served from inside Linux, which costs less (Phase 10).
  4. Applications (Linux programs ↔ Glint). Linux programs reach Glint's services through the same vsock channel (Phase 9), with a small library or daemon on the Linux side added when an application needs it.

USB is native. USB does not take any of the four paths. Glint owns the whole xHCI controller and the USB tree behind it (hubs and every class of device), as a standard interface under principle 6, and guests reach devices only through a shim: per-class virtio devices are the natural default, with request forwarding over vsock as a fallback (survey section 7). Glint keeps the keyboard, so the user can always reach it. Zephyr has no xHCI host driver and no host-side HID, mass-storage or network class (docs/zephyr-survey.md, section 7), so the xHCI and class drivers are Glint's own. Guests see an emulated xHCI controller with the devices Glint chooses to show them; it is Glint's primary peripheral, and Track U places it (docs/phases/U-usb.md).

DMA without an IOMMU. Neither the AM62x nor the AM67A has an IOMMU. The AM62x technical reference manual (SPRUIV7C) lists none, and the AM67A's (J722S, SPRUJB3D) lists "Virtualization (SR-IOV, xHCI, or Arm SMMU)" as unsupported. So a passed-through device can write to any memory, and Glint cannot catch it with page tables. Both chips do have region-based firewalls in front of DDR, which check each bus initiator's privilege ID. These might confine a device's DMA coarsely, if the device has its own privilege ID and TI's system firmware allows the firewall to be programmed. Slice 13.6 investigates this. Glint allows this only when a guest is explicitly marked as trusted for unprotected DMA. Without that opt-in, it refuses to pass such a device through, and the boot log records every opt-in.

The shell and human-facing syntax

Everything a person types to Glint is Crystal. The shell accepts only lines that also parse as Crystal and mean the same thing; Crystal allows calls without parentheses, so ls, cat "hello.txt" and i2c.read 0x48, 0 are ordinary Crystal. The shell's grammar is one table of rules, written as Crystal data for cleave's GlyphParser (the progressive multipass parser that began in crystal-robots). It grows by one rule per slice, only when a phase exposes something new to talk to, and Crystal's own parser checks every example. Commands are calls into Glint's platform interface, run by a small interpreter. Inside Glint and on small targets, the rules are matched by code generated at build time from PCRE2's compiled bytecode, so no PCRE2 is linked into the target (Track P). A fully featured Crystal shell belongs where the whole language is available: a Linux guest or BQ2 image running the Crystal compiler, and later Glint itself through Track C.

Crystal's standard library on Glint

Glint's scope includes enough operating-system support to run Crystal's whole standard library, apart from what is specific to another operating system, validated by Crystal's own spec/std suite (Track C). Any patch to Crystal for this is kept minimal, since Crystal's maintainers should not carry an educational kernel.

Build constraints

The bootstrap-qcow2 (BQ2) toolset is enough to build the Glint kernel. Building it brings in no Python, flex, bison, dtc, Perl or other extra tools. BQ2 provides: musl, BusyBox, make, m4, zlib, linux-headers, libressl, cmake, LLVM/clang/lld, Crystal and its libraries (bdwgc, pcre2, gmp, libyaml, libxml2, libffi, libiconv), shards, git, sqlite and fossil. In keeping with BQ2's direction, Glint also avoids make, cmake and shell scripts where Crystal can do the job.

This means:

Building the test platform: QEMU and firmware

Glint builds its own reduced QEMU from pinned upstream source (QEMU 11.1.2), using only BQ2 tools, for both aarch64 and x86_64. Glint targets aarch64 SBCs and x86_64 desktops and servers alike. Each QEMU binary can emulate either guest architecture on either host.

qemu-system-aarch64 qemu-system-x86_64
Machine virt (virtualization=on for EL2) q35
Devices GICv2/v3, PL011, virtio-mmio/pci, fw_cfg LAPIC/IOAPIC, 16550, HPET, virtio-pci, fw_cfg, QEMU's ACPI tables
Accelerators TCG; KVM on aarch64 hosts TCG; KVM on x86_64 hosts
EFI firmware U-Boot qemu_arm64_defconfig U-Boot qemu-x86_64_defconfig
Left out UI, audio, Rust devices, slirp at first, block formats other than raw/qcow2 same

Firmware is U-Boot, not EDK2. Both U-Boot configurations are built with cleave's Kconfig and dtc, so the same EFI implementation runs under QEMU and on the Beagle boards.

x86 hypervisor testing. QEMU's TCG emulates AMD SVM (target/i386/tcg/system/svm_helper.c) but has no VMX emulation. Glint's x86 hypervisor therefore implements SVM first, so it can be tested under TCG anywhere. VMX is tested with nested KVM on Intel hosts, or on Intel hardware directly.

Generators: work from the data

QEMU's build runs code generators written in Python. The rule: where the input is a data expression, the Crystal port works from that data and its specification, not from the Python program or its output. Python output may serve as a test oracle only where the knowledge exists only as Python code. Every generator below has a data form and a spec, so no Python oracle is planned:

Generator Data it reads Specification Needed by
decodetree.py target/arm/tcg/*.decode (15 files) docs/devel/decodetree.rst aarch64 only. x86's decoder is hand-written C
minikconf.py Kconfig, hw/**/Kconfig, configs/devices/*/*.mak docs/devel/kconfig.rst both
qapi-gen.py qapi/*.json schemas docs/devel/qapi-code-gen.rst both
tracetool trace-events files (nop backend only) docs/devel/tracing.rst both
feature_to_c.py gdb-xml/*.xml trivial: embeds files as C strings both
hxtool *.hx trivial: line filter both
keymap-gen (keycodemapdb) subprojects/keycodemapdb/data/keymaps.csv the CSV's columns and ui/input-keymap.c, which includes the tables both
block-coroutine-wrapper.py co_wrapper declarations in include/block/*.h and block/coroutines.h docs/devel/block-coroutine-wrapper.rst both
module_block.py the block drivers' module data none: the consumer in block.c and util/module.c (with --disable-modules, almost empty) both
make-config-poison.sh, qemu-version.sh the generated config headers; the version file trivial shell scripts, ported to Crystal both
Meson meson.build files not ported. The source lists, per-file flags and config-host.h are written as data in Crystal, derived from the pinned QEMU's meson.build both

Each port is checked through QEMU itself: the reduced QEMU must compile cleanly and pass its own C tests (tests/unit, tests/qtest, tests/tcg where they run without Python) and boot Glint and Linux. A test failing is the oracle; matching what Python would have generated is not.

GLib (≥ 2.66, core glib and gmodule only) is built the same way, from data. libfdt (QEMU's bundled dtc subproject) is plain C. Pixman is optional without a display. zlib is in BQ2.

The generator ports stay in Glint (qemu/tools/). They are not to be offered to cleave, BQ2 or other projects for now.

The four virtues

Every slice is judged by the four virtues of OCX (Ollama-Codex, the workbench this project is developed on), as the Ollama-Codex wiki states them:

Principles

  1. Layered construction in slices. See Development method below: one slice per check-in, each one demonstrated and small enough to analyze, with phases that follow the development text chapter by chapter.
  2. One interface, swappable providers. Above the platform interface, Glint code never knows whether firmware, a Zephyr driver or the Linux guest is behind a protocol.
  3. Host-testable logic. Put allocators, schedulers, parsers (devicetree, FAT, ELF, PE), virtio rings and page-table builders in plain Crystal that also compiles against the normal prelude, so crystal spec covers it on Linux. A fake EFI system table in Crystal lets the specs exercise the platform interface without firmware.
  4. One prelude; GC as an isolated option. Glint ships its own prelude/, a subset of Crystal's standard library that needs no libc or GC, and the kernel core never depends on a collector. Where a part of Glint wants the full standard library, it may use a garbage collector as an isolated, optional feature. That collector follows Crystal's own choice, the Boehm collector (bdwgc, already in BQ2), built freestanding over Glint's page allocator once threads exist (after Phase 8).
  5. Zephyr code linked in; Linux run on top. compat/zephyr implements kernel objects (k_thread, k_sem, k_mutex, k_msgq, k_work, k_timer, k_spinlock), struct device and DEVICE_DT_*. The generated devicetree macros and autoconf.h come from Glint's Crystal tools (see Build constraints). Its C headers declare the API and Crystal fun exports implement it. The Zephyr source is an external tree, not a copy in the checkout: the build finds it through ZEPHYR_SRC and checks it against the upstream commit recorded in third_party/zephyr/PIN.md, beside which any patches are kept as separate files and applied by Crystal code or BusyBox patch (Track Z states the pin). Linux is used only as an unmodified, prebuilt guest kernel image, pinned by checksum in guest/linux/.
  6. No BSPs. Glint's own code covers only what an architecture or a standard defines: UEFI, devicetree/ACPI, PSCI/SMCCC, the Arm generic timer, GIC, APIC, the virtualization extensions and virtio. There are no boards/ or soc/ directories. SoC support comes from firmware in hosted mode, from upstream Zephyr drivers matched by devicetree compatible, from the Linux guest for everything else, and from Zephyr's own board support on MCUs.

Zephyr's drivers fix their hardware at build time, from a devicetree, so native Glint is built against one build devicetree per machine class: QEMU virt and q35 now, BeaglePlay and BeagleY-AI later. Each is taken from upstream devicetrees (QEMU's own for virt, the PC's standard COM1 written as Zephyr's own x86 devicetrees write it for q35, and Linux's or Zephyr's board devicetrees later), with at most a small overlay, as data, never as code. At boot, before leaving boot services, Glint checks that the firmware's description matches the class the image was built for; if it does not, the boot stays hosted (2.6). This keeps principle 6: a build devicetree is upstream data that a generator reads, not board code Glint writes, and a machine with no class still runs, hosted, on its firmware. Late binding comes later: for drivers whose instances differ between machines only in addresses and interrupts, Glint will patch those in from the firmware's description at boot, so one build serves every machine of that shape.

  1. Education first, fit for daily use. Glint is primarily for teaching, and is also meant for everyday use by its maintainer: production worthy, though not aiming to compete commercially. Slices stay small enough to teach from, and nothing is excused from tests because it is "only educational".
  2. Measure the speed-up. Every swap of a firmware protocol for a Zephyr provider or a Linux-guest-backed one ships with a benchmark against the firmware protocol (throughput, latency, CPU time).

The development text

Chosen: xv6: a simple, Unix-like teaching operating system, by Russ Cox, Frans Kaashoek and Robert Morris (MIT). All development slices cite this one text. Citations are pinned to mit-pdos/xv6-riscv-book commit fa3b46bc43 and given as chapter and section with a quoted sentence, e.g. xv6 §6 "Interrupts and device drivers".

Why this text, judged by OCX's virtues (Ollama-Codex wiki):

Alternatives considered:

Three texts, three roles

The build follows xv6 alone. Two more texts are cited wherever they apply, each with a different job:

Text Role How citations are checked
xv6 (Cox, Kaashoek, Morris; MIT licence) Spine. It sets the phase order, and every slice cites the passage it implements Quoted exactly from xv6-riscv-book fa3b46bc43
Hailperin, Operating Systems and Middleware: Supporting Controlled Interaction, rev. 1.3.1 (CC BY-SA 3.0) Principle. It states, in general terms, why a mechanism is right. xv6 mostly says what xv6 does Quoted exactly from the LaTeX source. Section numbers are taken from the source's own chapter order
Tanenbaum & Bos, Modern Operating Systems, 4th ed. (2014) and 5th ed. (2023) (Pearson; proprietary) Survey. It gives the widest scope and the most influential framing. It is the one text of the three with a whole chapter on virtualization (ch. 7) and one on OS design (ch. 12) Checked against the 4th edition; not reproduced. The 4th edition is the reference edition. Every cited section was read in the maintainer's licensed copy on their behalf to confirm it supports the claim made here. At the maintainer's direction its text is not quoted or reproduced anywhere in this project; references give section numbers and titles plus our own one-line summary. 5th-edition locations come from Pearson's published tables of contents (5th Global Edition, 4th Global Edition); the 5th edition's content is unchecked

Each phase document ends with its references and a rationale saying what each text contributes and why xv6 still leads.

Where Glint goes beyond xv6 (EFI, the hypervisor, Zephyr, Linux as a guest), a slice cites the "Real world" section of the same chapter, which is where xv6 itself points beyond its own design. It also cites the interface specification it implements (UEFI 2.10, the Arm ARM, virtio 1.3, PSCI/SMCCC). Those are specifications, not a second textbook.

Development method: slices

This follows the tutorial line in crystal-robots (branch tutorial, docs/TUTORIAL.md). There, every one of 53 check-ins "compiles, passes crystal spec, and is demonstrated by a spec example or a crystal run/bin/crystal-robots invocation named in its own check-in comment". Phases were sized as one blog post each: motivation and design, then the commits in order, then a live demo. Glint uses the same rules, with each rule tied to an OCX virtue:

  1. One slice, one check-in, one idea. It builds both EFI images (aarch64 and x86_64), crystal spec passes, and nothing earlier regresses.
  2. Claim, passage, evidence (Clarity, Demonstrability). The check-in comment has four parts:
    • Claim: what this slice makes true;
    • Passage: the xv6 section and sentence it implements, plus the Hailperin and Tanenbaum references for that phase or slice where they apply (each phase document lists them). A track's slice is exempt from the xv6 text: it cites its own specification and sources instead (QEMU's documents for Track T, PCRE2's for Track P, Zephyr's for Track Z), as its document states;
    • Demonstration: the exact command and its observed result;
    • Size: the lines added and removed outside specs and fixtures, and, for a slice that changes what goes into an image, both images' sizes in bytes, before and after.
  3. Small enough to analyze (Parsimony). A slice's non-spec diff should be readable in one sitting: aim for under ~200 lines, and split anything over ~400. A slice may exceed ~400 when a further split would need a temporary stub that a later check-in removes; its check-in comment then says why. Tambassi's account of parsimony in software design (Philosophical Problems in Science 75, 2023, pp. 135–155) gives the review questions. Tambassi numbers each claim; each bracketed number links to the page of the article where that claim is made (journal pp. 138 and 145–146):
    • Does it "solve the problem it aims to solve, but no more" ([5])?
    • Can it still be "improve[d] by subtraction" ([6])?
    • Are its "components, details, and junctions … reduced to the essential" ([7])?
    • Does each thing appear only once ([39])? For example, the EFI protocol definitions serve both Glint and its guests.
    • Have the types of mechanism been reduced before their count ([40] before [41])? For example, one platform-interface mechanism for every provider.
  4. Through declared seams only (Loose coupling). A slice touches other parts only through the platform interface, compat/zephyr or the guest ABI. A slice that needs a new seam adds it as its own slice first.
  5. Demonstration ladder. Each slice is demonstrated at the highest rung it can reach:
    1. crystal spec on Linux against the fake EFI system table;
    2. a check of the built EFI images (PE32+ headers, sections, relocations);
    3. a headless boot under the project-built QEMU + U-Boot (once track T delivers), passing on an expected serial line;
    4. real hardware (BeaglePlay, BeagleY-AI, an x86_64 PC).
  6. Architectures. A slice is one check-in for both architectures when the code is shared, or differs only in a few register or instruction names. Where the architectures differ substantially (interrupt controllers, CPU start-up, the guest run loop), the slice splits into N.Ma (aarch64) and N.Mb (x86_64), aarch64 first, both inside the phase. The x86 hypervisor uses SVM, with VMX later.
  7. Every slice explains itself. In its phase document, each slice is a short paragraph that lets a reader with no other context see what it is for, what it is made of, how it connects to earlier slices and the rest of the design, and what brought it to this point in the order. It does this in prose, not under headings, and names the virtue it serves where that is not obvious. Within a phase, slices follow build dependencies, so a slice may cite an earlier section of the chapter than the slice before it. Across phases, each phase's opening passage moves forward through the book. A slice may cite an earlier chapter when it picks up work deferred from there; for example, sleep locks (xv6 §7.8) wait for Phase 9's sleep primitive.
  8. As-built index. docs/TUTORIAL.md lists every slice by hash, phase by phase, the way crystal-robots' does. Each phase gets an outline sized as one post: the chapter's opening passage, the slices, then the demo.
  9. Detail when due. The current phase's slices are complete, each with its quoted passage. Later phases list provisional slices that are refined, and given their quotations, when the phase starts.
  10. Who writes, who reviews. Codex runs write each slice on its own branch from a task in docs/tasks/. A Claude run reviews it against the four virtues and merges it, annotates it lightly, or sends it back with a revised task, as docs/WORKFLOW.md describes.

Status of the plan

The structure is settled: the concept, run modes, device paths, build constraints, principles, development method, and the order of phases and tracks. Phases 1 to 5 and Tracks P, T and Z are done on both machines: Glint boots, finds its hardware, leaves boot services by default, runs on Zephyr's UART drivers compiled from Glint's own generated headers, reports its own faults, and is a hypervisor whose test guest prints through emulated devices, with lazily backed memory. Track S's S.1 and Track U's U.1 are merged. Phase 6 is refined (rule 9) and is the current work. A review of Track Z against the four virtues led to the practices now in docs/WORKFLOW.md. Slices in later phases are provisional by design: each is refined, and given its quoted passage, when its phase starts, and any change to the structure is recorded in the decision log. The open decisions for the maintainer are listed under Open questions below.

Phases

Each phase follows one chapter of xv6, in the book's order, and has its own document. Phases 1–13 run in sequence. Track T builds the test platform alongside Phase 1 and must finish (T.11) before Phase 2; T.11 also meets slice 2.1, so 2.2 is Phase 2's first check-in. Track P builds the shell's grammar and matcher alongside Phase 1, and must reach P.4 before slice 1.8. Track Z builds the Zephyr seam after Track T: Z.1 came before any other Phase 2 slice, Z.3 comes before 2.4a, and Z.9 before 2.5. Track S brings Glint to microcontrollers after Phase 6, and Track C brings Crystal's standard library to Glint after Phase 10. Track U brings USB: U.1 after Phase 5, U.2–U.5 inside Phase 6 after 6.7b (Linux on both machines) and before 6.8, and U.6 with Phase 13.

Phase Document xv6 chapter What it adds Demo
1 Interfaces §1 Operating system interfaces The EFI-shaped platform interface in hosted mode: console, files, keyboard, one lookup mechanism, a C seam, a shell A scripted shell session on the fake EFI table; both images built and checked
2 Organization and boot §2 Operating system organization Booting under firmware, privilege level and watchdog, memory map, devicetree/ACPI, native mode's system table, the mode choice and leaving boot services (first on request), panic, the threat model, preloading, native by default Boots under QEMU + U-Boot on both architectures, reports its privilege, memory map and console, preloads its files and leaves boot services by default, with Zephyr's UART as console; panics cleanly at the fault address it printed; asked to stay hosted, it does
3 Page tables §3 Page tables Page allocator and the page-allocation interface, a page-table builder (3.2), Glint's own tables (3.2a aarch64, 3.2b x86_64), guard pages and exception stacks (3.3), permissions (3.3b), heap, guest second-stage tables, reading (3.6) and placing (3.6b) a preloaded guest image A guard-page fault is reported; a guest memory map is checked
4 Traps §4 Traps and system calls Full trap handling, a test guest, the guest run loop, PSCI/SMCCC calls, checking guest arguments The test guest calls PSCI and powers off
5 Page faults §5 Page faults Second-stage fault decoding, one device dispatcher for memory and I/O ports, UART, virtio-mmio and virtio-pci, virtio console, lazy guest memory The test guest prints through emulated devices
6 Interrupts and drivers §6 Interrupts and device drivers Interrupts, timers, virtual interrupts, an interrupt-driven Zephyr console, guest firmware, virtio-blk, Track Z's generators and shim extended, the first Zephyr storage provider Unmodified Linux boots to a shell on Glint; firmware vs Zephyr benchmark
7 Locking §7 Locking Secondary CPUs, spinlocks, lock order and checker, memory ordering, Zephyr's locks Lock-order checker; 4-CPU stress run
8 Scheduling §8 Scheduling Context switch, threads, preemption, per-CPU state, vCPUs as threads, proportional share Linux on 4 vCPUs alongside a second guest
9 Sleep and wakeup §9 Sleep and wakeup Sleep/wakeup, sleep locks, idle guests, virtqueue notifications, vsock, guest lifecycle An idle guest costs almost nothing; vsock echo
10 File system §10 File system Block layer, buffer cache, FAT, guest disks as files, the Linux driver domain Glint reads a disk only Linux drives
11 Logging §11 Logging Glint's persistent state with a write-ahead log State survives QEMU being killed mid-update
12 Concurrency revisited §12 Concurrency revisited Lock-free virtqueues, per-CPU device work, virtio-net, a lock audit virtio-net scales across 4 vCPUs
13 Summary §13 Summary Interchangeability review, BeaglePlay, BeagleY-AI, x86_64 PC, Intel VMX, pass-through on Beagle hardware, security review The Phase 6 demo on real hardware
T Test platform (QEMU's own specifications) Generator ports, GLib, reduced QEMU for both architectures, U-Boot, the boot harness Phase 1 images boot under the project-built QEMU
Z The Zephyr seam (Zephyr's own documentation and source) ELF images with a PE header; Phase 6's drivers checked first; Crystal generators for Zephyr's devicetree macros, autoconf.h and syscall stubs; a minimal shim; Zephyr's UART as a console provider Zephyr's PL011 and NS16550 drivers, unmodified, are Glint's console after ExitBootServices (2.6)
P The grammar and its matcher (PCRE2, cleave's GlyphParser) The shell's Crystal-syntax grammar as data; a PCRE2-free matcher generated at build time The grammar runs in Glint's images with no PCRE2 linked
U USB §6 Interrupts and device drivers An emulated xHCI controller for aarch64 guests, a virtual keyboard behind it, Glint's own xHCI driver, forwarding Glint's devices to guests, Beagle hardware Linux types into its shell through a USB keyboard Glint emulates
C Crystal's standard library §2.5, §3.6, §4.3–4.4 (user programs) User processes, Glint's system calls, a Crystal target, the Boehm collector, fibers Crystal's spec/std passes on Glint
S Small targets §2.1, the library organization Zephyr as the EFI provider on BeagleConnect Zepto (Cortex-M0+, 16 KiB RAM): UART, I2C, a testbench on BeagleY-AI The shell, with an i2c command, on BeagleConnect Zepto

Open questions for the maintainer

  1. Phase 6's first Zephyr provider, and the Zephyr pin. Slice 6.10 names virtio-blk, but Zephyr's virtio-blk driver (drivers/disk/virtio_blk.c) is not in the pinned v4.4.2; it arrives with v4.5.0, which is still at release candidates. NVMe (drivers/disk/nvme/) is in v4.4.2 and runs on QEMU. The choices are to move the pin to v4.5.0 before 6.10 is refined (Track S also wants v4.5.0, for the beagleconnect_zepto board), or to make NVMe the first provider at v4.4.2, or virtio-console. Z.2 compiles the NVMe sources early, so its result can inform the choice (docs/zephyr-survey.md, sections 1 and 6).
  2. Where USB lands. Answered (decision log, USB for guests is an emulated xHCI): Track U.

  3. Configuration on small targets. On MCUs the devicetree is used only at compile time, from Zephyr's own board devicetree, and the image carries no devicetree parser and no late binding (The devicetree on a small target in Track S). Its configuration symbols, though, come from the board's _defconfig and the SoC's Kconfig.defconfig. Z.6 builds autoconf.h from a short hand-checked table, and parses Zephyr's Kconfig files one at a time without following source lines. Either that approach is stretched to read a board's defaults, or Track S needs a fuller Kconfig reader (in cleave, under the plan's rule for cleave). Track S's S.2 is the first slice that has to choose.

On the back burner: the long-term home of the Linux guest build (see the decision log).

Tanenbaum check (MOS4)

Every MOS4 section cited in the phase documents was read in the maintainer's licensed copy. The copy sits outside the repository and is never committed. Results:

Decision log

The maintainer's decisions, in the order they were made. Check-in history gives the dates.