Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fukOS

CI License Last commit Architecture Bootloader

fukOS is a hobby 32-bit i686 operating system written in freestanding C and assembly. It boots through Limine/Multiboot2, uses its own framebuffer console, storage, keyboard, audio, FAT layer, shell, text editor, and a Doom Generic port.

The main hardware target is Acer Aspire ES1-533 with Intel Pentium N4200 / Apollo Lake and a 1366×768 display.

Contents

Screenshots

Shell Clock app Fastfetch
shell clock fastfetch
ls/tree output on real Acer hardware Full-screen flip clock Live system status card (ff)

Current feature set

  • Limine Multiboot2 boot path.
  • Linear framebuffer graphics with write-combining setup.
  • RAM shadow framebuffer for console/editor rendering.
  • Wallpaper and terminal transparency from fuko.conf.
  • PS/2 scancode set 1 keyboard input via firmware USB Legacy Emulation.
  • CPUID/PIT-based TSC frequency detection for software key repeat.
  • Shell with editable command line, history, scrollback, and tab completion.
  • External .fuk applications loaded from /apps at runtime by the FUK1 VM.
  • Full-screen terminal clock app with large flip-clock-style hour/minute cards.
  • Configurable BMP startup splash loaded from fuko.conf after storage mount.
  • FAT16/FAT32 storage over ATA PIO or xHCI USB Mass Storage.
  • File commands: ls, cd, pwd, tree, cat, head, wc, hexdump, touch, mkdir, rmdir, rm, cp, mv, echo.
  • Full-screen edit editor with undo, search, partial redraw, and fast blocking input.
  • BMP image/photo viewer with fit/fill modes.
  • Intel HDA output with foreground WAV playback and background bgplay playlists.
  • Doom Generic port linked into the kernel.
  • Background music continues while playing DOOM.
  • Physical-memory kernel heap initialized from the Multiboot2 memory map.
  • heaptest command for heap allocation tests.
  • IDT exception handling, remapped 8259 PIC, and a 100 Hz PIT timer IRQ.
  • Kernel panic screen with register, exception, error-code, and CR2 dump.
  • COM1 serial logging for boot diagnostics and panic reports.
  • DOOM save files are written as real FAT files and can be loaded after reboot.
  • ACPI shutdown and keyboard-controller reboot fallback.

Building on Arch Linux

Install the build utilities and runtime dependencies:

sudo pacman -Syu
sudo pacman -S --needed base-devel nasm python qemu-system-x86 limine

The supported build uses an i686-elf cross-toolchain. Install or build i686-elf-gcc and i686-elf-binutils, then verify that i686-elf-gcc and i686-elf-ld are in PATH.

Build the kernel:

make clean
make kernel.bin CROSS=i686-elf-

Build a bootable BIOS/UEFI disk image with the packaged Limine files:

make limine CROSS=i686-elf-

Run the image in QEMU using KVM when available, with TCG as a fallback:

make run-limine CROSS=i686-elf-
# or: ./run.sh

For UEFI testing, install edk2-ovmf and pass its firmware explicitly:

sudo pacman -S --needed edk2-ovmf
make run-limine CROSS=i686-elf- OVMF=/usr/share/edk2/x64/OVMF_CODE.fd

If Limine is unpacked locally rather than installed from the Arch package, set LIMINE_DIR:

make limine CROSS=i686-elf- LIMINE_DIR="$HOME/src/limine"

The generated image is os-limine.img. See docs/09-build-and-run.md for dependency checks, QEMU options, and USB deployment.

Typical hardware test flow

ff
heaptest
bgplay *.wav
doom

Recommended DOOM save test:

  1. Start DOOM.
  2. Save to a slot.
  3. Exit DOOM.
  4. Run ls and verify a file such as doomsav0.dsg exists.
  5. Reboot.
  6. Start DOOM again and load the save from the menu.

Shell controls

Key Action
Left / Right Move through current command
Home / End Move to beginning / end
Backspace / Delete Delete before / under cursor
Up / Down Browse command history
Shift+Up / Shift+Down Scroll shell output one row
Page Up / Page Down Scroll shell output one page
Tab Complete command, file, or directory name

Some shell commands

ff                 live system card with RAM/heap/disk/audio bars
heaptest           test kernel heap alloc/free/calloc/realloc behavior
irqinfo            show PIT interrupt ticks and COM1 status
panic-test confirm deliberately trigger a breakpoint panic and register dump
open <file>        open by type: text->edit, BMP->photo, WAV->play
start calc         run /apps/calc.fuk without linking it into the kernel
bgplay <file.wav>  start background WAV playback
bgplay *.wav       queue all WAV files in current directory
doom               start DOOM
clock              full-screen flip clock
edit <file>        full-screen text editor
photo [file]       full-screen BMP gallery/viewer

Text editor

edit <filename>

The editor supports arrows, Home, End, Page Up, Page Down, Backspace, Delete, Tab, Enter, Ctrl+F search, Ctrl+Z undo, Ctrl+K delete line, Esc/Ctrl+X save and exit, and Ctrl+Q quit without saving.

The editor waits through kbd_getchar(). Do not reintroduce non-blocking idle loops with repeated io_wait() or port 0x80 writes; that caused severe input latency on the real Acer.

Memory and heap

The kernel uses many explicit static buffers for predictable bare-metal behavior, and initializes a simple physical-memory heap from the largest suitable usable Multiboot2 memory-map range above the kernel image.

Heap implementation:

  • first-fit free list;
  • 16-byte alignment;
  • block splitting;
  • adjacent free-block coalescing;
  • kheap_alloc, kheap_calloc, kheap_realloc, kheap_free;
  • kheap_get_info for statistics;
  • heaptest for runtime validation.

DOOM reserves a private 32 MiB arena from this kernel heap for each run and frees it on exit.

External applications

fukOS loads .fuk applications directly from /apps on the FAT partition. They are not linked into KERNEL.BIN, so a new application can be copied to the USB drive without rebuilding the kernel:

/apps/hello.fuk  ->  start hello
/apps/tetris.fuk ->  start tetris

Every FUK1 source file starts with FUK1. Instructions are written one per line, and control flow uses labels and conditional jumps:

FUK1
set i 1
label loop
printv i
println
add i i 1
if_le i 10 loop
exit

Games use a non-blocking frame loop:

FUK1
clear
set x 10
set y 8
label frame
sleep 50
key_poll key
if_eq key 113 quit
if_eq key 130 left
if_eq key 131 right
goto draw
label left
sub x x 1
goto draw
label right
add x x 1
label draw
clear
cursor x y
print @
goto frame
label quit
exit

The VM provides dynamic integer, float, and string variables; arithmetic and bit operations; typed comparisons with direct true/false branches; labels; call/return; a 4,096-element integer array; safe conversions and string helpers; random numbers; terminal queries/positioning/colors, blocking and non-blocking keyboard input, and bounded timing. Applications may use up to 512 KiB of source, 256 variables, 64 nested calls, and 100,000,000 executed instructions per launch. VM state is allocated from the kernel heap instead of the shell stack, and labels are indexed once at startup for faster jumps in large programs.

A complete 10×20 Tetris implementation is included at apps/tetris.fuk. It demonstrates seven tetrominoes, collision detection, rotation, line removal, scoring, rendering, arrays, random pieces, and a real-time keyboard loop. Copy it to /apps/tetris.fuk on the USB drive and run start tetris.

Documentation:

DOOM integration

The doom/ directory contains a Doom Generic-style port linked directly into the kernel. DOOM shares the kernel address space and is not a separate process.

Important implementation points:

  • DOOM global state is restored before each launch using linker-isolated data/BSS ranges.
  • DOOM uses a private heap arena allocated from the kernel heap.
  • DOOM polls keyboard directly, so its platform loop explicitly services hda_bg_poll() and xhci_idle_drain().
  • This keeps shell-started bgplay music running while DOOM is active.
  • DOOM save files are bridged through the freestanding libc to FAT and persist across reboot.

Providing the IWAD

The IWAD is not part of this repository and is not compiled into the kernel. You have to supply it yourself:

  1. Obtain a DOOM IWAD you are entitled to use: the freely redistributable shareware doom1.wad - link
  2. On the running system the file is looked up as doom1.wad in the current directory, the volume root, /doom/, or /apps/.

Without an IWAD the doom command prints where to put the file and returns to the shell. Keeping the WAD out of the kernel also makes kernel.bin about 4 MB smaller.

Repository layout

kernel/        kernel, drivers, shell, editor, heap, Multiboot2 entry code
apps/          FUK1 applications copied to /apps on the boot medium
doom/          Doom Generic port (IWAD is supplied by the user, not bundled)
tools/         Limine FAT image builder
tests/         host unit tests and fuzz harness for the .fuk parser and labels
docs/          technical documentation
Makefile       kernel, image, and host test build rules
limine.conf    Limine boot configuration
.github/       GitHub Actions CI workflow

Host tests

The lexical layer of the .fuk interpreter (kernel/fuk_parse.c) and its label indexing and branch resolution (kernel/fuk_labels.c) are pure functions of their input with no kernel or libc dependencies, so they build and run on the host without a cross-toolchain:

make test                    # unit tests (ASan/UBSan by default)
make fuzz                    # deterministic fuzzer, plain gcc/clang
make fuzz FUZZ_ITERS=1000000 FUZZ_SEED=0xdeadbeef
make fuzz-libfuzzer HOSTCC=clang FUZZ_TIME=300   # coverage-guided

Use SAN= to build the host targets without sanitizers. The fuzzer prints the seed it was started with, so a CI failure can be replayed with make fuzz FUZZ_SEED=<seed from the log>.

Both make test and make fuzz run in CI on every push; see .github/workflows/ci.yml, which also builds kernel.bin and boots os-limine.img in QEMU, checking the serial log for the early klog lines and failing on a panic.

Current limitations

  • 32-bit i686 only; no SMP or 64-bit mode.
  • Single address space, ring 0 only, and no process isolation.
  • No paging, virtual memory, memory protection, or swap.
  • No scheduler, processes, threads, signals, or executable loader.
  • .fuk apps currently run inside a small interpreted VM; native ELF programs are not supported.
  • Keyboard, xHCI, and HDA are still serviced cooperatively; only the PIT uses an IRQ.
  • Storage support is limited to FAT16/FAT32 over ATA PIO or one xHCI USB Mass Storage device.
  • No journaling, permissions, users, networking, USB HID driver, or package manager.
  • Hardware-specific xHCI and Intel HDA support remains incomplete outside the target laptop.
  • Audio is limited to uncompressed PCM WAV; images are limited to BMP and IMG1.
  • RTC time has no configured timezone, NTP synchronization, or century-register handling.
  • The kernel has no automated bare-metal regression suite; real-hardware checks remain manual. Host tests and fuzzing cover the .fuk lexer and label table; CI additionally boots the image in QEMU and checks the serial log. The rest of the VM and the drivers are untested.
  • FAT operations take an exclusive driver-wide lock: the cluster and FAT-sector buffers are still shared statics, so a nested call is refused rather than served.

Development roadmap

Near-term - architecture debt

  1. Move PS/2, xHCI, and HDA toward IRQ-driven operation with synchronization primitives.
  2. Move the FAT driver's shared cluster and FAT-sector buffers into a per-operation context instead of the current exclusive-lock workaround.

Mid-term - isolation and safety

  1. Add paging with guard pages, a higher-half kernel, and a safer physical-page allocator.
  2. Introduce a preemptive scheduler, ring-3 processes, syscalls, and an ELF loader.
  3. Add a VFS layer, read-only ISO9660/ext2 support, and transactional FAT write recovery.
  4. Implement USB HID keyboards/mice without relying on firmware legacy emulation.

Long-term - userspace and beyond

  1. Build a userspace terminal, file manager, system monitor, and settings application.
  2. Add PNG/JPEG decoding, scalable fonts, mouse input, and window compositing.
  3. Add an RTL8139 or Intel e1000 driver, IPv4, DHCP, DNS, ICMP, and a small TCP stack.
  4. Add ACPI table parsing for power, battery, thermal state, and reliable reboot/shutdown.

Third-party material

The DOOM engine code in doom/ derives from id Software's DOOM source release and the doomgeneric port. Those sources are licensed GPL-2.0-or-later and are used here under the GNU GPL v2. Original DOOM source code is Copyright (C) 1993-1996 id Software, Inc.; later changes are Copyright (C) 2005-2014 Simon Howard and other Chocolate Doom contributors.

No DOOM game data ships with this repository. doom1.wad and any other IWAD is copyrighted by id Software / ZeniMax Media / Microsoft, is not covered by this project's GPL-2.0 license, and must be supplied by the user (see Providing the IWAD).

About

fukOS is a hobby 32-bit i686 operating system written in C. Boots via Limine/Multiboot2. Own framebuffer console, xHCI/ATA storage, FAT layer, keyboard, HDA audio, shell, text editor, and a Doom Generic port.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages