Skip to main content

Introduction

Portix OS is a bare-metal x86_64 kernel written in Rust, designed to boot directly on hardware without relying on an external bootloader or operating system. The kernel demonstrates modern OS development practices including custom memory management, interrupt handling, and a complete driver stack.
Portix OS v0.7.4 is a monolithic kernel that boots from BIOS, transitions through multiple CPU modes, and runs entirely in 64-bit long mode.

High-Level Architecture

The system follows a layered architecture:
┌─────────────────────────────────────────┐
│         User Interface Layer           │
│    (Terminal, IDE, File Explorer)      │
├─────────────────────────────────────────┤
│         System Services Layer          │
│  (Console, Graphics, File System)      │
├─────────────────────────────────────────┤
│          Driver Layer                  │
│  (Keyboard, Mouse, ATA, Serial)        │
├─────────────────────────────────────────┤
│        Core Kernel Layer               │
│  (Memory, Interrupts, Scheduling)      │
├─────────────────────────────────────────┤
│       Hardware Abstraction             │
│  (IDT, GDT, Paging, PIC)              │
└─────────────────────────────────────────┘

Directory Structure

The kernel source code is organized into logical modules:
Bootloader components written in x86 assembly:
  • boot.asm - Stage 1 bootloader (512 bytes, MBR)
  • stage2.asm - Stage 2 bootloader (handles mode transitions)
Architecture-specific code for x86_64:
  • idt.rs - Interrupt Descriptor Table setup
  • isr_handlers.rs - Interrupt Service Routines
  • isr.asm - Low-level ISR stubs
  • hardware.rs - CPU detection and features
Memory management subsystem:
  • allocator.rs - Buddy system allocator (O(log N))
  • Implements Rust’s GlobalAlloc trait
  • Manages heap from 0x400000 with configurable size
Device drivers:
  • input/keyboard.rs - PS/2 keyboard driver
  • input/mouse.rs - PS/2 mouse with scrollwheel
  • storage/ata.rs - ATA/IDE disk driver
  • storage/fat32.rs - FAT32 filesystem
  • serial.rs - COM1 serial port (debugging)
  • bus/pci.rs - PCI bus enumeration
Framebuffer graphics:
  • driver/framebuffer.rs - VESA mode setup
  • font.rs - Bitmap font rendering (8x14)
  • Double-buffered rendering at 30 Hz
Terminal and command system:
  • terminal/mod.rs - Line-based terminal
  • terminal/commands/ - Built-in commands
  • terminal/editor.rs - Text editor
User interface components:
  • tabs/system.rs - System information tab
  • tabs/ide.rs - Integrated development environment
  • tabs/explorer.rs - File browser
  • Chrome and navigation UI

Module Organization

The kernel’s main.rs declares the module hierarchy:
kernel/src/main.rs
pub mod arch;       // Architecture-specific (x86_64)
pub mod console;    // Terminal and command processing
pub mod drivers;    // Hardware drivers (input, storage, bus)
pub mod graphics;   // Framebuffer and rendering
pub mod mem;        // Memory management (allocator)
pub mod time;       // PIT timer (100 Hz)
pub mod ui;         // User interface components
pub mod util;       // Formatting and utilities

Component Interaction

Here’s how the major components interact during runtime:
All components run in kernel mode (ring 0) with full hardware access. There is no user/kernel mode separation in the current design.

Initialization Sequence

The kernel follows a strict initialization order in rust_main() (main.rs:192):
1

Memory Allocator

Initialize the buddy allocator to enable dynamic memory allocation
unsafe { ALLOCATOR.init(); }
2

Page Pool

Initialize memory pool for UI page management
init_page_pool();
3

Interrupts

Set up IDT, GDT, TSS, and enable interrupts
unsafe { arch::idt::init_idt(); }
4

Drivers

Initialize serial port, PIT timer (100 Hz), keyboard, and mouse
drivers::serial::init();
time::pit::init();
5

Hardware Detection

Detect CPU features and scan PCI bus
let hw = arch::hardware::HardwareInfo::detect_all();
let pci = drivers::bus::pci::PciBus::scan();
6

Storage

Scan ATA bus and mount FAT32 filesystem
let ata = ata::AtaBus::scan();
let vol = fat32::Fat32Volume::mount(drive);
7

Main Loop

Enter the event loop: process input, render UI, handle events

Boot Protocol

Portix OS uses a two-stage bootloader:
  1. Stage 1 (boot.asm) - Loaded by BIOS at 0x7C00, loads Stage 2
  2. Stage 2 (stage2.asm) - Switches to long mode, loads kernel
  3. Kernel - Rust entry point at rust_main()
See the Boot Process page for detailed information.

Memory Layout

Portix OS uses identity mapping for the first 1 GB of physical memory. The framebuffer is mapped separately based on its physical address from VESA.
Address RangeUsage
0x0000 - 0x0FFFReal mode IVT (preserved)
0x1000 - 0x4FFFPage tables (PML4, PDPT, PD)
0x6000 - 0x6FFFVESA info buffer
0x7C00 - 0x7DFFStage 1 bootloader
0x8000 - 0xFFFFStage 2 bootloader
0x9000 - 0x9FFFBoot info structure
0x10000+Kernel binary
0x400000+Heap (managed by buddy allocator)
0x600000+Double-buffer for framebuffer

Design Philosophy

No Dependencies

Completely no_std - no standard library, libc, or external runtime

Bare Metal

Direct hardware access, no hypervisor or firmware dependencies beyond BIOS

Safety First

Rust’s type system prevents many common OS bugs, with unsafe only where needed

Real Hardware

Designed to boot on real x86_64 hardware (VirtualBox, QEMU, physical machines)

Next Steps

Boot Process

Learn how Portix OS transitions from BIOS to 64-bit mode

Memory Management

Explore the buddy allocator and heap management

Interrupt Handling

Understand how interrupts and exceptions are processed

Build docs developers (and LLMs) love