Equinox OS is a 32-bit x86 hobby operating system with a monolithic kernel written in C++, C and NASM. It boots through GRUB Multiboot into a VESA 1360x768 linear framebuffer, runs ring-3 processes with demand paging, and — the part that defines the project — compiles its own userland from C source inside the OS with its built-in compiler, mtcc.
Beyond the kernel, the system ships with a working set of everyday OS facilities: a shell with pipes, globbing, redirection and scripting; a package manager (eggkg) that fetches, compiles and installs software from a Git-hosted package repository over HTTPS; a validated configuration system (.ecf files with a set builtin); a FAT32 disk tool (Qfs) that can format a disk and install a bootable GRUB; a TCP/IP stack with an HTTPS client and server; an LVGL desktop plus a ThorVG-powered vector desktop; and DOOM running from a demand-paged arena off the FAT32 disk.
| Release | 0.4 Beta |
| Target | i686 (32-bit), QEMU or real hardware |
| Boot | GRUB Multiboot (kernel.elf + boot modules) |
| Memory | 256 MB recommended (QEMU -m 256); 64 MB minimum |
| Language | C++17 / C / NASM |
| Display | VESA 1360x768x32, VGA text fallback |
root::users / $ equinoxinstall # the OS builds its own userland in-OS
root::users / $ mtcc /test/hello.c # compile + run C, inside the OS
root::users / $ eggkg update && eggkg install bash -y
root::users / $ grep -n printf /test/hello.c | tr a-z A-Z > /mnt/out.txt
root::users / $ mget https://github.com/octocat/Hello-World # HTTPS -> file
root::users / $ doom -iwad /mnt/doom1.wad # DOOM straight off the disk
- Overview
- Requirements
- Quick start
- Architecture
- Multitasking & process model
- Memory management
- Executable formats: MRP and ELF32
- mtcc — the in-OS C compiler
- Build recipes: ruf v3 and
mtcc -make - Self-hosting with
equinoxinstall - Packages:
eggkgand the Eggkg-l repository - Configuration:
.ecf,setand eqshell scripts - Disk management:
Qfs - System call interface (54 syscalls)
- Storage & filesystems
- Networking
- Graphics, desktop & games
- Drivers
- Shell command reference
- Building from source
- Testing
- Known limitations
- Repository layout
- Third-party components
| Area | What you get |
|---|---|
| Processes | Ring-3 user programs via TSS-based privilege transitions and int 0x80; a private page directory per task; kernel memory is unreachable from user code. |
| Multitasking | Preemptive round-robin scheduler (100 Hz), up to 8 tasks, per-task FPU state, virtual consoles (F1 / F2), spawn / wait / kill, zombies, and kernel pipes. |
| Demand paging | Task windows are reserved, not allocated. A page fault hands out one zero-filled page on first touch: a 24 MB DOOM arena costs only what DOOM actually uses. |
| Executables | MRP1 (18-byte header, checksummed flat binary) and static ELF32/i386, both loaded into the demand-paged window. |
| Compiler | mtcc: a single-pass C compiler with direct x86-32 code generation that runs inside the OS, with a 13-module libc spliced through <morph.h>. |
| Build recipes | ruf v3 .ruf files: variables with :=, $name expansion, copy / move ? to post-build actions — driven by mtcc -make. |
| Self-hosting | equinoxinstall compiles the shipped tool and game sources from C in-OS and installs the results. |
| Packages | eggkg: update / install / remove / list / search / info / sync; downloads sources over HTTP or HTTPS, builds with mtcc -make, installs to /bin, tracks them in installed.db, verifies sha256 when index.idx is present. |
| Configuration | .ecf (INI-lite) with schema validation, an overlay mechanism, and the set builtin; .es shell scripts with command logging. |
| Syscalls | 54 append-only syscalls (#1–#54): console, files, processes, pipes, memory, graphics, audio, input, networking. |
| Storage | ATA PIO driver (LBA28/LBA48, ATAPI detection, MBR), full FAT32 read/write with long file names, write-through consistency, and a RAM filesystem populated from GRUB modules. |
| Networking | lwIP 2.1.3: DHCP, DNS, ICMP, TCP. HTTP and HTTPS client (mget, BearSSL, fail-closed TLS), an in-process fetch transport for eggkg, and an HTTP server on port 80. |
| Graphics | 1360x768x32 VESA framebuffer, LVGL 8.3 apps (file manager, settings), an EquiX desktop built on ThorVG vector rendering, per-task clip windows, ANSI color output in the console. |
| Games | Snake, Breakout, Pong (self-hosted C sources) and DOOM loaded from the FAT32 disk. |
- Dynamic memory: the RAM top is read from the multiboot information instead of being hardcoded. Paging maps 16–128 MB depending on what is installed, the GUI arena grows with it, and the standard configuration is now 256 MB (the
infobanner reportsRAM: 256 MB; all makefile run targets pass-m 256). - eggkg package manager (ring-0 builtin) with the Eggkg-l repository:
package.list(format v0) + optionalindex.idx(v1: version / sha256 / size / mirrors), pure-C SHA-256 verification,/binsystem path,installed.db, reverse-dependency guards, and boot-time auto-activation of thebashpackage. .ecfconfiguration +setbuiltin: schema-validated keys (net.driver,base.path,dependencies.bash,eggkg.server, …), write-through patching of the active config file,active.confoverlay with.base.ecftemplates.- eqshell scripts (
.es) run withset -x FILE:[Eqshell]header,Log=Truedirective producing an 8 KB transcript at/eqshell.log, nesting up to 3 levels. - ruf v3 recipes with variables (
name := "value", case-insensitive$nameexpansion) and queuedcopy A [& B] ? D/move A [& B] ? Dpost-build actions; executed bymtcc -make <file.ruf>. equinoxinstallgrew-build:-build <file.ruf>(viamtcc -make),-build <tool>(single tool),-build *.ruf(single-star glob). The oldeqbuildcommand is gone.Qfsdisk tool:-list-disk,-t hdX -format fat32, and-install-boot [hdX](writes GRUBboot.img+core.img, generatesgrub.cfg, verifies the result).- Shell upgrades: line-level pipe
|, output/input redirection> >> <, single-star glob*, arrow-key history;eqbashgainedcdir/cfile/ccfile/save/delfile/deldir/prenpluslf/showfaliases; the nine bash-class tools (ls, cat, cp, mv, mkdir, rmdir, rm, touch, stat) moved out of the base ISO into the eggkgbashpackage. eqgu: the built-in editor for.cfiles — re-compiles the file on save and shows compiler diagnostics in place.- morph pkg API + ANSI colors:
libc/pkg.cadds 20 package-builder functions (pkg_copy,pkg_bin_install,pkg_db_add, …); the console parses ANSI CSI sequences (SGR colors, cursor home, clear line/screen), and<morph.h>exposesansi_fg,ansi_bg,ansi_goto, … to programs. - EquiX desktop (ThorVG): a full-screen vector desktop (
desktop) with demo/benchmark/info commandstvgdemo,tvgbench,tvginfo, alongside the existing LVGL apps.
- RAM: 256 MB recommended — this is what the makefile run targets use (
-m 256) and what theinfobanner reports. The system still boots and runs with 64 MB; fixed kernel regions (module staging at 40 MB, the FAT32 cache arena at 52 MB) set the practical floor. Installed memory is detected from the multiboot information at boot and logged asRAM detected: N MB. - QEMU 4.x or newer for the prebuilt images (
qemu-system-i386). - To build from source:
build-essential,gcc-multilib,g++-multilib,nasm,grub-pc-bin,grub-common,xorriso,mtools,python3(see Building from source).
You need only QEMU and the two images (equinox.iso, disk.img):
qemu-system-i386 -m 256 -boot order=d -cdrom equinox.iso \
-drive file=disk.img,format=raw,if=ide,index=0,media=disk \
-netdev user,id=net0,hostfwd=tcp::8080-:80 \
-device ne2k_isa,netdev=net0,iobase=0x300,irq=9-boot order=dboots the ISO. The demo disk carries an MBR without boot code.- Without
disk.img, drop the-driveline: the OS runs entirely from the RAM filesystem. - The guest gets
10.0.2.15by DHCP; the QEMU host is10.0.2.2, DNS is10.0.2.3. The guest web server is reachable from the host athttp://localhost:8080/. - To boot from the hard disk instead (after
Qfs -install-boot), use-boot order=c.
root::users / $ ls /mnt # FAT32 disk, auto-mounted
root::users / $ equinoxinstall # wizard: build userland in-OS (or: equinoxinstall -compile)
root::users / $ mtcc /test/hello.c # compile + run a C program
root::users / $ ps # task table
root::users / $ spawn /equinox/tools/bgcount.mrp # run a task in the background
root::users / $ eggkg update # fetch the package index (Eggkg-l)
root::users / $ eggkg install bash -y # 19 coreutils into /bin
root::users / $ doom -iwad /mnt/doom1.wad # DOOM from the disk
Press F1 to open a new virtual console/shell and F2 to return to the previous one. The shell supports single-star globbing (ls /equinox/tools/*.c), pipes (cat file | grep text), redirection (echo hi > /mnt/a.txt, >> to append, < for input), and arrow-key history.
disk.img is a 64 MB IDE image: MBR plus one FAT32 partition (type 0x0C, label EQDISK) holding README.TXT, a long-file-name sample, docs/, bin.dat and doom1.wad. Everything you write to /mnt is written through to the image.
GRUB (Multiboot) -> kernel.elf + boot modules (mtcc.mrp, games, tool sources, WAD)
|
boot/start.asm VBE 1360x768x32 (VGA text fallback), GDT, module staging @ 0x2800000
|
kernel/kernel.cpp RAM detection (multiboot) -> heap arenas -> paging -> IDT/PIC/PIT
| -> console -> PS/2 -> PCI -> scheduler -> RAMFS from modules
| -> ATA + FAT32 (/mnt) -> NIC + lwIP + nettask (DHCP) -> eggkg boot check
v
kernel/shell.cpp prompt "root::users / $" (eqbash: builtins + global tool dispatch)
|
+-- ring-3 programs: .mrp / .elf <--- int 0x80 ---> syscall layer (54 calls)
+-- equinoxinstall -> mtcc (in-OS) -> self-built userland
+-- eggkg -> net fetch -> mtcc -make -> /bin
The kernel is monolithic. Every subsystem mirrors its log to serial COM1, which makes the whole system scriptable from the host (the regression suites drive QEMU this way). The boot log lists each subsystem as [ OK ] together with every file loaded into the RAM filesystem.
More detail lives in docs/ARCHITECTURE.md and docs/GETTING_STARTED.md (Indonesian).
Scheduler. Preemptive round-robin driven by the 100 Hz timer (quantum: 1 tick = 10 ms). Each task owns a 16 KB kernel stack and a separate 16 KB interrupt stack (the TSS.ESP0 target), plus its own fxsave FPU state. When nothing is runnable the scheduler halts with interrupts on until an IRQ makes a task ready, so sleep(ms) is exact to the tick and the network task never busy-spins.
Limits. MAX_TASKS = 8, 16 file descriptors per task.
Per-task state. Every task carries its own file-descriptor table, current directory, argument string, private user arena and page directory, virtual console, and graphics clip window. Syscalls always act on the calling task's context.
Lifecycle.
spawn / spawn2 --> READY <--> RUNNING --> exit --> ZOMBIE --wait--> slot freed
^ | (status held for the parent)
| +--> SLEEP / BLOCKED (pipe, wait, console focus)
- A USER child becomes a zombie on exit: its slot and exit status are kept until the parent calls
wait. - Killed children are also waitable. Orphans are reaped when the parent dies. If the task table is full, the oldest zombie is reclaimed.
- Errors:
SYS_ECHILD(-13) forwaitwith no children,SYS_EPERM(-14).
Pipes. SYS_PIPE creates a 4 KB kernel ring buffer with reference-counted ends. Pipe descriptors are inherited across spawn. Reads block until data arrives and return EOF when the last writer closes. Writes block on a full buffer, and writing with no readers returns a broken-pipe error (-EIO). pipedemo (built by equinoxinstall) demonstrates a child writing to its parent.
Virtual consoles. Each task has its own cell mirror and cursor. Background tasks print to their own console instead of overwriting the screen. F1 opens a new shell on a new console, F2 focuses the previous one, and switch <n> selects a console explicitly. Graphics programs use a per-task canvas: the first draw snapshots the text screen and clears to black; the console is redrawn on exit.
Physical RAM is detected from the multiboot information at boot (paging_set_ram_top). Paging identity-maps 16 to 32 page tables (64–128 MB) depending on installed RAM; the region above the map is deliberately left unmapped. With the recommended 256 MB the paging map is capped at 128 MB and the dynamic GUI arena takes the remainder up to that cap.
| Region | Address / size | Purpose |
|---|---|---|
| Kernel heap | 2 MB at 0x300000-0x500000 plus a ~1 MB extension 0x2702000-0x27FFFFF (about 3 MB total) |
Free-list allocator with split, coalesce and canaries. Only physically adjacent blocks are ever merged. |
| User page pool | 0x500000-0x2600000 (33 MB) |
Bitmap of 4 KB physical pages handed to tasks on demand. Also the default MRP program window. |
| User stack | 1 MB, 0x2602000-0x2702000, guard page below |
Supervisor-only guard at 0x2601000 detects stack overflow. |
| Module staging | 0x2800000, 12 MB |
GRUB modules (mtcc.mrp, doom.mrp, tool sources, WAD). Big files are referenced zero-copy. |
| FAT32 disk arena | 8 MB at 0x3400000 |
File caches for FAT32 files, outside the kernel heap (free-list allocator). |
| GUI arena | 0x3400000 up to min(RAM top, 128 MB) — dynamic |
Framebuffer canvases and the desktop (LVGL / EquiX). Was a fixed 10 MB before 0.4 Beta. |
| Task window | arena at 0x500000+ (33 MB pool; 24 MB reserved for DOOM) plus the 1 MB stack |
Reserved with PTE_DEMAND; faulted in per page. |
| ELF window | segments in [0x800000, 0x2000000), 2 MB heap at 0x2000000 |
Static ELF32 images. |
Demand paging. Reserving a window marks its PTEs non-present with a PTE_DEMAND marker. The first access raises #PF; isr_14 calls task_demand_fault(), which allocates one physical page, maps it, zero-fills it through the faulting address, and resumes the instruction. Fresh .bss therefore reads as zero, and physical memory is consumed only for pages actually touched. Loader copies use a two-phase fill (map and zero under the kernel directory, then copy under the task's directory). meminfo (shell) and syscall #51 report pool totals, faulted KB per task, reserved versus faulted, stack pages and zombie count.
Guard pages. A supervisor-only guard page sits below each user stack. Overflow kills the offending program and the shell keeps running. The crash* programs exercise this: division by zero, NULL dereference, a write into kernel memory from ring 3, and runaway recursion.
A flat binary behind an 18-byte header. A 4-byte magic and an additive checksum let the loader reject truncated or corrupt files before jumping into them.
| Offset | Size | Field |
|---|---|---|
| 0 | 4 | magic M R P 1 |
| 4 | 1 | format version (1) |
| 5 | 4 | entry offset (relative to the code start) |
| 9 | 4 | code size |
| 13 | 1 | flags (MRP_FLAG_NEEDS_GUI reserved) |
| 14 | 4 | checksum (rotate-xor over the payload, non-zero seed) |
Programs link at 0x500010 (mrp_user/link_mrp.ld). The loader validates, maps the per-task demand window, copies the image, and enters ring 3. Programs use their own per-task arena for malloc / free; the arena is discarded on exit. mrp_user/mrp_pack.py compiles, links and wraps a hosted .cpp into a .mrp; mtcc -c produces one natively (with fixups patched against 0x500010).
Static ET_EXEC / EM_386 / little-endian executables run beside MRP. The loader validates the program headers (at most 16), requires every PT_LOAD segment and the entry point to fall in [0x800000, 0x2000000), maps the span into the demand window, and zero-fills .bss on fault. A plain ret from _start lands on the standard exit trampoline. Build one on the host with:
gcc -m32 -ffreestanding -fno-pie -static -no-pie -nostdlib -O2 \
-T mrp_user/elf_link.ld tools_user/elfdemo.c -o elfdemo.elf # or: make elfdemoRun it with elfdemo.elf, ./elfdemo.elf, or spawn + wait (exit status 42).
Both formats are launched the same way (run <file>, ./file, or by bare name from any directory — including subpaths such as equinox/games/snake.mrp), and both support spawn, wait and pipes.
mtcc (self-reported as mtcc 0.3) is a tcc-style, single-pass compiler: lexer, recursive-descent parser, and direct x86-32 code generation with no AST. It ships as an ordinary .mrp module and runs inside the OS.
mtcc program.c compile and run immediately (like tcc -run)
mtcc -c program.c compile to program.mrp, then run it
mtcc -make b.ruf multi-file build from a .ruf recipe:
echo / src / exclude / out / lib — self-hosting
without equinoxinstall
mtcc --debug prog.c verbose compiler info (file, code/data sizes)
flags: -c compile-only -q quiet --lib no-main check -make <file.ruf>
Language subset: int, char, void, one- and two-level pointers, 1-D arrays; if/else, while, do-while, for (with a declaration in the initializer), return, break, continue; every assignment and arithmetic/bitwise/logical/relational operator, pre/post ++ --, and the ternary operator; global scalars and arrays with constant, list and string initializers; recursion and forward prototypes (up to 8 parameters). Not supported: struct / union, floating point, switch, sizeof, typedef, 2-D arrays, variadic functions, static locals, unsigned semantics.
Preprocessor: #include <morph.h> (aliases: <stdio.h>, <stdlib.h>, <string.h>; nesting depth max 8), <multitasking.h>, <fileio.h>, "file.h" from RAMFS, object-like #define, #undef, #ifdef / #ifndef / #else / #endif (function-like macros are rejected with a clear message).
Diagnostics: calling a declared-but-undefined function fails the build and reports the line number of the first call site.
The libc lives in /equinox/libc as 13 modules spliced together by the <morph.h> master include (v0.9.3 added the pkg module). Roughly 98 public functions are available through the include, plus 57 compiler builtins that work without any include.
| Header / source | Contents |
|---|---|
<morph.h> (13 modules) |
string/memory: strlen strcmp strncmp strcpy strncpy strcat strncat strchr strrchr strstr strdup strtok strspn strcspn strcasecmp memcpy memset memmove memcmp memchr · convert/parse: atoi strtol itoa utoa sscanf abs · ctype (13): isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper · heap: malloc free calloc realloc · stdio: printf sprintf snprintf puts fputs fopen fread fwrite fseek ftell fclose fgetc fputc remove rename · misc: strerror rand srand qsort_int qsort_str time getenv abort · graphics: draw_line set_clip |
<morph.h> pkg module (v0.9.3) |
20 package-builder functions layered on syscalls #40–#48: pkg_is_dir pkg_is_file pkg_exists pkg_size pkg_join pkg_base pkg_mkdir_p pkg_copy_file pkg_copy_path pkg_copy pkg_remove pkg_move pkg_write pkg_append pkg_read pkg_list pkg_count pkg_manifest pkg_bin_install pkg_db_add |
<multitasking.h> |
task_spawn task_spawn_hint task_yield task_wait task_kill task_pid task_list pipe_create mem_info |
<fileio.h> |
f_open f_stat f_fstat f_readdir f_mkdir f_rmdir f_unlink f_rename f_free with F_* open flags |
| Built-ins | thin syscall wrappers available without any include: print printint getkey readline write open read close malloc sleep gettick getpid exit exec getargs mkfile lseek ring, file_open file_read file_close file_write file_read_all file_size file_exists, net_info net_ping, and the game API fb_info put_pixel fill_rect draw_line set_clip pollkey mouse_state spk_tone spk_silence snd_beep |
| ANSI helpers (v0.9.3) | clear_screen ansi_reset ansi_bold ansi_fg(c) ansi_fg_bright(c) ansi_bg(c) ansi_default ansi_goto(row,col) ansi_clear_line plus ANSI_BLACK..ANSI_WHITE color constants |
printf / sprintf / snprintf render locally inside the program (%d %i %u %x %X %o %p %c %s, with width and flags; true unsigned %u over the full 0..4294967295 range), taking up to 5 conversion arguments per call.
- The compiler emits a closed instruction set. A host-side x86-32 interpreter (
scripts/tcc_host_test/, run withmake test) executes exactly that set, so any codegen bug outside it is caught immediately. - Parity: the in-OS compiler produces byte-identical
.mrpimages to the host build of the same source. - Documentation:
mrp_user/TCC.md,mrp_user/workflow_mrp.md,docs/EGGKG.md.
A .ruf file is a small build recipe read by mtcc -make. One line per directive, # starts a comment, and key value, key = value and key := value are all accepted:
echo <text> print a log line while parsing
src <dir> source directory (repeatable); a bare path line is read as src
exclude <name> skip this entry (directory or .c file, any level)
out <dir> write every .mrp here (default: next to the sources)
lib all jobs use --lib mode; files under a "libc" directory always do
copy A [& B] ? D copy files/directories (recursive) to D
move A [& B] ? D move them to D — both run only AFTER all jobs succeed
v3 additions (0.4 Beta): variables and post-build actions.
pkg := "bash"
source := "/equinox/.local/$pkg/src"
Target := "/equinox/.local/$pkg"
echo "eggkg: Build $pkg (19 coreutils)"
src $source
out $Target
- Variable names are looked up case-insensitively (
$pkgand$Targetabove), and expansion happens in every directive value. A variable must not be named after a directive word (echo,src,exclude,out,lib,copy,move— directives win). copy/movetake multiple sources separated by&(up to 4) and use?as the "to" keyword. They are queued and executed in order after every compile job succeeds, so broken artifacts never spread.- The walker recurses to depth 6 and turns only
.cfiles into jobs. Limits: 128 jobs, 8 source dirs, 16 excludes, 16 variables, 16 copy/move actions. - Recipe versions: v1 is the flat
echo/src/exclude/out/libform; v2 wraps it in INI sections ([package],[build],[install], optional[src:file.c]heredocs) and is understood by eggkg, which strips it back to v1 before invoking mtcc; v3 adds the variables andcopy/move ?actions shown above. v3 recipes require OS 0.4 Beta (mtcc v0.9.3) or newer.
The ISO ships the userland as C source — /equinox/tools (20 tools), /equinox/games (snake, breakout, pong), and the 13-module libc — not as binaries. equinoxinstall compiles them with the in-OS mtcc:
equinoxinstall installation wizard, 4-5 phases
equinoxinstall -compile <dir> compile userland only (dir must hold libc/ + tools/)
equinoxinstall -build <file.ruf> build via mtcc -make
equinoxinstall -build <name> build one tool (mtcc -c /equinox/tools/<name>.c)
equinoxinstall -build <pola*> e.g. *.ruf — build every matching recipe
The wizard walks through: [1/4] pick a target disk (hda–hdh, or build in place), [2/4] prepare the target volume (format to FAT32 EQUINOXBASE if needed, export the /equinox + /user + /test layout plus kernel.elf), [3/4] choose the NIC driver (writes equinox/conf/system.ecf), [4/4] build the userland with a two-job mtcc pool (libc check-compile, then tools and games, with a live progress bar), and optionally [5/5] install the GRUB bootloader onto the target disk (Qfs -install-boot) so it boots without the CD.
Compiling mtcc itself from inside the OS is not supported (self-compilation); the honest answer is that mtcc.mrp is packed from the host with make mtcc. A failed compile keeps its source, so the command can simply be re-run. The RAM filesystem is rebuilt from the ISO on every boot, so each fresh boot carries the sources again.
Since 0.4 Beta the base ISO is intentionally slim: the nine bash-class tools (ls cat cp mv mkdir rmdir rm touch stat) moved to the eggkg bash package. Until you install it, the shell's own builtins and aliases (lf, showf, copy/cp, del, cdir, cfile, save, …) cover the same operations.
eggkg is a Gentoo-style package manager implemented as a ring-0 shell builtin (kernel/eggkg.cpp), so networking and spawning mtcc never leave the kernel. Its default server is the Eggkg-l GitHub repository.
eggkg update [source] download package.list (+ index.idx);
source = URL or local path
eggkg install <name> [-y] fetch sources, build with mtcc, install to /bin
eggkg remove <name> [-y] delete the files recorded in installed.db
eggkg list installed packages
eggkg search <pattern> search the index
eggkg info <name> package metadata
eggkg sync re-sync .local -> /bin (also runs at boot when
[dependencies] bash=true in system.ecf)
- Repository formats.
package.list(format v0) maps a package name to a list of source URLs (name = ["url1", "url2", ...]; GitHubbloblinks are rewritten toraw.githubusercontent.comautomatically, and local paths serve as offline repos). An optionalindex.idx(format v1) adds per-packageversion / desc / sha256 / size / url / mirror / deps; mirrors are tried in order (up to 3). - install runs four stages: read the index, download (archive packages up to 384 KB are extracted from embedded
[src:*]heredocs; loose sources are fetched file by file), build viamtcc -makeon the package's.rufrecipe (a canonical recipe is synthesized when the server ships none), and install the resulting.mrpinto/bin(zero-copy relink on RAMFS, copy on FAT32) with the file list recorded ininstalled.db. sha256 is verified wheneverindex.idxprovides it. - remove refuses to remove a package that others depend on, and removing
bashoffers to flip[dependencies] bash=falseinsystem.ecf. - Boot integration: when
system.ecfcontains[dependencies] bash=true, the kernel runseggkg syncautomatically at shell start, so packages installed into the workspace survive as long as/equinox/.localdoes. - Workspace:
/equinox/.local/<pkg>/holdsbuild.ruf,src/and the build output; override the local dir and server with theeggkg.local/eggkg.serverconfig keys (see Configuration). Transport is an in-process HTTP/HTTPS fetch (net_eggkg_fetch, BearSSL TLS 1.2,User-Agent: equinox-eggkg/0.9) —mgetis not involved.
The Eggkg-l repository currently indexes 11 packages (42 source URLs):
| Package | Description |
|---|---|
bash |
shell + coreutils class — 19 programs (cat cp cut diff dirname find grep head mkdir more mv rev rm sort tail tr uniq wc which) |
eqfetch |
mini neofetch |
emu-ch8 |
CHIP-8 emulator (includes the bounce.c8 ROM) |
wolf |
ray-cast maze shooter |
space |
space invader |
tetris |
falling blocks |
flappy |
flappy-bird style game |
ppmview |
PPM (P6/P3) image viewer (includes demo.ppm) |
bfi |
Brainfuck interpreter (includes hello.bf) |
bfc |
Brainfuck-to-C transpiler (mtcc -c it into a .mrp) |
sysmon |
interactive system-monitor TUI (-list-task, -kill, -spawn, -h) |
The bash package's recipes are ruf v3, so Eggkg-l requires Equinox 0.4 Beta (v0.9.3) or newer. package.list v0 carries no versions or hashes; when the repository publishes an index.idx, eggkg verifies sha256 automatically.
.ecf is a lightweight INI dialect that replaced the old boot nic.cfg entirely. # starts a comment; a [section] header prefixes the keys that follow; keys containing a dot are used as-is.
# /equinox/conf/system.ecf
[net]
driver = ne2000
[dependencies]
bash = trueThe store is loaded at boot from the first existing file: /equinox/conf/system.ecf, /mnt/equinox/conf/system.ecf, then the legacy /boot/system.ecf locations. Writes go to the mounted volume first (/mnt/equinox/conf/system.ecf) so they survive a reboot; the parser is static (no malloc) and tolerant: unknown keys are counted and skipped, invalid values error out, duplicate keys resolve last-wins.
The schema knows seven keys:
| Key | Values | Read by |
|---|---|---|
net.driver |
ne2000 | e1000 | none |
NIC probe order (needs reboot to apply) |
base.path |
any path (/mnt promotes the volume to root at boot) |
FAT32 boot logic |
active.conf |
file name of the overlay config | set / ecf store loader |
dependencies.bash |
true | false |
eggkg boot-time sync |
eggkg.server |
URL or path | package index source |
eggkg.mirror |
URL (reserved) | declared in schema, not yet read |
eggkg.local |
directory | package workspace (default /equinox/.local) |
set list active entries
set KEY show one value
set KEY VALUE change a value (schema-validated, written through)
set -a FILE apply every entry in FILE
set -w FILE write the active store to FILE
set -d FILE [-path DIR] [-base SRC]
make FILE the main config (fresh keys = NONE)
set -b PATH record the base.path pivot (applies after reboot)
set -x FILE run an eqshell script (.es)
Every change is validated against the schema (set net.driver bogus prints the allowed choices and is rejected), patched in place into the active .ecf file (comments preserved), and mirrored into the in-memory store. Keys that require a reboot (only net.driver) say so. set -d creates an overlay: the pointed file becomes the active config, new keys are cloned from a .base.ecf template (auto-derived from the file name) with every value set to the NONE placeholder, and the active.conf pointer is written back to the default config.
set -x FILE runs a small script format understood by the shell:
[Eqshell] <- first meaningful line, required
Log=True <- directive: capture every command + output
# comment <- skipped
diskinfo
Qfs -list-disk
- The header must be exactly
[Eqshell]. Directives areKey = Valuelines; the only recognized key isLog(True/False) — unknown directives are consumed with a warning. - Every remaining line is fed verbatim into the normal shell dispatch, so pipes, redirection, globbing,
sleep,waitand all builtins work inside scripts. Log=Truerecords each command and its output into a transcript that is flushed to/eqshell.log(8 KB cap) when the script ends — a runnable audit trail, not just echo.- Limits: script ≤ 4 KB / 512 lines, nesting depth ≤ 3.
Qfs is the disk utility builtin (in kernel/shell.cpp):
Qfs this help
Qfs -list-disk list disks (hda..hdh)
Qfs -t hdX -format fat32
format -> whole-disk FAT32, label EQUINOXBASE
Qfs -install-boot [hdX]
install the GRUB bootloader (boot without CD)
-list-diskshows every probed IDE slot with size, FAT32 presence, label and state (base,mounted,siap,tanpa-fat32).-t hdX -format fat32refuses to format a mounted volume; formatting produces a whole-disk FAT32 volume with a reserved gap (LBA 1..2047) for bootloader sectors.-install-bootwrites GRUB for real:boot.img(512 B) becomes the MBR at LBA 0 (the existing partition table is preserved),core.imglands at LBA 1..N, and agrub.cfgis generated on the volume (search label EQUINOXBASE,multiboot /boot/kernel.elf, onemoduleline per shipped.mrp/.c/.wad/.ruf/.elf/.h). It then reads the sectors back to verify, and printsBOOTABLE — reboot tanpa CD (QEMU: -boot order=c).- In the same family:
copy SRC [->] DST(recursive copy;cpis an alias) anddel PATH(recursive delete;rmstays non-recursive).
int 0x80, EAX = number, EBX / ECX / EDX = arguments, EAX = result (negative = error). Number 0 is deliberately unused so that "forgot to set EAX" is detectable. The numbering is append-only, so old binaries keep working. The table below mirrors kernel/library/header/syscall.h.
| # | Name | Signature | Notes |
|---|---|---|---|
| 1 | exit |
(status) |
ends the program |
| 2 | exec |
(path) |
run an MRP; nested exec returns EBUSY |
| 3 | getpid |
() |
caller's pid |
| 4 | write |
(fd, buf, len) |
console, file, or pipe |
| 5 | read |
(fd, buf, len) |
file or pipe; 0 = EOF |
| 6 | open |
(path) |
read-only open |
| 7 | close |
(fd) |
flushes dirty writable fds |
| 8 | getkey |
() |
keyboard, non-blocking |
| 9 | readline |
(buf, max) |
one line of input |
| 10 | print |
(str) |
|
| 11 | printint |
(n) |
|
| 12 | malloc |
(size) |
per-task arena |
| 13 | gettick |
() |
100 Hz ticks since boot |
| 14 | sleep |
(ms) |
tick-exact |
| 15 | getargs |
(buf, max) |
the program's arguments |
| 16 | mkfile |
(path, buf, len) |
create or overwrite, binary-safe |
| 17 | readfile |
(path, buf, max) |
whole-file read |
| 18 | filesize |
(path) |
|
| 19 | fileexists |
(path) |
|
| 20 | fbinfo |
(info*) |
framebuffer address / size / bpp / pitch |
| 21 | putpixel |
(x, y, color) |
|
| 22 | fillrect |
(x|w<<16, y|h<<16, color) |
|
| 23 | pollkey |
() |
non-blocking, 0 = none |
| 24 | mouse |
(state*) |
absolute position + buttons |
| 25 | speaker |
(freq) |
PC speaker on/off |
| 26 | sndbeep |
(freq, ms) |
queued timed tone |
| 27 | lseek |
(fd, off, whence) |
|
| 28 | printf |
(fmt, args[3]) |
kernel-side printf |
| 29 | ringinfo |
() |
caller CPL (0 or 3) |
| 30 | blit |
(src, w|h<<16, flags) |
8 bpp to framebuffer, scaled |
| 31 | setpalette |
(pal*) |
256 x RGB |
| 32 | keyevent |
() |
press/release + raw scancode |
| 33 | mousedelta |
(int32[2]) |
raw PS/2 delta + button mask |
| 34 | netinfo |
(u32 w[10]) |
IP, MAC, counters |
| 35 | netping |
(ip) |
4x ICMP echo |
| 36 | spawn |
(path, arena_hint) |
new task, non-blocking |
| 37 | yield |
() |
|
| 38 | taskinfo |
(u32[]) |
task list (ps) |
| 39 | kill |
(pid) |
|
| 40 | open2 |
(path, flags) |
O_RDONLY/WRONLY/RDWR/CREAT/TRUNC/APPEND/EXCL/DIR |
| 41 | unlink |
(path) |
|
| 42 | mkdir |
(path) |
|
| 43 | rmdir |
(path) |
empty directories only |
| 44 | rename |
(old, new) |
|
| 45 | stat |
(path, stat*) |
size, type, backing store, mode |
| 46 | readdir |
(fd, dirent*) |
one entry per call |
| 47 | fstat |
(fd, stat*) |
|
| 48 | free |
(ptr) |
|
| 49 | wait |
(pid, status*) |
blocking waitpid; -1/any child supported |
| 50 | pipe |
(fds[2]) |
4 KB ring |
| 51 | meminfo |
(u32 w[6]) |
pool and per-task memory |
| 52 | spawn2 |
(path, hint, args) |
spawn with arguments |
| 53 | setclip |
(x|w<<16, y|h<<16) |
per-task draw window |
| 54 | drawline |
(x0|y0<<16, x1|y1<<16, color) |
Bresenham, clipped |
Negative results are errnos (SYS_ENOENT, SYS_EBADF, SYS_EFAULT, SYS_EBUSY, SYS_EIO, SYS_ECHILD, ...). syscalls prints the live table from the running kernel.
ATA / IDE (PIO). Primary and secondary buses, master and slave (four slots probed at boot with IDENTIFY), LBA28 with automatic LBA48 for large disks, ATAPI (CD-ROM) detection, MBR parsing (four primary entries, 0x55AA validated), and FLUSH CACHE after writes. A generic block layer (kernel/library/drivers/blk.cpp) sits in front of the drivers; AHCI sources exist alongside as work in progress.
FAT32 (read/write).
- Mount validates the BPB, FSInfo and cluster layout. The first FAT32 partition mounts at
/mntautomatically (mount/umountdo it by hand). - Lazy RAMFS mirror: directories populate on first use and file contents load on first read.
ls,cd,cat,edit,mget, the GUI file manager and every syscall work on disk files transparently. - Long file names are read and written with 8.3 mangling (
~1..~9numeric tails, collision checks against the real on-disk short names). Name matching on the volume is case-insensitive per the FAT spec. - Write-through: create, overwrite, extend, truncate,
mkdir, delete. Both FAT copies and the FSInfo sector stay consistent, directories grow on demand, and a failed I/O rolls the operation back. - Fast reads: cluster chains are walked with contiguous-run coalescing (up to 128 sectors per ATA transfer), so the 4.2 MB
doom1.wadstreams in well under a second. - Verified against an independent implementation (mtools) and a host-side mini-fsck up to 100 % volume usage.
RAMFS. The tree is populated from GRUB modules at boot. The dist/ layout mirrors it: dist/equinox/tools maps to /equinox/tools, dist/equinox/games to /equinox/games, dist/*.c to /test, and dist/equinox/repo to an offline eggkg repository (eggkg update /equinox/repo/package.list).
System path /bin. eggkg-installed programs land in /bin, which the shell consults when resolving bare command names; in-OS-built tools live in /equinox/tools.
ne2k_isa / e1000 (0x300 / IRQ 9) -> RX ring (drained outside the IRQ) -> lwIP 2.1.3 (NO_SYS) -> DHCP / DNS / ICMP / TCP
|
mget (HTTP + HTTPS client) + httpd (server on :80)
eggkg in-process fetch + BearSSL TLS 1.2, 9 root CAs
- Kernel
nettaskpolls the stack cooperatively so the shell never blocks the network. mget <url>downloads over HTTP or HTTPS into the current directory (cd /mntfirst to write to the disk), follows up to 3 redirects, and supports-port <n>. TLS is fail-closed: certificate verification uses 9 built-in root anchors;mget -k(--insecure) is an explicit opt-out.httpdserves a status page and RAMFS files on port 80 (http://localhost:8080/from the QEMU host).ping,tcpping,dns,ifconfig,netdbgcover diagnostics. QEMU user-mode networking does not forward ICMP, so usetcppingthere.eggkguses its own in-process transport (net_eggkg_fetch) with the same TLS stack and redirect handling, returning fetched archives and sources directly to the package manager.- NIC registry (
kernel/net/nic.c): one struct (probe / send / recv / mac / irq / overflow) separates lwIP from hardware. NE2000-ISA is the first driver; e1000 is also implemented, and pcnet32 / eeepro100 devices are recognized and reported honestly. Thenet.driverconfig key selects the driver (or disables networking withnone).
- Display: VESA linear framebuffer at 1360x768x32 with a text-mode fallback. 24-bit RGB console colors, plus an ANSI CSI parser in the console (SGR 0/1, fg 30-37, bg 40-47, bright 90-97/100-107, cursor home
H, clearJ/K) so colored output works both from the shell and from programs. - Per-task drawing:
set_clipconfines a task'sput_pixel,fill_rectanddraw_lineto a window, enforced by the kernel. Graphics output is focus-gated so background tasks cannot paint over the active console. blit: scaled 8 bpp to 32 bpp with a palette, one syscall per frame, with a 4:3 letterbox option.- EquiX desktop (ThorVG, new in 0.4 Beta):
desktopruns a full-screen vector-rendered desktop (exit with ESC / menu), withtvgdemo,tvgbenchandtvginfoas standalone demo, benchmark and info commands. ThorVG is compiled into the kernel and draws through the GUI arena. - LVGL 8.3 apps:
fm(flex-layout file manager browsing/mnt, PS/2 mouse) andsettings. Theguicommand runs the LVGL demo. LVGL is compiled in whenkernel/gui/lvgl/exists in the tree. - Text editor (
edit): arrows, PgUp/PgDn, Home/End, Tab; Ctrl+S saves (write-through on FAT32), Ctrl+Q quits.eqgu <file.c>adds compile-on-save: the file is run throughmtccand diagnostics appear without leaving the editor. - Libgame (
Libgame/libgame.h): header-only helpers layered on the Morph SDK: rectangles, filled circles, a scalable 5x7 bitmap font, keyboard/mouse polling, non-blocking sound effects, a fixed-timestep helper, xorshift RNG, AABB collision. Snake, Breakout and Pong ship as self-hosted C sources built byequinoxinstall. - DOOM (doomgeneric port,
mrp_user/doom/): runs from a 24 MB demand-paged arena and reads its WAD straight from the FAT32 disk (doom -iwad /mnt/doom1.wad). It uses the file, blit, palette, keyboard and sound syscalls and its own small libc shim. - Audio: PC speaker with a timed-tone queue (
beep,song,snd_beep).
| Device | Notes |
|---|---|
| VESA / VBE framebuffer | mode set in start.asm; VGA text fallback |
| PS/2 keyboard | IRQ 1, per-console scancode rings, F1/F2 console control, arrow-key history |
| PS/2 mouse | IRQ 12, AUX-filtered, absolute position + raw deltas |
| ATA / IDE PIO | LBA28/48, ATAPI detect, MBR; generic block layer on top |
| AHCI | sources present (kernel/library/drivers/ahci.cpp), experimental |
| PCI | config-space enumeration (0xCF8/0xCFC), BARs, IRQ routing, bridge recursion, lspci |
| NE2000 (ISA) | first driver in the NIC registry |
| e1000 | implemented; pcnet32 / eeepro100 recognized |
| PC speaker + PIT | tone queue; 100 Hz system timer |
| CMOS RTC | file timestamps, clock |
| Serial COM1 | mirror of the console for automation and logs |
The prompt is root::users / $. Paths can be absolute (/mnt/x) or relative (./x, dir/x). The shell resolves bare names against its builtins, the /bin system path (eggkg packages), /equinox/tools, /equinox/games and the current directory. Line features: single-star glob *, pipes |, redirection > >> <, arrow-key history. The full command-by-command reference with examples lives in docs/COMMANDS.md.
Legend: B = kernel builtin, T = userland tool (built by equinoxinstall or installed by eggkg), P = bundled program (.mrp / .elf).
| Command | Type | Description |
|---|---|---|
ls [dir] / ls -l / lf [-l] |
B, T | list a directory (RAMFS and /mnt alike; lf is the new name, ls remains during the transition window) |
cd <dir> / pwd |
B | change / print the working directory |
tree [dir] |
B | recursive directory tree |
cat <file> / showf <file> |
B, T | print a file |
copy <src> [->] <dst> / cp |
B, T | copy a file or directory (recursive) |
mv <src> <dst> |
T | move / rename |
del <path> |
B | recursive delete |
rm <file> / delfile |
B, T | delete a single file (write-through on /mnt) |
mkdir <dir> / cdir <name> |
T, B | create a directory |
rmdir <dir> / deldir |
B, T | remove an empty directory |
touch <file> / cfile <name> |
T, B | create an empty file / update its time |
ccfile <name> <text> |
B | create a file with one line of content |
save <name> << "text" |
B | create or overwrite a file with the given text |
stat <file> |
T | size, type, backing store, timestamps |
pren <file.mrp> |
B | MRP binary preview |
edit <file> |
B | built-in text editor (Ctrl+S save, Ctrl+Q quit) |
eqgu <file.c> |
B | editor with compile-check on save |
xxd <file> [n] |
B | hex dump of the first n bytes (default 64) |
mount / umount |
B | attach / detach the FAT32 volume at /mnt |
diskinfo |
B | ATA drives, partitions, volume layout, free clusters, arena and cache stats |
fm [path] |
B | LVGL graphical file manager |
sys cwd|mkdir|touch|rm ... |
B | direct kernel filesystem calls |
grep [-i -n -c -v], head [-n N], tail [-n N], wc [-l -w -c], sort [-r], uniq [-c], cut -d DELIM -f LIST, tr SET1 SET2 / tr -d SET, rev, nl, more (23-line pager), find [-name SUBSTR], which NAME, diff FILE1 FILE2, strings FILE [minlen], cksum FILE..., basename PATH, dirname PATH.
| Command | Type | Description |
|---|---|---|
ps |
B | task table: pid, state, kind, console, name (eqbash is the shell task) |
run <prog> / ./prog |
B | run a .mrp or .elf in ring 3 (foreground) |
spawn <prog> [args] |
B | start a program as a new background task |
kill <pid> / wait [pid] |
B | terminate a task / block for a child's status |
yield / sleep <ms> |
B | give up the CPU / tick-exact sleep |
switch <n> |
B | move display focus to console n (same as F1/F2) |
meminfo |
B | user page pool, faulted vs reserved pages per task, zombies |
| Command | Type | Description |
|---|---|---|
equinoxinstall |
B | interactive install wizard (build userland in-OS) |
equinoxinstall -compile <dir> |
B | compile userland only |
equinoxinstall -build <file.ruf | name | *.ruf> |
B | build a recipe, one tool, or every matching .ruf |
mtcc [--debug] [-c] <file.c> |
P | compile and run C, or compile to .mrp (-c) |
mtcc -make <file.ruf> |
P | multi-file build from a ruf recipe |
eggkg update|install|remove|list|search|info|sync |
B | package manager (see its section above) |
set [KEY [VALUE]] / -a / -w / -d / -b / -x |
B | view, validate and write .ecf config; run .es scripts |
Qfs [-list-disk | -t hdX -format fat32 | -install-boot] |
B | disk listing, formatting, GRUB installation |
info (version banner, feature build, RAM size), cpu (CPUID), lspci, memmap, malloc (kernel heap statistics), tick, clock, syscalls (live syscall table), sctest (syscall self-test), ring / ringstats, testconv / teststr / testvector (kernel libc self-tests), random, math, mouse, reboot, panic [text] (deliberate panic).
| Command | Description |
|---|---|
mem <hexaddr> |
read one 32-bit word from kernel memory (a bad address faults the kernel) |
alloc <n> / free <hexaddr> |
allocate from the kernel heap and dump; free reports the call without freeing |
calc <a> <op> <b> / hex <n> / dec <hex> |
integer calculator and base conversion |
color <fg> [bg] / color list / color reset |
console colors |
echo <text> / clear |
print text / clear the screen |
| Command | Description |
|---|---|
ifconfig |
interface status: DHCP address, MAC, counters |
ping <host> |
ICMP echo (not forwarded by QEMU user-mode networking) |
tcpping <host> [port] |
TCP connect probe with RTT |
dns <hostname> |
resolve a name |
mget <url> [-port <n>] [-k] |
HTTP/HTTPS download to the current directory; -k / --insecure skips certificate verification |
httpd / nettask / netdbg |
server status / network task status / stack statistics |
| Command | Type | Description |
|---|---|---|
desktop |
B | EquiX vector desktop (ThorVG); ESC or menu exits |
tvgdemo / tvgbench / tvginfo |
B | ThorVG demo / benchmark / renderer info |
gui / fm / settings |
B | LVGL demo / file manager / settings panel |
snake, breakout, pong |
P | games (self-hosted C sources, built in-OS) |
doom [args] |
B | launch DOOM (default -iwad /doom1.wad; e.g. doom -iwad /mnt/doom1.wad, -warp 1, -nosound) |
beep / song |
B | PC-speaker tone and melody tests |
dbgmouse |
P | mouse diagnostic (SYS_MOUSE) |
hello (minimal MRP), morph_demo / demo_api (SDK and syscall tour), bgcount (background counter for spawn), spin (60-second runner for ps/kill tests), blittest, fstest (24-check file-syscall suite), pipedemo (child writes a pipe, parent reads), elfdemo.elf (static ELF32, exit status 42), and the crash* family — crashde (divide by zero), crashptr (NULL dereference), crashkmem (ring-3 write into kernel memory), crashstk (guard-page recursion) — all of which the shell must survive.
arr, divzero, edge, exec_test, gfxclip, guess, hello, libc, libcmini, libtest, morphgfx, morphio, multitask, negtest, netinfo, pkgtest (pkg API + ANSI demo), pl1-pl5, primes, ringtest, sleeptest, stresstwo, undeftest, varidx.
| Key | Action |
|---|---|
| F1 | open a new shell on a new virtual console |
| F2 | focus the previous console |
| Arrow keys | command history |
| Ctrl+S / Ctrl+Q | save / quit in edit and eqgu |
Requirements (Ubuntu / Debian):
sudo apt install build-essential gcc-multilib g++-multilib nasm \
grub-pc-bin grub-common xorriso mtools qemu-system-x86 python3The makefile auto-detects the toolchain: an i686-elf-g++ cross compiler if present, otherwise the host g++ -m32 (needs gcc-multilib). The LVGL source under kernel/gui/lvgl/ is compiled in when present (-DHAS_LVGL); lwIP and BearSSL come from third_party/.
make pack mtcc # stage tool/game sources + libc + samples; pack mtcc.mrp
make all # kernel.elf + equinox.iso (also stages tool sources and builds elfdemo)
make diskimg # dist/disk.img, 64 MB FAT32 demo disk (needs mtools)
make run-disk # boot the ISO with the disk and networking under QEMU (-m 256)
make run # boot the ISO only (-m 256)
make test # host-side mtcc test harness (no QEMU needed)Notes:
- Do not run
make cleancasually. It removes the wholedist/directory, including prebuiltdoom.mrpanddoom1.wad. - DOOM:
make doomrebuildsdoom.mrpfrom adoomgenericcheckout, which is not bundled here. The full package ships a prebuiltdist/equinox/games/doom.mrp. Put the sharewaredoom1.wadindist/(it becomes a zero-copy boot module) and/or on the disk image. - Version strings can be re-stamped across a tree with
scripts/bump_version.py(dry-run by default; rewrites only string literals and line comments, never identifiers, numeric literals or IP addresses).
The QEMU harness drives the system through the serial log and the QEMU monitor, checking screen contents and serial output. Each subsystem ships its own script under scripts/; adjust the developer-machine paths (ISO location, QEMU install prefix) at the top of each file before running elsewhere.
| Suite | Coverage |
|---|---|
scripts/regression_v03.py, regression_task2.py, regression_task3.py, regression_multitask.py |
boot, self-hosting build, tools battery, demand paging, ELF + bss, spawn / wait / kill / zombie, pipes, meminfo, canvas semantics, games, F1/F2, DOOM 24 MB arena |
scripts/fat32_test.py, fat32_write_test.py |
FAT32 read/write, persistence, host-side mtools oracle, stress to 100 % |
scripts/install_test.py, installer_wizard_test.py, base_img_test.py, bootdisk_test.py |
equinoxinstall modes, .es scripts, base image layout, Qfs -install-boot boot |
scripts/eggkg_test.py, eggkg_net_test.py, eggkg_build_test.py |
eggkg index/download/build/install/remove flows, network transport |
scripts/ecf_test.py, docs_verify_test.py |
.ecf schema/overlay behavior, documentation-vs-code checks |
scripts/v091_banner_test.py, qemu_v10*_test.py |
boot banner (RAM: 256 MB), feature regressions |
make test |
host x86-32 interpreter for the compiler's instruction set (no QEMU) |
- The 1 MB user stack does not grow automatically; hitting the guard page ends the program.
MAX_TASKSis 8, and zombies hold a slot until reaped (the oldest is reclaimed when the table is full).- The paging identity map tops out at 128 MB even when more RAM is installed; the remainder is only reachable through the GUI arena.
- ELF segments must lie in
[0x800000, 0x2000000); ELF tasks get a fixed 2 MB heap. - One FAT32 volume at a time (
/mnt), MBR primary partitions only, 512-byte sectors, no FAT12/16, file names over 63 characters fall back to 8.3. - mtcc is a C subset: no
struct/union, floating point,switch,sizeof,typedef, 2-D arrays, variadic or function-like macros;printftakes at most 5 conversion arguments. - The base ISO ships without the bash-class tools; install the
bashpackage (eggkg install bash) or use the builtins/aliases. - eggkg
package.listv0 carries no versions or hashes (sha256 verification requires anindex.idx), and archive packages are capped at 384 KB. - FAT32 file caches in the disk arena are managed by a free-list, but heavy churn of very large files can fragment it.
- The per-task clip window is not inherited across
spawn, and graphics-program pixels are not preserved after exit (by design). - AHCI is experimental; the ATA PIO driver is the supported path.
boot/ start.asm (VBE, GDT, module staging) and the grub.cfg template
kernel/
kernel.cpp entry point and subsystem bring-up
eggkg.cpp package manager (ring-0 builtin)
shell.cpp eqbash shell, equinoxinstall, Qfs, set/ecf, .es runner, dispatch
library/ paging, malloc, task/scheduler, syscall, stdio (consoles + ANSI + canvas),
libc, idt/timer, ATA/blk/ahci, RAMFS, FAT32 (+write/format), PCI,
ELF + MRP loaders, ecf.c, egg_sha256.c, audio, UI (editor, TUI)
net/ lwIP glue, NE2000, e1000, NIC registry, httpd, TLS client, eggkg fetch
gui/ LVGL 8.3, the file-manager app, and the EquiX desktop (ThorVG glue)
thorvg/ ThorVG vector renderer (0.4 Beta)
libc/ the 13 in-OS libc modules + morph.h (spliced by mtcc <morph.h>)
mrp_user/ Morph.h SDK, MRP packer, linker scripts, DOOM shim, TCC.md, TARGETS.md
tools_user/ userland tools in C (compiled in-OS by equinoxinstall) and elfdemo
games/ Libgame/ snake/breakout/pong sources and the game framework
test/ C sample programs for mtcc
mtcc.c the in-OS C compiler (canonical source, incl. -make/ruf v3)
scripts/ image builder, QEMU regression harnesses, bump_version.py, host mtcc tests
third_party/ lwIP 2.1.3, BearSSL (with root-CA anchors)
docs/ user documentation (Indonesian): getting started, commands,
architecture, eggkg, release notes
dist/ build output: equinox.iso, kernel.elf, disk.img, staged sources, repo/
| Component | Use | License |
|---|---|---|
| LVGL 8.3 | GUI toolkit (file manager, settings) | MIT |
| ThorVG | vector renderer behind the EquiX desktop | MIT |
| lwIP 2.1.3 | TCP/IP stack | BSD-3-Clause |
| BearSSL | TLS 1.2 client (mget, eggkg) | MIT |
| doomgeneric | DOOM engine port | GPL-2.0 (id Software's DOOM source) |
doom1.wad |
shareware DOOM data | id Software shareware terms |
Eggkg-l (the default package repository) is a separate repository: github.com/amnottdevv/Eggkg-l.