A hybrid BIOS/UEFI bootloader written entirely in Rust. Scans storage devices
and network adapters from a boot menu, PXE-boots over TFTP, chain-loads an
installed OS (FreeDOS verified) from the hard disk, and includes a
built-in no_std Lua interpreter that can run interactive shells and execute
.lua scripts fetched over the network.
Produces legacy BIOS (MBR+stage2) binaries, x86_64 UEFI and ARM64 EFI applications,
ARM64 bare-metal binaries, PCI expansion ROMs, and a native Linux x86_64 binary.
The only non-Rust code is a tiny 16-bit MBR and protected-mode entry stub in
NASM (~1.6 KB total). The firmware crates use no external crates; the native
target links only the shared common and lua crates.
- BIOS — 16‑bit MBR + 32-bit Rust stage2: menu, PCI storage scan, E820 memory map, e1000 MMIO DHCP + DNS lookup, PXE boot
- x86_64 UEFI — Pure Rust PE/COFF: SNP protocol, DHCP client, ARP resolve, DNS lookup, storage scan (GPT partitions with GUID/size/label), PXE boot
- UEFI option ROM — PCI expansion ROM with direct e1000 MMIO driver (no UEFI protocols needed during DXE)
- ARM64 UEFI — Same Rust code compiled for
aarch64-unknown-uefi(large custom stack for the Lua interpreter) - ARM64 bare‑metal — No firmware: PL011 UART, PCI ECAM walk, AHCI probe, PXE boot
- BIOS option ROM — Legacy PCI expansion ROM from
rust_payload.binviaromwrap --bios - ROM wrapper — Rust CLI tool wraps PE/COFF into UEFI PCI option ROM (
--biosfor BIOS option ROM) - Native Linux — Same menu + Lua interpreter as a host binary; the kernel handles networking (
make run-native).make luabuilds a standalonebin/luashell / script runner that skips the menu - Lua interpreter — no_std, no heap, fixed static buffers. A
[3] Lua Shellmenu entry and PXE.luascripts run the same interpreter (dhcp,fetch(),global,local, tables, functions, loops) - PXE Boot — DHCP options 66/67, TFTP client (RFC 1350), executes PE/COFF/ELF32/ELF64/Multiboot and
.luascripts - OS chain-loading —
[4] Chain to other bootloaderboots an installed OS: on BIOS, the entry stub chain-loads the active partition's VBR with a BIOS-IPL-style real-mode handoff (FreeDOS 1.4 verified); on UEFI, it enumerates the firmware's boot options and hands off to the selected entry (Debian 13 (trixie) network installer verified).make freedos-installinstalls FreeDOS ontodisks/bios.imgfrom the host in one step;make debian-netinst-isofetches the Debian netinst ISO for UEFI validation
# Install Rust targets
rustup target add x86_64-unknown-uefi aarch64-unknown-uefi aarch64-unknown-none
# Install system dependencies
# Arch: pacman -S nasm edk2-ovmf qemu-system-x86 qemu-system-aarch64
# Debian: apt install nasm ovmf qemu-efi-aarch64 qemu-system-x86 qemu-system-arm
# Fedora: dnf install nasm edk2-ovmf edk2-aarch64 qemu-system-x86 qemu-system-arm
make all # Build everything (firmware + native)
make run-x86_64-uefi # x86_64 UEFI in QEMU (e1000 NIC, full DHCP, PXE boot)
make run-aarch64-bare # ARM64 bare-metal + AHCI drive
make run-native # Run the native Linux binary (no QEMU)
make run-lua # Standalone Lua shell on the host (no QEMU)
# Boot an OS from the virtual hard disk (FreeDOS):
make freedos-iso # One-time: download the FreeDOS 1.4 LiveCD ISO
make freedos-install # Install FreeDOS onto disks/bios.img (host-side, scripted)
make debian-netinst-iso # One-time: fetch Debian 13 (trixie) network installer (UEFI validation)
make run-i386-bios # then choose menu [4] Chain to other bootloaderThe firmware run-* targets automatically start an OpenWrt VM as the
DHCP/TFTP PXE server and populate tftp-root/ with bootloader binaries, the
Lua demo (test.lua), and a test file.
| Target | Binary | Description |
|---|---|---|
make i386-bios |
bin/rust_payload.bin, bin/stage2_entry.bin |
32‑bit BIOS stage2 |
make x86_64-uefi |
bin/rustrapper.efi |
x86_64 UEFI application |
make aarch64-uefi |
bin/rustrapper_arm64.efi |
ARM64 UEFI application |
make aarch64-bare |
bin/rustrapper_arm64_bare.elf |
ARM64 bare‑metal |
make x86_64-uefi-rom |
bin/rustrapper_efi.rom |
PCI expansion ROM (UEFI option ROM) |
make i386-bios-rom |
bin/rustrapper_bios.rom |
PCI expansion ROM (BIOS option ROM) |
make native |
bin/rustrapper_native |
Native Linux x86_64 binary |
make lua |
bin/lua |
Standalone Lua shell / script runner |
make debian-netinst-iso |
debian-13.7.0-amd64-netinst.iso |
Fetch Debian 13 (trixie) network installer (UEFI validation) |
make freedos-install |
disks/bios.img (+ FreeDOS) |
Install FreeDOS 1.4 onto the BIOS disk image |
make run-i386-bios # Legacy BIOS stage2 (serial, Ctrl-A X to exit)
make run-i386-bios-rom # Legacy BIOS with PCI expansion ROM (rust_payload.bin)
make run-i386-bios-install # Boot the FreeDOS 1.4 LiveCD to install onto disks/bios.img
make run-x86_64-uefi # x86_64 UEFI (e1000 NIC, SNP protocol, full DHCP; boots rustrapper first)
make run-x86_64-uefi-debian # x86_64 UEFI with Debian 13 netinst attached (installs to a separate disk)
make run-x86_64-uefi-rom # x86_64 UEFI with custom option ROM (direct e1000 MMIO)
make run-x86_64-uefi-rom-debian # same, with Debian 13 netinst + separate disk attached
make run-aarch64-uefi # ARM64 UEFI (e1000 NIC via direct PCI scan; boots rustrapper first)
make run-aarch64-uefi-debian # ARM64 UEFI with Debian 13 arm64 netinst + separate disk
make run-aarch64-bare # ARM64 bare‑metal with AHCI drive
make run-native # Native Linux binary (runs on the host, no QEMU)
make run-lua # Standalone Lua shell (runs on the host, no QEMU)
make run-lua SCRIPT=lua/demo/test.lua # Run a Lua script on the hostAll firmware run targets except the x86_64 UEFI ones use -nographic
(Ctrl-A X to exit); the x86_64 UEFI targets open a QEMU window. All need the
OpenWrt PXE server (started automatically via pxe-start), except
run-x86_64-uefi-debian, which uses user-mode networking for the installer.
The native target runs directly on the host; type dhcp in the Lua shell to
set up networking.
Menu choice [4] Chain to other bootloader chain-loads the active partition's boot
sector the way a BIOS IPL would (LBA reads via INT 13h AH=42h, real-mode
handoff with DL = boot drive). FreeDOS 1.4 is the verified guest:
make i386-bios # builds disks/bios.img (rustrapper MBR + stage2,
# pre-partitioned: active FAT16 at LBA 2048)
make freedos-iso # one-time: fetch FD14LIVE.iso
make freedos-install # format + install KERNEL.SYS/COMMAND.COM (host-side)
make run-i386-bios # menu [4] -> FreeDOS kernel -> C:\> shellThe installed image includes a minimal AUTOEXEC.BAT that runs CTTY COM1,
so the FreeDOS shell is fully interactive over the -nographic serial console.
Two details matter for coexistence with the bootloader (see AGENTS.md gotcha 65):
- The FAT16 partition starts at LBA 2048, past the MBR's 450‑sector stage2 load area — an install whose filesystem begins at LBA 63 overwrites the bootloader on disk and the next boot triple-faults.
make freedos-installis scripted (install-freedos.sh+ the FreeDOS 1.4 boot-sector code infreedos/bootsect.bin); the interactive alternative (make run-i386-bios-install) works too, but skip the FDISK step so the pre-made LBA-2048 partition is kept, and runmake restore-mbrafterwards (it restores rustrapper's MBR code and warns if the partition overlaps the stage2 area).
Rebuilding the bootloader (e.g. make i386-bios) updates disks/bios.img's
bootloader area in place — the FreeDOS install survives. Disk images live in
disks/, which make clean never touches; make wipe-disks recreates them
blank.
Menu choice [4] Chain to other bootloader on the UEFI target enumerates the
firmware's boot options (from NVRAM BootOrder/Boot#### variables) and
presents them as a submenu, then hands off to the selected entry:
make debian-netinst-iso # one-time: fetch debian-13.7.0-amd64-netinst.iso
make run-x86_64-uefi-debian # menu [4] -> pick "UEFI QEMU DVD-ROM" -> Debian installerThe handoff uses LoadImage/StartImage when the option carries a file path,
and falls back to setting BootNext plus a cold reset for device-only entries
such as the El Torito CD-ROM image, so any firmware-listed boot target works.
Every target presents a menu:
Menu:
[1] List storage devices
[2] Boot from network
[3] Lua Shell
[4] Chain to other bootloader
Choose:
Choosing [3] opens an interactive Lua shell running the built-in interpreter.
The shell starts without networking — run the dhcp command to set it up
(establishes the network and enables fetch()):
> dhcp
local IP: 10.0.0.35
TFTP server: 10.0.0.1
true
> print(fetch("test.txt"))
21
> global booted = true
> if booted then
>> print("network OK")
>> end
network OK
The shell supports full line editing (Left/Right/Home/End/Delete),
Up/Down command history with draft restore, Tab completion of builtin/global
names, Ctrl-C to cancel the current input, Ctrl-L / clear to clear the
screen, and multiline continuation (>> ) for incomplete Lua input.
Supported: integers and floats (IEEE-754 doubles, e.g. 5.5, .5, 1e3),
strings, booleans, nil, local/global variables, + - * / %,
comparisons, and/or/not, .. concat, if/elseif/else, while,
repeat ... until, break, goto/labels, numeric for, generic
for k, v in table (or for k, v in pairs(table)), named function/return,
tables, print(), comments.
int / int stays integer (10/3 == 3); mixing in a float promotes to float,
and floats print like Lua's %.14g (5.0, 1/3.0 -> 0.33333333333333).
Calls can return multiple values (select, next, pairs), so k, v = next(t) walks a table (assigning t[k] = nil removes the field) and
local a, b, c = select(1, x, y, z) binds several.
Builtins:
_VERSION— the interpreter version string,"Lua 5.5"next(t [, k])— return the next key/value pair of a table (ornilat the end);next(t) == niltests for an empty tablepairs(t)— thenextfunction plus the table, forfor k, v in pairs(t) do ... end; a__pairsmetamethod is dispatchedprint(v1, v2, ...)— print values separated by tabs, followed by a newlinestring.byte(s [, i [, j]])— return the numeric byte codes of characterss[i..j]; defaulti=1, defaultj=i; negative indices count from the end; returns nothing if the range is emptystring.char(b1, b2, ...)— return a string made from the given byte values (each 0..255); with no arguments returns""string.dump(f)— return a binary string containing the function's bytecode and metadata (interpreter-specific format; noloadis provided)string.find(s, pattern [, init [, plain]])— find the first match ofpatternins; returns the 1-based start/end indices ornil;plain=truedoes a literal substring search; supports a subset of Lua patterns (.,%a/%d/%l/%s/%u/%w/%x/%p/%c,[set],[^set],*,+,-,?,^,$)string.format(formatstring, ...)— format arguments according toformatstring; supports%% %s %q %c %d %i %u %o %x %X %f %e %E %g %Gwith flags- + ' ' 0 #, width, and precision;%g/%Guse%.14gprecision; results over 1024 bytes errorstring.gmatch(s, pattern [, init])— return an iterator over the matches ofpatternins; yields each match's captures (or the whole match when there are no(...)captures); works in aforloop or by direct calls until it returnsnil;initdefaults to 1string.gsub(s, pattern, repl [, n])— replace up tonmatches ofpatterninswithrepl(string, table, or function) and return(result, count); in a stringrepl,%0..%9are captures and%%is%string.len(s)— return the number of bytes ins(same as#s)string.lower(s)— return a copy ofswith ASCII uppercase letters converted to lowercasestring.match(s, pattern [, init])— return the captures of the first match ofpatternins(or the whole match), ornil;initdefaults to 1string.pack(fmt, v1, ...)/string.packsize(fmt)/string.unpack(fmt, s [, pos])— pack/unpack binary data according to a format string (seehelp format-strings)string.rep(s, n [, sep])— returnsrepeatedntimes, optionally separated bysepstring.reverse(s)— return a reversed copy ofsstring.sub(s, i [, j])— return the substrings[i..j](1-based, negative indices count from the end)string.upper(s)— return a copy ofswith ASCII lowercase letters converted to uppercasetable.concat(list [, sep [, i [, j]]])/table.create(n [, m])/table.insert(list, [pos,] value)/table.move(a1, f, e, t [, a2])/table.pack(...)/table.remove(list [, pos])/table.sort(list [, comp])/table.unpack(list [, i [, j]])— the table library (concatenate, create, insert, move, pack, remove, sort, unpack)math.ceil(x)/math.floor(x)/math.maxinteger/math.mininteger/math.random([m [, n]])/math.randomseed(x)/math.tointeger(x)/math.type(x)— the math library (ceil, floor, max/min integer, random, randomseed, tointeger, type)io.close([f])/io.flush([f])/io.input([f])/io.lines([name])/io.open(name [, mode])/io.output([f])/io.read(...)/io.tmpfile()/io.type(obj)/io.write(...)— the io library, operating on the pseudo-filesystem of fetched files (read/write to in-memory files and stdout)- Embedded files (native target) — bake files into the pseudo-filesystem at build time so
io.open()/dofile()can read them without networking: setRUSTRAPPER_EMBED="name=path,..."(comma-separatedname=pathpairs; a bare path uses its basename as the name) orRUSTRAPPER_EMBED_DIR=/path/to/dir(embeds every file in that directory) when building, e.g.RUSTRAPPER_EMBED_DIR=./assets cargo build -p nativeormake native RUSTRAPPER_EMBED_DIR=./assets. Embedded files appear inlsalongside fetched ones. os.exit([code [, close]])/os.remove(filename)/os.rename(oldname, newname)— the os library (exit the interpreter; remove/rename files in the pseudo-filesystem on the native target)setmetatable(table, metatable|nil)— store/remove a table's metatable and return the table; dispatched metamethods:__index,__newindex,__eq,__lt,__le,__concat,__add/__sub/__mul/__div/__mod,__unm,__call,__tostring,__pairs; a__metatablefield protects itrawequal(v1, v2)— primitive equality, never__eqrawget(table, index)— the realtable[index]without__index(agrees withtable[index])rawlen(v)— length of a table or string without__len(a table's length is the run of integer keys from 1)rawset(table, index, value)— the realtable[index] = valuewithout__newindex; returns the table (nil/NaN indexes error)select(index, ...)— arguments afterindex(-1is the last), or the argument count whenindexis"#"tonumber(e [, base])— convert a number or numeric string to a number (ornil); withbase2..36, parse a string as an integer in that basetostring(v)— the human-readable string form of any value (same rendering asprint)type(v)— the Lua type name of a value:"nil","boolean","number","string","table", or"function"(native builtins count as functions)warn(msg, ...)— concatenate string/number arguments and printLua warning: <msg>; the control messages"@off"/"@on"toggle warningspcall(f, ...)— protected call:trueplus the results on success, orfalseplus the error object on failure (a coroutine canyieldthrough it)xpcall(f, err, ...)— likepcall, but on failure callserr(error_object)and returnsfalseplus the handler's results; the handler runs unprotectederror(v [, level])— raisevas an error object;levelis validated but ignored (no source positions)assert(v [, message, ...])— returns all arguments whenvis truthy; otherwise raises an error withmessage(default"assertion failed!")coroutine.create(f)/coroutine.resume(co, ...)/coroutine.yield(...)/coroutine.status(co)/coroutine.wrap(co)/coroutine.isyieldable()/coroutine.running()/coroutine.close(co)— real coroutines on the bytecode VM (a pool of 3;type(co)is"thread")dhcp/dhcp()— set up the network (e1000 + DHCP); prints the negotiated MAC/IP/subnet/gateway/TFTP server/bootfile, sets themac,ip,subnet,gateway,server,bootfile,tftp_port(default 69) globals, and enablesfetch()anddofile()fetch("file"[, "dest"])— download a file from the TFTP/HTTP/HTTPS server (optionaltftp:///http:///https://prefix; defaults totftp://), saving it under the optional localdestname, and return its byte count (ornil) (HTTP/HTTPS on native; HTTPS on UEFI via firmware stack)dofile("file.lua")— load a Lua chunk from the TFTP server, run it, and return its valuels/ls()— list the files downloaded withfetch(), asname (N bytes)exit— leave the shell;shell()— nested shell (not supported)
On the native target, dhcp discovers the local IP and TFTP server from the
kernel instead of running DHCP itself.
The same shell runs on the host without the boot menu: make lua builds
bin/lua. ./bin/lua starts the shell directly, and ./bin/lua script.lua
runs a script (exit status 0 on success, 1 on error, with the error message on
stderr) — handy for testing Lua scripts outside QEMU.
| Target | NIC | Method | DHCP | PXE |
|---|---|---|---|---|
| BIOS Rust stage2 (disk) | e1000 | PCI I/O ports + MMIO | Full DHCP (DISCOVER→OFFER) | TFTP download + execute (ELF32/Multiboot/.lua) |
| BIOS (option ROM) | e1000 | PCI option ROM with PCIR header | e1000 I/O BAR driver (real hardware only) | TFTP download + execute (ELF32/Multiboot) |
| x86_64 UEFI (disk) | e1000 | SNP protocol | Full DHCP (DISCOVER/OFFER/REQUEST/ACK) | TFTP download + execute (PE/COFF/.lua) |
| x86_64 UEFI (option ROM) | e1000 | Direct MMIO + I/O port PCI scan | Full DHCP (DISCOVER→OFFER) | TFTP download + execute (PE/COFF) |
| ARM64 UEFI | e1000 | Direct PCI scan + MMIO | Full DHCP (DISCOVER→OFFER) | TFTP download + execute (PE/COFF/.lua) |
| ARM64 bare-metal | e1000 | PCI ECAM + MMIO | Full DHCP (DISCOVER→OFFER) | TFTP download + execute (ELF64/.lua) |
| Native Linux | kernel | std UDP sockets | Kernel handles it (dhcp reads routing) |
TFTP download + run .lua / display |
All targets support PXE boot via DHCP options 66 (TFTP server) and 67 (bootfile name). When these options are present in the DHCP response, the bootloader automatically:
- Downloads the specified file via TFTP (RFC 1350; 512-byte blocks by default, server may shrink the block size via an OACK)
- Detects the file format by magic number (PE/COFF, ELF32, ELF64, Multiboot, Multiboot2, text, or binary)
- Executes the file if it's a recognized executable format, runs
.luafiles through the built-in Lua interpreter, or displays it if it's text
.lua scripts can call fetch("file") to pull additional files (e.g. a kernel
and initrd) from the same TFTP server; downloaded files are kept in host
memory. lua/demo/test.lua is the PXE demo script.
The run-* targets start an OpenWrt VM as the DHCP/TFTP PXE server on
10.0.0.1 (QEMU socket networking), serving the auto-generated tftp-root/
directory. This needs no root privileges and no external TFTP server.
├── common/ # no_std Rust library (print, scan, menu, e1000, dhcp, arp, dns, netio, tftp, loader)
│ └── src/
│ ├── menu.rs # Shared [1]/[2]/[3] menu logic
│ ├── print.rs # Callback-based print (putc/puts/print_hex/print_dec/print_ip)
│ ├── scan.rs # Generic device-scan loop
│ ├── e1000.rs # Direct MMIO e1000 driver (init/send/recv) — shared by all targets
│ ├── arp.rs # ARP request build + reply parse
│ ├── dns.rs # DNS query build + response parse + unicast UDP frame build
│ ├── netio.rs # e1000 glue: ARP resolve + DNS lookup + dns_resolve_and_print
│ ├── dhcp.rs # DHCP frame build/parse, IP checksum, DhcpConfig (incl. DNS server, PXE options)
│ ├── tftp.rs # TFTP client (RFC 1350) with block size negotiation (RFC 2348), streaming transfer
│ └── loader.rs # File format detection (PE/COFF, ELF32, ELF64, Multiboot, text, binary)
├── lua/ # Minimal no_std Lua interpreter (no heap, fixed static buffers)
│ ├── demo/test.lua # PXE demo script (fib, tables, fetch())
│ └── src/
│ ├── lib.rs # LuaState (~104 KB), values, errors, closures, builtins, host tests
│ ├── lex.rs # Tokenizer (ints, floats, strings, comments, symbols)
│ ├── parse.rs # Recursive-descent parser → AST
│ ├── vm.rs # Bytecode compiler + stack-machine interpreter, coroutines
│ ├── eval.rs # Runtime helpers + native builtin dispatch (print, pcall, ...)
│ └── repl.rs # Interactive shell driver (shared by all targets)
├── bios/ # Rust 32-bit BIOS stage2
│ ├── Cargo.toml
│ ├── link.ld # Link at 0x100000
│ ├── targets/i386-unknown-none.json
│ └── src/
│ ├── mbr.asm # 512‑byte MBR stage‑1
│ ├── stage2_entry.nasm # Entry stub for Rust stage2 (A20, protected mode, payload copy)
│ ├── main.rs # _start entry, menu dispatch
│ ├── serial.rs # COM1 driver (putc, getc, flush)
│ ├── vga.rs # VGA text-mode driver with scrolling
│ ├── pci.rs # PCI scan via I/O ports 0xCF8/0xCFC
│ ├── net.rs # PCI + e1000 scan, DHCP, PXE boot (thin wrapper over common)
│ ├── mem.rs # E820 map + TFTP buffer region selection (captured by the stub)
│ ├── fetch.rs # Lua `dhcp`/`fetch()`/`dofile()` host callbacks (static slots)
│ └── loader.rs # ELF32/Multiboot execution
├── uefi/ # Rust UEFI binary (x86_64 + ARM64)
│ └── src/
│ ├── efi.rs # Hand-typed EFI types, GUIDs, function offsets
│ ├── scan.rs # Storage device enumeration
│ ├── net.rs # SNP + direct e1000 DHCP client, PXE boot (uses common e1000/dhcp/tftp)
│ ├── mem.rs # UEFI memory allocation (AllocatePool/FreePool)
│ ├── loader.rs # PE/COFF execution (LoadImage/StartImage) + `.lua` scripts
│ ├── fetch.rs # Lua `fetch()` host callback (AllocatePool slots)
│ └── main.rs # efi_main entry point
├── arm64-bare/ # Rust ARM64 bare‑metal binary
│ └── src/
│ ├── pci.rs # PCI ECAM walk, BAR sizing, AHCI probe
│ ├── uart.rs # PL011 UART driver
│ ├── net.rs # PCI + e1000 scan, DHCP, PXE boot (thin wrapper over common)
│ ├── mem.rs # Fixed RAM region allocation
│ ├── loader.rs # ELF64 execution
│ ├── fetch.rs # Lua `fetch()` host callback (static BSS slots)
│ └── main.rs # global_asm! entry, UART/PCI init
├── native/ # Native Linux x86_64 binaries (std; kernel handles networking)
│ └── src/
│ ├── lib.rs # Shared lib (term/net/fetch/cli) backing both binaries
│ ├── term.rs # Raw-terminal I/O + signal-safe cleanup
│ ├── cli.rs # Standalone `bin/lua` entry: REPL or run a .lua file
│ ├── bin/lua.rs # Standalone Lua shell / script runner
│ ├── main.rs # Menu loop, storage scan via /sys/block
│ ├── net.rs # Kernel networking: gateway/IP from /proc + std UDP TFTP client
│ └── fetch.rs # Lua `dhcp` + `fetch()` host callbacks (std Mutex)
├── romwrap/ # CLI tool: wraps PE/COFF into PCI option ROM
├── freedos/ # FreeDOS install resources (bootsect.bin: FAT16 VBR code)
├── install-freedos.sh # Host-side FreeDOS install into disks/bios.img (make freedos-install)
├── tftp-root/ # Files served via the OpenWrt PXE server (auto-generated)
├── Makefile # Build orchestration
└── AGENTS.md # Full development reference & gotchas
All crates are host‑testable — platform‑specific code is guarded with #[cfg(not(test))].
cargo test --workspace # 319 tests across all crates| Crate | Tests | What's Tested |
|---|---|---|
common |
98 | Hex/decimal formatting, device info, scan loop with mocks, DHCP build/parse (incl. PXE options), ARP build/parse, DNS build/parse, subnet check, TFTP protocol, file format detection |
lua |
128 | Lexer, parser, bytecode compiler + VM, integer & float arithmetic and formatting, next/pairs/rawequal/rawget/rawlen/rawset/select/setmetatable/tonumber/tostring/type/warn/pcall/error/coroutine.*, closures/upvalues (local function, anonymous functions, shared capture, per-iteration loop capture), metamethod dispatch (__index/__newindex/__eq/__lt/__le/__concat/arithmetic/__unm/__call/__tostring/__pairs) + _VERSION, multiple values/assignment, global keyword, string.find, string.format, string.gmatch, string.gsub, string.len, string.lower, string.match, string.pack/unpack, string.rep/reverse/sub/upper, table.*, math.*, io.*, dhcp builtin, demo script output, REPL (echo, fetch, help), state-size guard |
uefi |
39 | EFI type sizes, GUID values, SNP mode layout, constants, PCI IO protocol, boot-option parsers |
arm64-bare |
21 | PCI offset encoding, storage subclass naming |
romwrap |
24 | PCIR layout, BIOS/UEFI code types, entry routine, 512-byte alignment, edge cases |
native |
2 | /proc/net/route gateway hex decode, TFTP RRQ build |
bios |
7 | E820 region selection for the TFTP buffer (min/4 GB bounds, filtering, largest region) |
- Rust with targets:
x86_64-unknown-uefi,aarch64-unknown-uefi,aarch64-unknown-none,i386-bios(needs nightly-Zjson-target-specand-Zbuild-std=core) - BIOS:
nasmandobjcopy(for assembling the MBR/entry stub and stripping the ELF to a flat binary) - Testing:
qemu-system-x86_64(with OVMF),qemu-system-aarch64(withQEMU_EFI.fd) - FreeDOS install (
make freedos-install):mtools(mformat/mcopy) andbsdtar(libarchive) to extract files from the LiveCD ISO - Native target: no extra dependencies (std only); an OpenWrt VM image is fetched by
setup-openwrt.shfor therun-*PXE server