grassleaff/everos8
1
1
Fork
You've already forked everos8
0
everos/8 is a minimalist experimental operating system for x86, inspired by the namespace philosophy of Plan 9 and the ascetic simplicity of early Unix-like systems.
  • C 93.6%
  • Assembly 4.2%
  • C++ 1.2%
  • Makefile 0.5%
  • Awk 0.4%
  • Other 0.1%
2026年05月29日 19:10:59 -03:00
apps ADD: integrate musl libc and wire syscall layer to userland apps 2026年05月29日 19:05:55 -03:00
assets Add logo (on assets folder) and improve the README.md 2026年05月25日 16:04:33 -03:00
musl ADD: Update README.md and the musl libc PORTING.md 2026年05月29日 19:10:59 -03:00
src ADD: integrate musl libc and wire syscall layer to userland apps 2026年05月29日 19:05:55 -03:00
.gitignore Initial commit of everos/8 2026年05月25日 13:21:40 -03:00
LICENSE Initial commit 2026年05月25日 16:20:26 +02:00
Makefile ADD: integrate musl libc and wire syscall layer to userland apps 2026年05月29日 19:05:55 -03:00
README.md ADD: Update README.md and the musl libc PORTING.md 2026年05月29日 19:10:59 -03:00

everos8

The everos/8 project is a minimal operating system for x86, written in C and assembly. Everything in the system is a node in a hierarchical namespace tree, inspired by Plan 9 from Bell Labs.


The design

In Plan 9, there is no distinction between reading a file, querying a process, or talking to a device, every resource is a path you open, read, and write. everos/8 applies the same idea at the smallest possible scale:

/
├── dev/
│ ├── cons read: keyboard | write: screen
│ ├── null discards writes, returns empty on read
│ └── rand returns pseudo-random bytes on read
├── proc/
│ └── shell read: current process state
├── sys/
│ ├── version
│ └── motd
└── fs/ user-created files

ns_read(node, buf, len) works identically whether node is a plain file, a device, or a proc entry. That uniformity is the entire point.


Memory layout

0x010000 – 0x1FFFFF kernel image (code + data + stack)
0x200000 – 0x3FFFFF kernel heap (kmalloc free-list allocator)
0x400000 – userland / musl brk region

The heap is a first-fit free-list allocator with immediate coalescing on kfree. kmalloc / kzalloc / kfree are available everywhere in the kernel after mm_init().


Syscall ABI

Userland communicates with the kernel via int 0ドルx30 (not Linux's int 0ドルx80). The register convention mirrors i386 Linux so musl can be ported with a one-file change:

Register Role
eax syscall number
ebx arg 1
ecx arg 2
edx arg 3
eax return value

Syscalls implemented so far:

Number Name Description
0 exit terminate the current app
1 write write bytes to VGA (fd 1 or 2)
3 read read a line from the keyboard (fd 0)
7 getpid returns 1
45 brk move the userland heap break

musl libc port

everos/8 ships with a port of musl libc 1.2.4 under musl/. The entire port required changing exactly two files from upstream:

File Change
musl/arch/i386/syscall_arch.h int 0ドルx80 -> int 0ドルx30
musl/arch/i386/bits/syscall.h.in everos/8 syscall numbers

All 1500+ other musl source files are unmodified. Apps in apps/ are compiled against musl and linked statically into the kernel binary, so standard headers like <unistd.h>, <string.h>, and <stdlib.h> work out of the box.

musl port status:

Phase Modules Syscalls needed Status
1 string, stdlib, ctype, prng none done
2 stdio (printf, fgets...) write, read next
3 malloc / free brk next
4 unistd (getpid, sleep...) exit, getpid next

Writing an app

Apps live in apps/ and are compiled with musl headers. Add an entry to the table in src/kernel/app.c to register it with the shell.

// apps/hello.c
#include <unistd.h>
int hello_main(void) {
 const char msg[] = "hello from everos/8\n";
 write(1, msg, sizeof(msg) - 1);
 return 0;
}
// src/kernel/app.c — register the new app
static const App apps[] = {
 { "hello", hello_main },
 { "myapp", myapp_main }, // add here
};

From the shell:

/ apps — list available apps
/ run hello — run an app

Requirements

sudo apt install binutils gcc-multilib qemu-system-x86 make gdb

Tested on Debian 13 (trixie) x86-64. The toolchain targets i386.


Building

make

Produces everos.img, a raw ~1.40 MB disk image.


Running

make run # inside the terminal (QEMU curses display)
make run-sdl # separate SDL window

To quit QEMU: Ctrl-A then X (curses), or close the window (SDL).

Manual invocation:

qemu-system-i386 -drive file=everos.img,format=raw,index=0,media=disk -m 32M

Debugging

make debug

Starts QEMU paused and waiting for GDB on port 1234, then launches GDB connected to it.


Shell commands

Command Description
ls [path] List nodes in a directory
read <path> Read a node
write <path> <text> Write text to a node
echo <text> Print text to the screen
mkfile <path> [text] Create a file
mkdir <path> Create a directory
touch <path> Create an empty file
rm <path> Remove a node
mv <src> <dst> Move or rename a node
dd if=<src> of=<dst> Copy data between nodes
stat <path> Show node metadata
cd [path] Change working directory
ps List running processes
mem Show heap usage
apps List available apps
run <name> Run an app
clear Clear the screen
about About
help List commands

Tab completion and arrow-key history navigation are supported.


Boot sequence

  1. QEMU loads the boot sector (boot.S) at 0x7C00 in real mode.
  2. The bootloader reads 32 sectors from disk into physical address 0x10000 via INT 13h.
  3. A20 is enabled, the GDT is loaded, and the CPU switches to 32-bit protected mode.
  4. Execution jumps to entry.S at 0x10000, which sets up segment registers and the stack.
  5. kernel_main() initialises the heap, VGA, namespace tree, process table, and IDT.
  6. The scheduler loop runs shell_run() on every tick.

Limitations

  • No virtual memory or paging.
  • No hardware timer; the scheduler is purely cooperative.
  • Apps are linked statically into the kernel image (no on-disk loading yet).
  • No disk persistence — the namespace resets on reboot.
  • x86 (i386) only.