LugalOS is a bare-metal, dependency-free microkernel operating system written in pure freestanding C11 and RISC-V assembly.
The "Microkernel" in the title was dropped for a long time while the IPC, scheduler and MMU work were aspirational, on the principle that a name should describe what the code does. It is restored as of v0.6.0 (preemptive scheduling landed in v0.7.0, separately linked user programs in v0.8.0): message-passing IPC, a real scheduler, user programs that run in U-mode from files on disk, and hardware-enforced per-task memory isolation on both memory models β PMP regions on NOMMU RISC-V (verified on real RP2350 silicon) and Sv39 page tables on the 64-bit MMU target β are implemented and continuously tested. Implementation Status below still states exactly what is and is not real, including what remains roadmap.
It is designed to scale dynamically from embedded NOMMU microcontrollers (like the RP2350 / Pico 2) up to 64-bit MMU application processors (like the Kendryte K210 and VisionFive 2).
LugalOS is early-stage. The section below reflects what's actually implemented today, not the
long-term architectural goal described in the rest of this document and in plan/ β if
a feature isn't listed here as working, treat it as roadmap, not present-tense fact.
Working today, verified by the automated test suite (tests/runner.py, 181 tests on QEMU RV32
NOMMU and RV64 MMU) and by a hardware-in-the-loop suite (tests/hw/, 14 tests against real RP2350
silicon):
- Microkernel core: preemptive scheduler with per-task kernel stacks; copy-always message channels as the IPC primitive; U-mode tasks with hardware-enforced per-task memory domains β PMP regions on the M-mode targets, Sv39 page tables on RV64, behind one interface; a syscall boundary that validates and copies every user pointer; and the console and 9P/filesystem servers running as scheduled tasks rather than inline calls.
- More than one user program at a time: each loaded program gets its own image, user stack and
memory domain, and hands all three back when it ends β including its Sv39 page-table tree on the
MMU build.
(spawn "path")starts one without waiting;execstill runs one to completion. - Ports bound to protocols at boot: a physical channel can be a console, a dedicated 9P link,
or both demultiplexed, chosen by name in
init.lispβ with one owner per wire, so binding the same UART to two protocols is refused rather than silently allowed.cat /proc/portsshows what each name is and which wire it drives. - Memory taken only while it is used: the C compiler and the editors hold their working memory (~150 KB together) on the heap for the duration of a command and return it afterwards, rather than reserving it in the image. On RP2350 that is what takes the kernel image from 434 KB to 183 KB and the heap from 60 KB to 312 KB.
- User programs larger than two pages: the image is sized from the program headers and rounded
to a power-of-two page run, with each segment granted what its ELF
p_flagsdeclare β so W^X comes from the linker rather than from the loader assuming a layout. A segment whose page count is not a power of two is granted as several NAPOT pieces. - A real process ABI: programs receive
argc/argv(built in their own stack page, so no kernel pointer crosses the boundary), return an exit status the shell and/proc/psreport, and reach named services over copy-always channels viaSYS_CHAN_CALLβ with every buffer validated against the caller's own domain. The old register-IPC entry points are deleted, their numbers permanently retired. - User programs: a separately linked ELF is loaded from the filesystem into pages the allocator
hands out, and runs as a U-mode task confined to three of them β text (R|X), data (R|W), stack
(R|W).
execis that path, so a program compiled on the machine byccruns confined too. The loader validates every header offset against the file size before using it. - Boots to an interactive shell (
lsh) on all three targets. - FAT32 filesystem engine β subdirectories,
mkdir/rmdir/cp/rm, VirtIO and physical SPI SD backends, embedded flash ROM disk, RAM disk. - The embedded Scheme/Lisp interpreter, including
define/lambda(self-recursion and the(define (fn args...) body...)signature form both work),if,begin,let,cond,quote, and around 40 built-in primitives β run(help)for the current list. - The native C11 compiler (
chibicc), producing real RISC-V ELF binaries, and the Thompsoned-style line editor. - The native RP2350 USB CDC ACM console (
/dev/ttyACM0), written from scratch against the hardware.
-
Microkernel Syscall Interface: RISC-V
ecall-routed syscall dispatch with validated copy-in/copy-out at the boundary β a user pointer is checked against the calling task's own memory domain and then copied, so the kernel never dereferences a caller-supplied address. Services are reached by message passing over copy-always channels (kernel/chan.h), which a U-mode program reaches throughSYS_CHAN_CALL; the older register-basedsys_ipc_*entry points were never more than stubs and have been deleted, their syscall numbers permanently retired. -
Plan 9 Inspired Universal Namespace: Everything is addressed through top-level resource paths:
-
/sd0/β FAT32 VirtIO persistent SD storage volume (/sd0/docs/readme.txt). -
/ram0/β FAT32 in-memory RAMDisk storage volume (/ram0/notes.txt). -
/proc/β Synthetic kernel metrics, generated on read and served as real byte streams (so a remote node can read them over 9P):/proc/ps(the live task table),/proc/meminfo(live page allocator counters),/proc/version,/proc/df,/proc/kmsg(the kernel log ring),/proc/devices(the probed device registry),/proc/buildid. -
/dev/β Hardware device nodes (/dev/uart,/dev/null,/dev/zero). -
/srv/β Named service endpoints, reached by copy-always message passing:/srv/console(the console server β anything that can write here emits on the terminal, including a remote node over 9P) and/srv/p9(this node's own 9P/filesystem server, which is what(mount-local ...)attaches).
-
-
Microkernel Core (see Implementation Status for what is not yet done):
-
Preemptive scheduler with per-task kernel stacks drawn from a real page allocator
(
kernel/palloc.c). A 100 Hz timer interrupt switches tasks at arbitrary instructions, so a task that never yields cannot monopolise the machine; tasks may also yield explicitly. The per-target timers (SIOmtime, CLINT, and Sstcstimecmp) sit behind one interface, and the RP2350 tick rate is measured at boot rather than assumed. -
Copy-always message channels (
kernel/chan.h) as the only IPC primitive. Both copies are performed even on NOMMU builds where they are provably redundant β the discipline is what lets one set of server sources be correct under both memory models, and it is why a local service and a service on another machine are the same code path. -
U-mode tasks with hardware-enforced per-task memory domains, behind a single interface
(
kernel/mem_domain.h): PMP regions on the NOMMU/M-mode targets and Sv39 page tables on RV64. A task that stores into kernel memory faults and is terminated; the kernel survives. -
Validated syscall boundary (
kernel/uaccess.h): every user pointer is checked against the calling task's own domain and then copied, so the kernel never dereferences a caller-supplied address and cannot be used as a confused deputy. -
Servers as scheduled tasks: the console and the 9P/filesystem server run as tasks rather
than inline calls. Kernel diagnostics (
printk) and user-facing output (cprintf) are separate streams, so handing a channel to a login shell does not silence the log, and detaching the log does not silence the shell.
Verifying these claims yourself β the shell exposes the same probes the test suite uses, so none of the above has to be taken on trust:
Command Shows pmpinfo/pmpdumpWhat PMP this silicon actually implements β usable regions, granularity, and a per-register dump. On RP2350 it reports 8 configurable regions and a 32-byte granule. usertestA task really dropping to U-mode. Asserted on the hardware-set trap cause (8 = ecall from U-mode), which the kernel cannot fake. isolationtestA U-mode task storing into kernel memory: it faults, the task is terminated, and a canary in kernel .datais verifiably untouched.deputytestA U-mode task asking the kernel to write kernel memory on its behalf: refused β while a pointer the task does own still works. taskdemoTwo tasks interleaving at explicit yield points, which is what distinguishes real switching from a no-op yield. preempttestA task that never yields still gets switched away from. This cannot pass without a timer interrupt, which is exactly why it exists separately from taskdemo.klog detach consoleKernel diagnostics stop reaching the terminal while the shell keeps working. -
Preemptive scheduler with per-task kernel stacks drawn from a real page allocator
(
-
Storage Engine & VirtIO Block Device:
- Native FAT32 filesystem engine supporting 32-bit cluster allocation, subdirectories (
.,..), BPB formatting, file read/write, deletion, directory creation (mkdir), removal (rmdir), and copying (cp). - Hardware VirtIO MMIO Block Driver backed by a persistent shared disk image (
build/lugalos_sd.img) used across both 32-bit and 64-bit builds.
- Native FAT32 filesystem engine supporting 32-bit cluster allocation, subdirectories (
-
Native C11 Compiler (
chibicc): Integrated C11 compiler (cc <src.c> <dst.elf>) generating native RISC-V ELF binaries directly on LugalOS! -
Unified Lisp Machine Shell (
lsh):-
POSIX
$\rightarrow$ S-Expression Transformation: All standard POSIX shell inputs (ls /sd0,cp a b,cc src dst) are automatically transformed into Lisp S-Expressions ((ls "/sd0"),(cp "a" "b")) and executed directly by the core Lisp engine! -
Complete Scheme / Lisp Core: Full support for
define,lambda,quote('),if,begin,let,cond, arithmetic (+,-,*,=), memorypeek/poke, and string data types. -
System Boot Scripts: Automatically loads
/sd0/system/stdlib.lispand executes/sd0/system/init.lispat system startup. -
Dual-Mode Interactive Line Editor & Emacs Multi-Line Canvas: Single-line editing with ANSI escape sequences (
Ctrl-A/E/K/L/P/N, Arrow keys, Delete), clean session history logging, and a full Emacs-style multi-line editor (e [filename]orCtrl-X Ctrl-M) featuring a top optical separator, line numbers (%3d β), an active status line, and keybindings:-
Ctrl-X Ctrl-E: Evaluate buffer in Lisp engine -
Ctrl-X Ctrl-S: Save buffer to active filename -
Ctrl-X Ctrl-F: Find/load file into editor (status line prompt) -
Ctrl-X Ctrl-R: Insert file at cursor position (status line prompt) -
Ctrl-X Ctrl-W: Write buffer to new filename (status line prompt) -
Ctrl-X Ctrl-C: Exit editor (prompts on status line if buffer modified)
-
-
POSIX
-
Native RISC-V ELF Compiler (
lisp-to-elf): Compiles Lisp AST S-expressions directly to native RISC-V machine code (add,sub,mul,ret) and packages them into ELF32 / ELF64 binaries on disk! -
Extended Unix Teletype Line Editor (
ed): Classic Thompson Unixededitor with current line pointerdot, line range addressing (.,$,,,%,N,M), insert (i), append (a), change (c), delete (d), print (p), numbered print (n), substitution (s/old/new/), search (/pattern/), and file I/O (e,w,f). -
Native RP2350 USB CDC ACM Driver: Bare-metal USB 1.1 device stack (
drivers/usb_cdc.c) driving the RP2350's onboard USB controller directly β no TinyUSB/Pico SDK runtime dependency. Enumerates as a composite dual-ACM device, presenting/dev/ttyACM0as a fully interactivelshconsole over the same USB cable used for flashing (mirrored alongside the physical UART debug console), with DTR-gated output so a freshly-opened terminal never receives a stale backlog of boot-time log lines./dev/ttyACM1islink_usb_cdc(plan/phase5_distributed_design.md's A3b): a real bulk 9P transport, verified against physical hardware bytests/hw/, including talking to a live QEMU node over it. -
Automated Integration Test Harness: Non-interactive QEMU PTY integration runner (
tests/runner.py) executing 75 automated test cases across RV32 (NOMMU) and RV64 (Sv39 MMU) builds (seetests/runner.pyfor the current count, as this grows over time).
lugalos/
βββ arch/riscv/
β βββ common/ # RISC-V assembly entry point, traps, ELF loader
β βββ include/arch/ # CSRs, Trap frames, VMM, ELF headers
β βββ rv32_nommu/ # 32-bit physical identity memory mapping
β βββ rv64_mmu/ # Sv39 page-table scaffolding (not yet wired up, see Implementation Status)
β βββ rp2350/ # RP2350 boot header, binary_info metadata
βββ cmake/ # Cross-compilation toolchains (RV32, RV64, RP2350)
βββ drivers/ # UART drivers (16550 / PL011 / RP2350), VirtIO Block, RAMDisk
βββ fs/ # FAT32 filesystem engine (Subdirectories, BPB) & Plan 9 VFS Server
βββ kernel/ # Microkernel main, scheduler, IPC, shell, printk
βββ libc/ # Freestanding C string library
βββ linker/ # Linker scripts (QEMU virt RV32/64, RP2350 XIP Flash)
βββ tools/ # SD root template, FAT32 disk image generator, UF2 packager
βββ user/
βββ chibicc/ # Native C11 compiler (`chibicc`)
βββ ed/ # Extended Unix teletype line editor (`ed`)
βββ lisp/ # Scheme REPL & RISC-V S-expression ELF compiler
LugalOS uses a single, unified 64-bit cross-compiler toolchain (riscv64-elf-gcc) for all targets (both 64-bit MMU and 32-bit NOMMU / RP2350). The 64-bit toolchain target compiler compiles 32-bit RISC-V code cleanly via -march=rv32imac_zicsr_zbs -mabi=ilp32.
riscv64-elf-gcc(Unified 64-bit cross-compiler toolchain)cmakeandninjapython3(for FAT32 SD disk image pre-population and Flash ROMDisk generation)qemu-system-riscv32andqemu-system-riscv64
sudo apt update
sudo apt install gcc-riscv64-unknown-elf cmake ninja-build python3 qemu-system-miscbrew install riscv64-elf-gcc cmake ninja qemu python3cmake -B build/rv32 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-rv32-nommu.cmake
ninja -C build/rv32
./scripts/run-qemu-rv32.shcmake -B build/rv64 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-rv64-mmu.cmake
ninja -C build/rv64
./scripts/run-qemu-rv64.shLugalOS boots on the Raspberry Pi Pico 2 (RP2350 RISC-V Hazard3 core). The interactive lsh console is reachable two ways: over a CP2101/CP2102 UART-to-USB adapter wired to GPIO0/GPIO1 (below), or natively over the Pico 2's own USB port via the onboard USB CDC ACM driver β no extra adapter needed. Both are mirrored to the same shell session.
| Component | Details |
|---|---|
| Raspberry Pi Pico 2 | RP2350 board (Hazard3 RISC-V core) |
| USBβSerial adapter | CP2101 or CP2102 (3.3 V logic, 5 V power out) |
| 4 jumper wires | Femaleβfemale or as appropriate |
CP2101 Adapter Raspberry Pi Pico 2 (RP2350)
ββββββββββββββ βββββββββββββββββββββββββββββ
5V βββββββββββΊ Pin 40 VBUS (powers the board via onboard 3.3V regulator)
GND βββββββββββΊ Pin 38 GND (common ground)
TXD βββββββββββΊ Pin 2 GPIO1 (UART0 RX β CP2101 transmits β RP2350 receives)
RXD βββββββββββ Pin 1 GPIO0 (UART0 TX β RP2350 transmits β CP2101 receives)
Note: CP2101 signal levels are 3.3 V β connect directly to GPIO0/GPIO1 without level shifters.
Do not connect the adapter's3V3output to anything;5V β VBUSis the sole power source.
βββββββββββββββββββββββββββββββββββββββββ
β [USB] β
β β
β Pin 1 GPIO0 UART0 TX ββββ RXD β
β Pin 2 GPIO1 UART0 RX βββΊ TXD β
β Pin 3 GND βββΊ GND β
β Pin 6 GPIO4 I2C0 SDA βββΊ SDA β
β Pin 7 GPIO5 I2C0 SCL βββΊ SCL β
β ... β
β Pin 14 GPIO10 SPI1 SCK βββΊ CLK β
β Pin 15 GPIO11 SPI1 MOSI βββΊ MOSI β
β Pin 16 GPIO12 SPI1 MISO βββ MISO β
β Pin 17 GPIO13 SPI1 CS βββΊ CS β
β Pin 38 GND (alt GND) β
β Pin 40 VBUS 5V input ββββ 5V β
βββββββββββββββββββββββββββββββββββββββββ
MicroSD Module Raspberry Pi Pico 2 (RP2350)
ββββββββββββββ βββββββββββββββββββββββββββββ
VCC βββββββββββΊ Pin 36 3V3(OUT) / VBUS
GND βββββββββββΊ Pin 18 GND
CLK βββββββββββΊ Pin 14 GPIO10 (SPI1 SCK)
MOSI βββββββββββΊ Pin 15 GPIO11 (SPI1 MOSI)
MISO βββββββββββ Pin 16 GPIO12 (SPI1 MISO)
CS βββββββββββΊ Pin 17 GPIO13 (SPI1 CS)
DS1307/DS3231 RTC Module Raspberry Pi Pico 2 (RP2350)
ββββββββββββββββββββββ βββββββββββββββββββββββββββββ
VCC βββββββββββΊ Pin 36 3V3(OUT)
GND βββββββββββΊ Pin 38 GND
SDA βββββββββββΊ Pin 6 GPIO4 (I2C0 SDA)
SCL βββββββββββΊ Pin 7 GPIO5 (I2C0 SCL)
Internal pull-ups on GP4/GP5 are enabled by the driver, so no external pull-up resistors are required. The same bus reaches the RTC at
0x68(i2c_rtc.c) and, if present, an AT24C32 EEPROM at0x57(at24c32.c) β(i2c-scan)lists whatever actually responds.
cmake -B build/rp2350 -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-rp2350.cmake \
-DLUGALOS_TARGET=RP2350
ninja -C build/rp2350
# Generates: build/rp2350/lugalos.uf2-
Hold BOOTSEL button on Pico 2 while plugging in USB (or while powering on via CP2101 5V).
The board mounts as a USB mass storage device calledRP2350. -
Copy the UF2 firmware:
# Linux cp build/rp2350/lugalos.uf2 /media/$USER/RP2350/ # macOS cp build/rp2350/lugalos.uf2 /Volumes/RP2350/
After the first flash, this is automatic. The firmware implements the Arduino-style "1200-baud touch": opening the console CDC port at 1200 baud and dropping DTR makes the device reboot itself into BOOTSEL via the bootrom, so no button press is needed.
cd tests/hw
uv run flash.py --verify # touch -> wait for the volume -> copy -> confirm /proc/buildid--verify compares the board's /proc/buildid against what the local tree builds, which turns
"the board is running older firmware" into an explicit message instead of a confusing test failure.
The bootstrap flash still has to be manual, because firmware that predates the touch cannot respond
to it.
- The Pico 2 will flash, reboot automatically, and start LugalOS.
Via the CP2101/CP2102 UART adapter:
# Linux
picocom -b 115200 /dev/ttyUSB0
# macOS
picocom -b 115200 /dev/tty.usbserial-*Or, with no extra adapter, directly over the Pico 2's own USB port once it enumerates as a composite CDC ACM device:
# Linux
picocom -b 115200 /dev/ttyACM0
# macOS
picocom -b 115200 /dev/tty.usbmodem*/dev/ttyACM0 (Linux) or /dev/tty.usbmodem* (macOS) carries the same interactive lsh session as the UART console above (output is mirrored to both). Output only starts flowing once the terminal asserts DTR (i.e. once something actually opens the port), so connecting doesn't dump a backlog of boot-time log lines. /dev/ttyACM1 / the second CDC ACM interface is link_usb_cdc β a real 9P transport, not a console; see tests/hw/ for hardware-in-the-loop tests exercising it (including bridging it to a live QEMU node). The p9share shell command offers the same coexisting-9P-and-console story over the single physical UART instead, for a one-cable setup.
Expected output after boot:
LugalOS Lisp Machine v0.6.0 (build 152.3ce6e4e2)
[Dev] Registry: rtc, eeprom, usb, uart, uartslip, uartdemux, usbnet
[PAlloc] Page allocator: 18 pages of 4096 bytes at 0x2006e000 (72 KB)
[9P Chan] Local 9P server endpoint '/srv/p9' online (copy-always IPC).
[Sched] Cooperative round-robin scheduler online (max 8 tasks)
lsh>
The build system automatically invokes tools/elf2uf2_rp2350.py which:
- Reads
_startand_stack_topsymbol addresses from the ELF - Embeds a valid PICOBIN IMAGE_DEF block (RP2350 BootROM metadata) into the boot2 Flash region
- Generates a standard UF2 file with correct per-family block counters (
0xE48BFF5Acode,0xE48BFF57IMAGE_DEF)
lsh> mkdir /sd0/projects
lsh> cp /sd0/hello.c /sd0/projects/hello_copy.c
lsh> ls /sd0/projects
Name Size (Bytes) Attr Type
---------- ------------ ----- -----
. 0 0x10 <DIR>
.. 0 0x10 <DIR>
HELLO_CO 82 0x20 <FILE>
lsh> cat /sd0/projects/hello_copy.c
#include <lugal.h>
main() {
printf("Hello from LugalOS FAT32 Storage!\n");
}lsh> ed /sd0/hello.c
'/sd0/hello.c': 82 bytes (5 lines)
:1,$n
1: #include <lugal.h>
2:
3: main() {
4: printf("Hello from LugalOS FAT32 Storage!\n");
5: }
:3c
printf("Hello from Extended ed Editor!\n");
.
:1,$n
1: #include <lugal.h>
2:
3: printf("Hello from Extended ed Editor!\n");
4: printf("Hello from LugalOS FAT32 Storage!\n");
5: }
:w
'/sd0/hello.c': 121 bytes written
:qlsh> e /sd0/math.lisp
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1 β (define (factorial n)
2 β (if (= n 0)
3 β 1
4 β (* n (factorial (- n 1)))))
5 β (factorial 6)
βββ /sd0/math.lisp βββββββββββββββββ C-X C-E: eval | C-X C-S: save | C-X C-C: exit βββ
=> 720
The LugalOS kernel hosts an embedded Lisp Machine Engine that serves as the microkernel's primary execution engine, REPL, and interactive shell environment (lsh).
(define var val)/(define (fn args...) body...): Binds global symbols and procedure signatures.(lambda (args...) body...): Constructs anonymous procedure closures.(quote expr)/'expr: Prevents evaluation of literal S-expressions and lists.(if condition then-expr else-expr): Evaluates conditional branches.(begin expr1 expr2 ...): Evaluates sequential expressions, returning the value of the final S-expression.(let ((var val) ...) body...): Establishes local lexical bindings.(cond (clause1) (clause2) ... (else default)): Multi-branch conditional selection.
+, -, *, /, =, <, >, <=, >=
(read-file path): Reads content from Plan 9 VFS into a string.(write-file path content): Overwrites file content on Plan 9 VFS.(load path): Evaluates a.lispsource file from disk (e.g.(load "/sd0/system/stdlib.lisp")).
(ls path): Performs directory listing across/flash0/,/sd0/,/ram0/,/proc/,/dev/,/srv/.(mkdir path): Creates directory in FAT32 storage engine.(rm path): Removes file from VFS.(cp src dst): Copies file content between VFS locations.(cat path): Reads and prints file content to UART console.(ps): Displays the live task table (/proc/ps) β real scheduler state, including thep9srvserver task.(meminfo): Displays live page-allocator counters β pages total, free and used (/proc/meminfo).(df): Displays mounted volume capacity and cluster usage (/proc/df).(top): Displays system process, memory, and storage monitor dashboard.
(time): Returns monotonic milliseconds elapsed since system boot.(date): Returns ISO 8601 formatted date and time string.(set-date "YYYY-MM-DD HH:MM:SS"): Updates LugalOS clock and persists to DS1307/DS3231 RTC hardware.(i2c-scan): Scans I2C bus (I2C0onGP4SDA /GP5SCL) and outputs responsive slave matrix.(eeprom-read [offset] [len]): Reads non-volatile string from AT24C32 4KB I2C EEPROM (0x57//dev/eeprom).(eeprom-write offset string): Writes persistent string to AT24C32 4KB I2C EEPROM.(p9-loopback payload): Evaluates 9P2000 RPC round-trip over in-memory transport gateway (/srv/p9_loopback).
These exist so that policy β which hardware is used, which link serves 9P, who owns the terminal β
lives in init.lisp rather than being compiled into the kernel.
(devices): Prints the probed device registry (same content as/proc/devices).(dev-present? "name"): Whether this board actually has a device β lets a boot script branch on the hardware instead of on which target it was built for.(klog-sinks),(klog-detach "console"),(klog-attach "console"): Inspect and rebind kernel-log output. Detaching stops diagnostics reaching the terminal without silencing the shell; the log keeps accumulating in the ring either way, readable via/proc/kmsg(locally or over 9P).(console-device),(console-bind "uart"|"usb"): Which device owns the interactive console, and hand it to another one at runtime.(mount-local "name"): Attach this node's own namespace at/name/through the local 9P channel β/name/sd0/xreaches the same bytes as/sd0/x, having crossed serialized frames and the copy-always channel. Mostly a demonstration that a local server and a remote one are the same code path.(mount-remote "name" ["device"]),(unmount "name"): Attach a peer's namespace over a named 9P link (omit the device to use this board's default).(p9-serve "device"),(p9-unserve "device"): Serve inbound 9P on a named link.(spawn-pump n): Spawn a task that services background 9P links and yields. Exists to make the client/server concurrency hazard genuinely reachable in tests.
(cc src dst): Invokes nativechibiccC11 compiler on VFS C source files.(exec path): Loads and executes native RISC-V ELF binaries in supervisor space.
On boot, LugalOS initializes the Lisp Machine engine and executes the boot lifecycle:
- Loads
/sd0/system/stdlib.lisp(standard library extensions written in pure Lisp). - Executes
/sd0/system/init.lispto initialize system settings and launch startup tasks.
LugalOS is licensed under the MIT License.
- Microsoft UF2 Tools:
tools/uf2conv.pyandtools/uf2families.jsonare sourced from Microsoft UF2 (USB Flashing Format) (MIT License), providing standard UF2 block conversion and family ID registry lookups. - Raspberry Pi Picotool:
tools/picotoolis sourced from the Raspberry Pi Picotool Repository (BSD 3-Clause License), used for RP2350 image analysis, partition table parsing, and binary validation. - Igor Michalak's bare-metal-rp2350: Reference bootloader headers, RISC-V XOSC/PLL clock tree setup, and dual-core reset patterns from
bare-metal-rp2350. - hathach's TinyUSB: The native RP2350 USB CDC ACM driver (
drivers/usb_cdc.c) was implemented and debugged against DPRAM/endpoint-control register layouts and buffer-control write ordering cross-checked fromrp2040_usb.c/usb_dpram.h(MIT License) β no TinyUSB code or runtime is linked into LugalOS; the USB device stack is written from scratch directly against the hardware. - Rui Ueyama's chibicc: C11 compiler architecture adapted from
chibicc(MIT License). - Ken Thompson & Bell Labs: Unix
edteletype editor and the Plan 9 Operating System universal namespace model.