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:
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→ /pikchrshow
- 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.
- Compiled-in Zephyr drivers (performance). Upstream Zephyr C drivers are
built against
compat/zephyrand 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. - 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.
- 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.
- Hosted mode. Glint stays in boot services and uses EFI timer events,
AllocatePagesand firmware protocols, with cooperative scheduling. It runs anywhere, slowly, and on U-Boot everything is polled. It turns the watchdog off. Zephyr providers can replace firmware drivers here (DisconnectController+ driver binding), but they must poll. - Native mode. Native mode begins when Glint calls
ExitBootServicesand owns the machine. It keeps EFI runtime services and the hardware description, and the files it loaded before the exit. It begins with only a console: Zephyr's own UART driver, compiled in throughcompat/zephyrby Track Z (PL011, asarm,sbsa-uart, on QEMUvirt; NS16550 by I/O port onq35), in poll mode until interrupts arrive in Phase 6. Glint writes no UART driver. It runs only on a machine whose firmware description matches a class Glint was built for (principle 6). It gains a timer, the interrupt controller, storage and preemptive scheduling phase by phase: exceptions in Phases 2 and 4, the MMU in Phase 3, interrupts in Phase 6, scheduling in Phase 8. It is complete once compiled-in providers cover the essentials (console, timer, interrupt controller, storage). - Hypervisor mode (native, plus a Linux guest): the mode Glint is built
around. Glint must own the
virtualization level: EL2 on Arm, VMX/SVM root on x86. On BeaglePlay
and BeagleY-AI, Glint is entered at EL2: TF-A hands over to U-Boot "at
the highest available Exception Level (EL2 if available, otherwise EL1)"
(TF-A firmware design),
and U-Boot's EFI launch (
do_bootefi_execinlib/efi_loader/efi_helper.c) drops only from EL3 to EL2. It goes lower only withARMV8_SWITCH_TO_EL1, which neither board's configuration sets. The plan proceeds on that basis: slice 2.2 reports the level under QEMU, and 13.2–13.3 confirm it on the boards. The A53 cores in AM62x/AM67A are Armv8.0 with no VHE, so Glint at EL2 runs as a classic split-mode hypervisor.
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:
- Real PCs have all of these. The 8259 and PIT stay in chipsets for old
software. (Not checked against a chipset datasheet; QEMU's
q35, which copies one, models all four.) - Not interchangeable. The IOAPIC and the 8259 have different registers
(QEMU 11.1.2
hw/intc/ioapic.cuses an index/data window in memory;hw/intc/i8259.cuses I/O ports), and so do the HPET and the PIT. The HPET can take over the PIT's interrupt (its legacy mode,hw/timer/hpet.c), but a guest still has to drive it differently. - One CPU: a guest loses little. The 8259 has 15 lines, more than Glint's few devices need. Its cost is an I/O exit to end each interrupt, where the IOAPIC's would be a memory exit.
- Several CPUs (Phase 8): the 8259 can't send interrupts to other CPUs.
Devices would use MSI, where a device signals by writing to an address;
Glint makes that write itself on the emulated device's behalf, so no
decoding is needed. But MSI needs a capability in PCI configuration
space, which 5.5 left out, and MSI-X, whose table sits behind a memory
BAR (
hw/virtio/virtio-pci.c), stays out under A. - Linux's timer: each CPU's local APIC timer. Linux measures its rate at boot against the PIT or HPET, so without an HPET the PIT has to be good enough for that, or Glint tells the guest the rate through CPUID. (Not checked: Linux's source isn't in the workspace; 6.7b shows it.)
- Changing course later: adding an IOAPIC or HPET means decoding the guest's instruction on each access. Linux reaches both with plain 32-bit moves, so that decoder would be small, but it is what A chose to avoid.
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:
- 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).
- 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).
- 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).
- 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:
- The build driver is a Crystal program,
tools/glint_build.cr, built as the shard executablebin/glint-build. It callscrystal,clang,ld.lldandllvm-objcopy. This is the plan's one statement of how Glint's images are made. They are compiled as ELF (LP64, GNU C) and linked byld.lldwith Glint's own linker script (boot/efi.lds). Their PE32+ header and.relocdirectory are assembled inboot/crt0.S, whose entry code applies the ELF relocations (c/efi_reloc.c) beforeefi_main: the method Linux and U-Boot use for EFI programs. On x86_64, calls into UEFI go through Microsoft-ABI thunks in one boundary (c/efi_boundary.c,boot/efi_boundary.cr), andcrt0.Sconverts firmware's call intoefi_main, since UEFI uses the Microsoft x64 convention and ELF code System V. This replaces the*-unknown-windows+-subsystem:efi_applicationmethod of BQ2'sEfiAppBuilder(src/efi_app_builder.cr), which Phase 1 followed: that target is LLP64 with MSVC preprocessor behaviour, and Zephyr's C miscompiles under it (docs/zephyr-survey.md, risk 1). Slice Z.1 built and proved it on Phase 1's images. - Image code runs without Crystal's start-up. Firmware calls
efi_maindirectly, so the program's top-level code never runs. A constant whose value needs computing, a class variable with an initialiser, and a statement in a module or class body are all silently left zeroed. Image code builds such values at call time instead, asboot/efi.cr's GUID methods do. Host specs run Crystal's normal start-up and cannot see the difference; 2.3's type names and 2.4a's devicetree GUID both failed this way, only on real boots.spec/image_initialization_spec.crchecks the linked image for start-up initialiser symbols, and the image's sources with Crystal's own parser. The shell's bytecode (P.4b) was a third case, broken since 1.8 because no boot test typed a command. - Zephyr's build system is not used. West, CMake scripts,
gen_defines.py/edtlib, Kconfiglib,gen_syscalls.py,gen_offset_header.pyand the linker-script generators are all Python, CMake or both. Glint replaces the parts it needs with Crystal, starting from cleave (MIT, Crystal ≥ 1.18.2), which already has:Cleave::Dts+Cleave::Dtc: dtc 1.7 semantics, DTBs byte-identical to dtc across Linux 6.12's 266 arm64 DTBs and U-Boot 2025.07. Preprocessing isclang -E, as kbuild does it;Cleave::Fdt: DTB read and write. Glint needs both inside the kernel: to read firmware's DT, and to build the guest's DT at run time. There, Glint's prelude has no GC and no fullString/Hash. So either the kernel prelude grows enough forCleave::Fdt, or the kernel gets a small allocation-free reader that is checked againstCleave::Fdtin specs. Glint takes the second way, with a reader (2.4a) and a writer (6.5) of its own, until the prelude can run cleave's;Cleave::Kconfig: Linux 6.12, U-Boot and Zephyr (Kconfiglib) Kconfig parsing, the$(...)preprocessor with Kconfiglib's functions and a hook for the devicetree ones, and.config/autoconf.hreading and writing;Cleave::Fat16andCleave::Elf: the ESP image for QEMU tests, and loading ELF payloads. Glint uses cleave as a shard dependency, so Glint does not keep a copy of that code. Fixes go upstream into cleave. What remains for Zephyr:- answers to the
$(dt_*)preprocessor functions (dt_compat_enabled,dt_node_reg_addr_hex, …), which query the build devicetree. Cleave's Zephyr dialect takes them through a hook, and itsFdtcan answer them; - a
devicetree_generated.hgenerator (in place ofgen_defines.py/edtlib) that reads Zephyr's YAML bindings with Crystal's YAML (libyaml). This is the largest new piece; - the
zephyr/syscalls/*.hstubs that Zephyr headers include (in place ofgen_syscalls.py), or a shim that makes them unnecessary whenCONFIG_USERSPACE=n; offsets.hand linker-script fragments, made from Crystal templates. Zephyr C files are then compiled directly with clang from a source list kept in Crystal. Track Z builds early, limited forms of the devicetree-header generator,autoconf.h(from a checked symbol table) and the syscall stubs, enough for two poll-mode UARTs. Which Phase 6 slices extend them is stated once, in Track Z's What Track Z leaves. The full Kconfig tree is needed only by Track S. If cleave (or BQ2) is the better home for the new generators, they go there.
- The Linux guest is an input, not a build product. Building Linux needs
flex, bison and more, so Glint's build never builds Linux. The guest
Imageand initramfs come in as pinned, checksummed artifacts, built for now by cleave, which owns the Linux build. The guest DT is generated by Glint at run time with its own FDT writer (6.5). - QEMU and its firmware are built inside this project, under the same BQ2-only rule (see the next section).
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:
- Clarity (can be stated): "The objective and its boundaries must be explicit and unambiguous so that code can be judged against it." In Glint this covers a slice's stated claim, written boundaries such as the threat model, and assumptions recorded beside the code that relies on them.
- Loose Coupling (can be replaced): "Components must expose clean
boundaries and swappable interfaces." In Glint this is the platform
interface with swappable providers, the
compat/zephyrseam, the guest ABI, and using other projects' tools only through their interfaces. - Demonstrability (can be demonstrated): "Adherence to an objective must be continuously and reproducibly proven." In Glint this is the demonstration ladder and the evidence in every check-in.
- Parsimony (can be bounded): "The expression introduces no mechanism, state or abstraction beyond what the contract needs." In Glint this is the slice size limit and Tambassi's review questions below, including reusing one implementation instead of writing a second.
Principles
- 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.
- 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.
- 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 speccovers it on Linux. A fake EFI system table in Crystal lets the specs exercise the platform interface without firmware. - 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). - Zephyr code linked in; Linux run on top.
compat/zephyrimplements kernel objects (k_thread,k_sem,k_mutex,k_msgq,k_work,k_timer,k_spinlock),struct deviceandDEVICE_DT_*. The generated devicetree macros andautoconf.hcome from Glint's Crystal tools (see Build constraints). Its C headers declare the API and Crystalfunexports implement it. The Zephyr source is an external tree, not a copy in the checkout: the build finds it throughZEPHYR_SRCand checks it against the upstream commit recorded inthird_party/zephyr/PIN.md, beside which any patches are kept as separate files and applied by Crystal code or BusyBoxpatch(Track Z states the pin). Linux is used only as an unmodified, prebuilt guest kernel image, pinned by checksum inguest/linux/. - 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/orsoc/directories. SoC support comes from firmware in hosted mode, from upstream Zephyr drivers matched by devicetreecompatible, 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.
- 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".
- 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):
- Demonstrability. The book describes one running system "line by line" (§13 Summary). Every passage points at code that compiles and runs, and every Glint slice must be demonstrable in the same way.
- Parsimony. xv6 is a few thousand lines that one reader can hold in their head. Its whole argument is built on keeping interfaces "simple and narrow" (§1; see Phase 1).
- Clarity. Its chapter order is a build order: interfaces → organization and boot → page tables → traps → page faults → interrupts and drivers → locking → scheduling → sleep/wakeup → file system → logging → concurrency. Each Glint phase opens with the passage that states its purpose, and the citations progress from earlier passages to later ones.
- Loose coupling. §2 frames the monolithic/microkernel trade-off as being about which code needs privilege. Glint's answer is a small privileged core, with Linux and Zephyr code behind seams. The book states the cost of the other choice in one sentence: monolithic kernels grow until "no one developer understands all of the interactions between different parts of the code; this is a recipe for bugs" (§2.3).
- Licence. The book source is under an MIT-style licence. That is not Creative Commons, but it is more permissive than CC BY-SA, so passages can be quoted in Glint's repository and check-in comments without restriction.
Alternatives considered:
- Modern Operating Systems (Tanenbaum & Bos): the broadest scope and influence, including chapters on virtualization and I/O. But it is proprietary, so its passages can't be reproduced in the repository or checked by a reader who doesn't own the book, which weakens Demonstrability. Its chapter order is a survey order, not a build order.
- Operating Systems and Middleware: Supporting Controlled Interaction (Hailperin, CC BY-SA 3.0): the best CC-licensed option. It covers virtual machine monitors (§7.5.2 "Protection of Entire Simulated Machines") and has a security section in every chapter. But it is conceptual rather than code-led, has no boot or device-driver chapter, and its order (threads → scheduling → synchronization → transactions → VM → processes …) would make citations jump around. It is less influential.
- Operating Systems: Three Easy Pieces (Arpaci-Dusseau): free to read, all rights reserved.
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:
- One slice, one check-in, one idea. It builds both EFI images
(aarch64 and x86_64),
crystal specpasses, and nothing earlier regresses. - 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.
- 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.
- Through declared seams only (Loose coupling). A slice touches other
parts only through the platform interface,
compat/zephyror the guest ABI. A slice that needs a new seam adds it as its own slice first. - Demonstration ladder. Each slice is demonstrated at the highest rung
it can reach:
crystal specon Linux against the fake EFI system table;- a check of the built EFI images (PE32+ headers, sections, relocations);
- a headless boot under the project-built QEMU + U-Boot (once track T delivers), passing on an expected serial line;
- real hardware (BeaglePlay, BeagleY-AI, an x86_64 PC).
- 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.
- 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.
- As-built index.
docs/TUTORIAL.mdlists 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. - 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.
- 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, asdocs/WORKFLOW.mddescribes.
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
- 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 thebeagleconnect_zeptoboard), 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). Where USB lands. Answered (decision log, USB for guests is an emulated xHCI): Track U.
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
_defconfigand the SoC'sKconfig.defconfig. Z.6 buildsautoconf.hfrom a short hand-checked table, and parses Zephyr's Kconfig files one at a time without followingsourcelines. 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:
- Confirmed and stronger than claimed: §7.5 (the small privileged core; a precedent for the provider model), §7.7 (Device Domains is Glint's driver domain; the I/O MMU subsection bears on DMA without an IOMMU), §12.2.1 (the parsimony principles, agreeing with Tambassi and xv6 §1).
- Confirmed: §§1.5, 1.6, 1.7.3, 2.3.1–2.3.2, 2.3.4, 2.3.8, 2.4, 3.3, 3.6.2, 4.3.6, 4.3.7, 5.1.4, 5.1.5, 5.2.2–5.2.4, 5.3.2, 5.5, 6.6.4, 7.2, 7.4.1, 7.6, 7.9, 8.1.3, 8.1.4, 1.4.6, ch. 8, ch. 9, ch. 12.
- 5th edition, partly checked: the publisher's public preview of the 5th Global Edition (front matter to §2.1) confirms MOS5 §§1.3.6 (now UEFI boot), 1.4.5, 1.5, 1.6 and 1.7.3. The rest of the 5th edition is unchecked.
- Corrected: MOS4 §1.3.6 covers legacy BIOS boot only, so §11.3.2 (where UEFI appears) was added. The caching reference was narrowed from §4.4 to §4.4.4. §4.5.1 (FAT) was added.
Decision log
The maintainer's decisions, in the order they were made. Check-in history gives the dates.
- Glint goes beyond being inspired by Zephyr and Linux: it runs portions of their code.
- No BSPs for SoC targets.
- "Use EFI to run on any target, then use code compiled from Zephyr and Linux to provide more optimal performance. For ultra-small targets, some Zephyr code can stand in for EFI." This produced the EFI-shaped platform interface with swappable providers, the run modes and Track S.
- No Linux code is linked in. The Linux kernel runs on top as a guest, so its drivers can be used, and the GPL/Apache linking conflict does not arise.
- "This OS should look more like a hypervisor to Linux." This produced What Linux sees, with hypervisor bring-up following native mode directly.
- No Python, flex, bison or other extra dependencies: the
bootstrap-qcow2toolset must be enough to build Glint. - cleave is reused for Kconfig, devicetree and FAT.
- QEMU and its firmware are built within this project (Track T).
- QEMU's generators are ported by working from the data they read and its specification. Python output is an oracle only where the knowledge exists only as Python. U-Boot with EFI replaces EDK2. The reduced QEMU covers both aarch64 and x86_64. The generator ports stay in Glint.
- SVM first for x86 hypervisor mode; VMX emulation is to be worked out later.
- Development is organized into crystal-robots-style slices in phases following one text. That text is the xv6 book ("MIT licensing is friendly"). Tambassi's account of parsimony supplies the slice review questions.
- Hailperin and Tanenbaum are cited alongside xv6 wherever they apply, with a rationale relative to all three. The 4th edition of Tanenbaum is the reference edition. It is checked against the maintainer's licensed copy on their behalf and never reproduced, and 5th-edition locations are given as well.
- Each phase has its own document, with its slices. Plan text carries no dates.
- Linux is used for its breadth of drivers, with Glint in charge for robustness. Four device paths are needed (pass-through, bridges, return, applications), as set out in Devices and the Linux guest.
- Unprotected DMA by a passed-through device is allowed only on explicit opt-in per guest.
- Glint stays an OS that can host guests, with native-mode fallback on machines without virtualization.
- Drivers start with what EFI provides. The small target is the BeagleConnect Zepto, with UART and I2C from Zephyr. A testbench pairs it with BeagleY-AI running a regular Linux distribution, connected over UART and SWD, with the bootstrap-loader and reset lines on GPIOs, a Rust-based programming tool and OpenOCD. Other drivers are added as needed.
- Mainline U-Boot on BeaglePlay and BeagleY-AI gives EFI applications a serial console, a devicetree, block storage and networking, but no display. PSCI comes from Arm's trusted firmware (TF-A).
- Glint is primarily for education but production worthy for daily use. A garbage collector is allowed as an isolated feature, following Crystal's choice of the Boehm collector.
- Cleave owns the Linux guest build for now.
- Track S builds on Zephyr's existing
beagleconnect_zeptoboard and the BeagleBoard Imaging Utility (bb-imager-rs) for flashing. - Glint's own code is licensed MPL-2.0. Contributions from second parties
need a Developer Certificate of Origin sign-off (see
CONTRIBUTING.md). - The long-term home of the Linux guest build is on the back burner. The ideal is for patches to land in mainline, and for BQ2 to become a build service for reproducible builds that builds mainline itself.
- EL2 entry on the Beagle boards is taken as documented (TF-A, then U-Boot's EFI launch); 2.2 reports it under QEMU and 13.2–13.3 confirm it on the boards.
- Development is done by Codex runs, with a Claude run reviewing each
slice against the virtues before merging (
docs/WORKFLOW.md). This starts once OCX gives the reviewer a route to start Codex runs. - Human-facing syntax is Crystal throughout. The shell's grammar is one
table of
Cleave::GlyphParserrules, matched inside Glint by code generated at build time from PCRE2's bytecode (Track P). The aim is ultimately to regenerate PCRE2 with the glyph parser. - Glint's scope includes OS hooks for Crystal's whole standard library,
except what is specific to another OS, validated by
spec/std, with minimal patches to Crystal (Track C). - Glint's work helps land Zephyr's MSPM0 I2C driver (pull request #117311), testing it on BeagleConnect Zepto; the maintainer reviews it upstream.
- PCRE2 is pinned strictly to 10.44, the version BQ2 builds: Track P builds it from pinned source and never uses the host's PCRE2, so the generated matcher constants are the same on every host.
- Rule 3 allows a slice over ~400 lines when splitting it further would need a temporary stub, provided its check-in comment says so (first applied to T.6a2).
- GLib is pinned to 2.88.4 (core
glibandgmoduleonly), built from source by Track T; libfdt follows QEMU 11.1.2's owndtc.wrappin. - The reduced
qemu-system-aarch64(T.8) is built for the x86_64 host this node has, with TCG only. A native aarch64-host build with KVM (for example on BeagleY-AI) comes as a later slice. - QEMU's build also runs
keymap-gen,block-coroutine-wrapper,module_blockand two small shell scripts, which the first generator table missed. They are ported under the same rules as slices T.6d, T.6e and T.6f, before T.8a finishes. - The reduced QEMU builds stay BQ2-only at link time: QEMU uses its POSIX
coroutine-sigaltstackbackend (musl has no ucontext, so no libucontext), and the out-of-line__atomic_*functions come from compiler-rt'slib/builtins/atomic.catllvmorg-18.1.7, the LLVM release BQ2 builds, compiled by Glint into a small static archive (no libatomic). - Glint's images are built as ELF (LP64, GNU C) and given their PE/COFF
header by Glint's own build, the method Linux and U-Boot use for EFI
programs, instead of compiling for
*-unknown-windows. Zephyr's C then compiles unmodified, without the 32-bitlongand MSVC-preprocessor failures the Zephyr survey found, and ELF linker scripts give Zephyr the section ordering its device and init tables rely on. On x86_64, calls into UEFI go through Microsoft-ABI thunks. Chosen by the reviewer at the maintainer's request ("you choose"); proved by a probe slice before the Zephyr seam is built on it. - USB is handled natively for standard xHCI host controllers: xHCI is a
standard interface, like PCI and virtio, so it falls under principle 6
rather than needing a BSP or a Zephyr provider. Glint owns the whole xHCI
controller and the USB tree behind it (hubs and every class of device);
guests get devices through a shim (an emulated or paravirtual USB device),
never the controller itself. USB input
is a trusted path: Glint keeps the keyboard, so the user can always reach
the hypervisor even while a guest owns the display console. (Where this
lands and what the shim is are settled by USB for guests is an emulated
xHCI, below;
docs/zephyr-survey.mdcovers what Zephyr offers for USB host.) - U-Boot, the EFI firmware for both QEMU machines (T.10), is pinned to the latest mainline release, 2026.07. Beagle seeks mainline support in U-Boot and Linux, so Glint tracks mainline releases rather than a board vendor's fork. cleave has not yet booted anything; its 2025.07 checks cover Kconfig parsing and DTB output only, so they are no reason to pin an older release, and T.10 may find cleave fixes to send upstream.
- A workaround for a toolchain bug in an upstream build is allowed only with
a minimal reproducer, a guard that fails if the upstream text changes,
and a report sent upstream, recorded in
docs/upstream/. It is removed when the fix reaches a pinned release. (First case: U-Boot's arm64.bss ADDR(.rela.dyn)under ld.lld, T.10a.) - Native mode begins at
ExitBootServices. Hosted mode stays the default boot until Phase 6; Phase 2 leaves boot services only as a demonstration. (Superseded by the entry Native from Phase 3 below.) - After the exit, the console is Zephyr's own UART driver through
compat/zephyr(PL011, or itsarm,sbsa-uartcompatible, on QEMUvirt; NS16550 by I/O port onq35), in poll mode until Phase 6's interrupts. Glint writes no UART driver. - Zephyr is pinned at v4.4.2, commit
dccb09599635bdff17633fa7e9dab014b91dce90. - The Zephyr seam comes early, as Track Z, after Track T and before Phase 2's exit demonstration, following the Zephyr survey's recommendation. Its first slice is the ELF-image probe; Phase 6's 6.8 and 6.9 extend its generators and shim rather than create them.
- Native from Phase 3. This replaces the earlier entry that kept hosted mode
the default boot until Phase 6. Phase 2 still proves leaving boot services
first as a demonstration, entered with a shell
nativecommand (2.6). From Phase 3 on, every boot first loads through EFI what it needs (its files from the ESP, guest images among them, and the final memory map) into memory of its own, then exits boot services and runs native. Hosted mode remains the fallback when 2.6's checks fail, and the mode for machines Glint cannot drive yet. The reviewer placed the preload late in Phase 2 (2.9), and the switch of default in its own slice after it (2.10), so Phase 3 starts native; Run modes holds the statement. - Zephyr's drivers are built against one build devicetree per machine class
(QEMU
virtandq35now; BeaglePlay and BeagleY-AI later), taken from upstream devicetrees as data, never code. At boot Glint checks that the firmware's description matches the class it was built for, and otherwise stays hosted. Late binding (patching addresses and interrupts into driver instances from the firmware's description at boot, for drivers where only those differ) comes later. Principle 6 says how this keeps No BSPs. - Accepted defaults:
virt's build devicetree describes the UART asarm,sbsa-uart; serial input drops escape sequences and ignores a line feed that follows a carriage return (Z.9); Phase 2 enters native mode with a shellnativecommand. - The serial console speaks UTF-8 both ways (Z.9): output encodes UCS-2 as UTF-8, and input decodes UTF-8 into keys, dropping invalid sequences, so Phase 1's non-ASCII shell example works through Zephyr's UART.
- Three Phase 6 slices extend Track Z, and no others: 6.3 (interrupt cells and interrupts), 6.8 (the generators) and 6.9 (the shim). This completes the earlier entry, which named only 6.8 and 6.9; Track Z's What Track Z leaves holds the statement.
CONFIG_MMUstays unset on x86_64 too, by one listed override in Z.6's table. Zephyr'sX86_64selectsX86_MMUand soMMU. Glint owns the page tables, and drivers use physical addresses, as on aarch64. Z.6's tables are otherwise closed underselect, and its spec prints the override.- x86 devices through I/O ports only (Phase 5). SVM reports no size or
register for a guest's access to memory, so on x86_64 guests reach Glint's
devices only through I/O ports, and Glint has no instruction decoder. On
aarch64, devices are memory-mapped, and the data-abort syndrome gives the
size and register for single-register loads and stores (QEMU 11.1.2
target/arm/tcg/translate-a64.c:iss_validis set forLDR/STRwithout writeback and clear for pairs and writeback forms), so aarch64 needs no decoder either. 5.5's virtio-pci uses virtio's legacy I/O-port BAR on x86_64 for the same reason. The maintainer chose this ("For x86, that sounds like it makes sense"), relayed in glint 366ac226de on Nov 10, 2026. USB for guests is an emulated xHCI. "Emulating the USB controller is the primary peripheral to be captured by Glint" (the maintainer, same relay). Guests see an emulated xHCI controller; Glint keeps the real controller and chooses which devices to show. xHCI because the Beagle boards' controllers are xHCI in host mode, Glint's native driver shares its data structures, guests already drive it, and QEMU has a model to test against. Under the I/O-port rule above x86_64 guests can't reach it, since xHCI's registers are only memory-mapped, so it is aarch64-only. Track U places it: U.1 after Phase 5, U.2–U.5 inside Phase 6 after 6.7b and before 6.8 (refined in Phase 6's document, Nov 10, 2026). This answers open question 2, which listed emulated xHCI among the shims.
x86 guests' interrupts. x2APIC through MSRs, the 8259 and PIT on I/O ports, no IOAPIC or HPET; plain MSI with several CPUs; timer calibrated against the PIT. Glint's design under choice A, which the maintainer left to it (glint 5c447d1377, Nov 11, 2026); the stakes are under What Linux sees.