Vostok

System overview

Vostok began with a stricter goal than “make a kernel that boots.” The system had to carry a program through its entire life: edit source code inside the OS, compile it into a native executable, load it into a private address space and run it without giving the process ambient access to the machine.

That constraint shaped the project. Memory management, scheduling, IPC, files, capabilities and the Iskra compiler were not developed as isolated demonstrations. Each subsystem had to participate in one working vertical path.

A source file becomes a real x86-64 ELF process without leaving Vostok.

Architecture

Vostok is a reproducible research prototype for x86-64. Limine boots a freestanding kernel; the kernel then brings up userspace services including init, a UART console service, an interactive shell, an editor and the native Iskra compiler.

The architecture keeps the execution model intentionally narrow: one core, one thread per process and a round-robin scheduler. This made ownership, isolation and cleanup explicit before adding broader abstractions.

Physical and virtual memory

Physical memory is divided into 4 KiB pages and tracked with separate managed and allocated states. This distinction lets the allocator reject out-of-range, reserved-page and double frees.

Every process receives a private lower-half address space, a guarded user stack and its own page tables. The kernel and higher-half direct map remain shared above it. When a process exits, its pages, page tables and stacks are reclaimed together.

Preemptive scheduling

The scheduler is driven by the local APIC timer. On each tick the interrupt path saves the complete user register frame, selects the next runnable process, switches CR3 and TSS.RSP0, and returns through iretq.

Two CPU-bound Iskra programs that never call into the kernel are part of the regression workload. If both complete, scheduling is genuinely preemptive rather than cooperative by accident.

IPC and capabilities

Processes do not receive ambient access to devices or services. Handles encode both a table slot and a generation; every lookup checks the object type and the rights required for the operation. Closing a handle advances its generation, so stale handles stop being valid.

IPC uses synchronous rendezvous endpoints and can transfer a capability with a message. Rights may be preserved or reduced during transfer, but never amplified. The shell, for example, cannot touch UART directly: all character I/O crosses an IPC endpoint owned by the console service.

Edit, build and run

The visible demonstration runs after boot, entirely inside Vostok:

vostok> edit /home/demo.isk
fn main() -> i32 {
    print("hello from native iskra\n");
    return 0;
}

vostok> build /home/demo.isk
iskrac: native x86-64 elf written to /home/a.out

vostok> run /home/a.out
hello from native iskra

build starts a compiler process written in Iskra. It reads the source through a filesystem capability and emits ELF64 directly, without an assembler or linker inside Vostok. run validates that file, maps its loadable segment into a fresh address space and starts it at ring 3.

The compiler is intentionally a bootstrap subset rather than a claim of full self-hosting. Its purpose is to prove that the edit-build-run loop crosses real process, filesystem, capability and executable boundaries.

Implementation decisions

Several implementation choices favour visible invariants over premature generality.

  • A rotating bitmap allocator is sufficient while contiguous physical allocation is not required; a buddy allocator would add machinery without solving a current problem.
  • Synchronous IPC makes the sender-receiver rendezvous and capability transfer easy to reason about before endpoint queues are introduced.
  • The local APIC timer replaces the legacy PIT/PIC path and matches the Q35 environment used for regression testing.
  • Static ELF64 loading keeps mapping, validation and lifetime rules inspectable before dynamic linking exists.

These are constraints, not hidden shortcuts. They define the system that is tested today.

Testing and metrics

Host tests cover the Iskra frontend and low-level data structures. QEMU regression tests exercise the boundaries that mocks cannot: page-table switches, ring-3 execution, exceptions, preemption, IPC denial and transfer, process cleanup, ramfs editing, dynamic ELF loading and the complete edit-build-run scenario.

Vostok also exposes live measurements for compiler timing, binary sizes, context switches, preemptions, scheduler cycles, IPC latency, UART interrupts and reclaimed pages. The metrics exist to make system behaviour inspectable, not to imply production performance.

Current limitations

Vostok is a working, vertically integrated operating-system experiment. It is not yet a general-purpose OS: there is no SMP, demand paging, copy-on-write, networking, persistent storage, dynamic linking, POSIX layer or production hardening.

Keeping those limits visible is part of the project. The result is small enough to understand end to end, but complete enough to demonstrate the difficult boundary: a language, compiler, kernel and userspace cooperating to turn source code into an isolated native process.

Explore the source on GitHub