Home OS Kernel Architecture

On this page 61

Last Updated: 2025-10-24 Version: 0.1.0 Status: Development (76% Complete)

Table of Contents

  1. Overview
  2. System Architecture
  3. Memory Management
  4. Process Management
  5. File Systems
  6. Network Stack
  7. Device Drivers
  8. Interrupt Handling
  9. Synchronization
  10. Boot Sequence

Overview

Home OS is a modern, microkernel-inspired operating system written in Zig that targets both x86-64 and ARM64 (AArch64) architectures. The kernel emphasizes safety, performance, and modularity.

Design Principles

  • Memory Safety: Leveraging Zig's compile-time safety guarantees
  • Modularity: Clear separation between kernel subsystems
  • Performance: Zero-copy operations, lock-free algorithms where possible
  • Portability: Architecture-agnostic core with platform-specific implementations

Key Features

Multi-Architecture Support: x86-64, ARM64 (AArch64) ✅ Modern Memory Management: 3 allocators (Bump, Slab, Buddy), COW, TLB shootdown ✅ Multi-tasking: Round-robin and priority scheduling, SMP support ✅ File Systems: ext2 and FAT32 (read/write) ✅ Network Stack: ARP, IPv4, TCP, UDP with full socket API ✅ Device Drivers: AHCI, NVMe, e1000, xHCI with error recovery ✅ Comprehensive Testing: 550+ tests across all subsystems


System Architecture

High-Level Design

┌──────────────────────────────────────────────────────────────────┐
│                        User Space                                 │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐       │
│   │  Shell   │  │   Apps   │  │ Services │  │Libraries │       │
│   └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘       │
└────────┼──────────────┼──────────────┼──────────────┼────────────┘
         │              │              │              │
┌────────┼──────────────┼──────────────┼──────────────┼────────────┐
│        │       System Call Interface (25 syscalls)  │            │
├────────┴──────────────┴──────────────┴──────────────┴────────────┤
│                        Kernel Space                               │
│   ┌────────────┐  ┌───────────┐  ┌────────────┐                 │
│   │  Process   │  │  Memory   │  │    VFS     │                 │
│   │   Mgmt     │  │   Mgmt    │  │            │                 │
│   └─────┬──────┘  └─────┬─────┘  └─────┬──────┘                 │
│         │                │               │                        │
│   ┌─────┴──────┬─────────┴────────┬──────┴──────┐               │
│   │ Scheduler  │  Page Tables     │ ext2/FAT32  │               │
│   │(Round Robin│  (4-level x86-64,│             │               │
│   │ Priority)  │   3-level ARM64) │             │               │
│   └────────────┘  └──────────────┘  └────────────┘               │
│                                                                   │
│   ┌───────────────────────────────────────────────────────────┐ │
│   │         Network Stack (ARP, IPv4, TCP, UDP)               │ │
│   └───────────────────────────────────────────────────────────┘ │
│                                                                   │
│   ┌───────────────────────────────────────────────────────────┐ │
│   │      Device Drivers (AHCI, NVMe, e1000, USB xHCI)         │ │
│   └───────────────────────────────────────────────────────────┘ │
│                                                                   │
│   ┌───────────────────────────────────────────────────────────┐ │
│   │     Interrupt Handlers (20 exceptions + IRQs + IPIs)      │ │
│   └───────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘

┌─────────────────────────────┴──────────────────────────────────┐
│                      Hardware Layer                             │
│   CPU │ MMU │ Timers │ Storage │ Network │ USB │ GPIO │ ...   │
└─────────────────────────────────────────────────────────────────┘

Package Structure

packages/
├── kernel/src/           # Core kernel
│   ├── memory.zig       # Memory allocators (Bump, Slab, Buddy)
│   ├── paging.zig       # Page tables, COW, TLB
│   ├── process.zig      # Process management
│   ├── scheduler.zig    # Task scheduler
│   ├── syscall.zig      # System call interface
│   ├── interrupts.zig   # Exception/interrupt handlers
│   ├── apic.zig         # APIC/x2APIC, IPIs
│   ├── sync.zig         # Spinlocks, mutexes
│   └── dma.zig          # DMA, IOMMU, bounce buffers
├── fs/src/              # File systems
│   ├── vfs.zig          # Virtual File System
│   ├── ext2.zig         # ext2 filesystem
│   └── fat32.zig        # FAT32 filesystem
├── net/src/             # Network stack
│   └── network.zig      # ARP, IPv4, TCP, UDP, sockets
├── drivers/src/         # Device drivers
│   ├── ahci.zig         # SATA (AHCI)
│   ├── nvme.zig         # NVMe SSD
│   ├── e1000.zig        # Intel gigabit ethernet
│   └── usb/xhci.zig     # USB 3.0 (xHCI)
└── platform/            # Platform-specific code
    ├── x86_64/          # x86-64 implementation
    └── aarch64/         # ARM64 implementation

Memory Management

Virtual Address Space Layout

x86-64 (48-bit addressing)

0xFFFF_FFFF_FFFF_FFFF  ┌───────────────────────────────────┐
                       │  Kernel Space (Higher Half)       │
0xFFFF_8000_0000_0000  ├───────────────────────────────────┤
                       │  Kernel Heap (Buddy/Slab)         │
                       ├───────────────────────────────────┤
                       │  Kernel Stack                     │
                       ├───────────────────────────────────┤
                       │  Kernel Code & Data               │
                       │  (Identity Mapped from 0x100000)  │
0xFFFF_8000_0010_0000  ├───────────────────────────────────┤
                       │                                   │
                       │  Canonical Hole                   │
                       │  (Non-canonical addresses)        │
                       │                                   │
0x0000_7FFF_FFFF_FFFF  ├───────────────────────────────────┤
                       │  User Stack (grows down)          │
0x0000_7FFF_0000_0000  ├───────────────────────────────────┤
                       │  Memory-Mapped Files / Shared Mem │
0x0000_6000_0000_0000  ├───────────────────────────────────┤
                       │  User Heap (grows up)             │
0x0000_0100_0000_0000  ├───────────────────────────────────┤
                       │  User Data (.data, .bss)          │
0x0000_0000_0080_0000  ├───────────────────────────────────┤
                       │  User Code (.text)                │
0x0000_0000_0040_0000  ├───────────────────────────────────┤
                       │  NULL Guard (unmapped)            │
0x0000_0000_0000_0000  └───────────────────────────────────┘

Memory Allocators

Home OS uses a three-tier allocator strategy optimized for different use cases:

1. Bump Allocator (memory.zig:BumpAllocator)

Purpose: Ultra-fast allocation during early boot

pub const BumpAllocator = struct {
    current: usize,
    limit: usize,
    lock: sync.Spinlock,

    pub fn alloc(size: usize, alignment: usize) ![]u8 {
        // O(1) allocation
        // Just bump the pointer forward
    }
};

Characteristics:

  • Time Complexity: O(1) allocation
  • Space Overhead: Minimal (just two pointers)
  • Fragmentation: None (no freeing)
  • Thread Safety: Spinlock-protected
  • Use Case: Boot-time allocations before heap is ready

2. Slab Allocator (memory.zig:SlabAllocator)

Purpose: Fixed-size kernel object allocation (processes, file descriptors, etc.)

pub fn SlabAllocator(comptime T: type) type {
    return struct {
        free_list: ?_Slab,
        lock: sync.Spinlock,

        pub fn alloc() !_T { /_ O(1) _/ }
        pub fn free(ptr: _T) void { /_ O(1) */ }
    };
}

Characteristics:

  • Time Complexity: O(1) alloc/free
  • Fragmentation: Minimal (same-size objects)
  • Cache Locality: Excellent (LIFO free list)
  • Per-Type Caches: Separate slab for each kernel object type
  • Use Case: Kernel data structures (Process, FileDescriptor, Socket, etc.)

3. Buddy Allocator (memory.zig:BuddyAllocator)

Purpose: General-purpose variable-size allocation

pub const BuddyAllocator = struct {
    const MAX_ORDER: usize = 11;  // 2^11 = 8MB max
    free_lists: [MAX_ORDER]?_Block,
    lock: sync.Spinlock,

    pub fn alloc(size: usize) ![]u8 { /_ O(log n) _/ }
    pub fn free(memory: []u8) void { /_ O(log n) with coalescing */ }
};

Characteristics:

  • Block Sizes: Powers of 2 from 4KB (20 × 4KB) to 8MB (210 × 4KB)
  • Time Complexity: O(log n) allocation, O(log n) freeing
  • Coalescing: Automatic buddy merging on free
  • Fragmentation: Moderate (external fragmentation from power-of-2 rounding)
  • Use Case: Dynamic kernel allocations, DMA buffers

Buddy Algorithm:

Allocate 12KB:

1. Round up to next power-of-2: 16KB (order 2)
2. Search free lists from order 2 upward
3. If order 4 block found (64KB):
   - Split 64KB → 32KB + 32KB (order 3)
   - Split 32KB → 16KB + 16KB (order 2)
   - Return first 16KB, add buddies to free lists

Free 16KB at address A:

1. Check if buddy at A^16KB is free
2. If yes: merge → 32KB, check next level
3. Repeat until buddy is allocated

Page Table Management

x86-64 Paging (4-Level)

Virtual Address (48-bit):
┌──────┬──────┬──────┬──────┬────────┐
│ PML4 │ PDP  │  PD  │  PT  │ Offset │
│ 9bit │ 9bit │ 9bit │ 9bit │ 12bit  │
└──────┴──────┴──────┴──────┴────────┘
 [47:39][38:30][29:21][20:12] [11:0]

Translation Process:

1. CR3 register → PML4 base address
2. VA[47:39] → Index into PML4 → PDP address
3. VA[38:30] → Index into PDP → PD address
4. VA[29:21] → Index into PD → PT address
5. VA[20:12] → Index into PT → Physical page
6. VA[11:0]  → Offset within 4KB page

Page Table Entry (x86-64)

Bit 63:     Execute Disable (NX)
Bits 62-52: Available for OS use
Bits 51-12: Physical address (40 bits)
Bit 11-9:   Available for OS
Bit 8:      Global (G)
Bit 7:      Page Size (PS)
Bit 6:      Dirty (D)
Bit 5:      Accessed (A)
Bit 4:      Cache Disable (PCD)
Bit 3:      Write-Through (PWT)
Bit 2:      User/Supervisor (U/S)
Bit 1:      Read/Write (R/W)
Bit 0:      Present (P)

COW Marker: We use available bit 9 to mark Copy-on-Write pages.

Copy-on-Write (COW)

Location: paging.zig:PageRefCount, paging.zig:CowHandler

COW Fork Flow


1. Parent process calls fork()


   ├─> Create child process structure

   ├─> Copy page table (but share physical pages)
   │   │
   │   ├─> For each writable page:
   │   │   ├─> Mark as read-only
   │   │   ├─> Set COW bit (available1)
   │   │   └─> Increment reference count
   │   │
   │   └─> Read-only pages: just share (no COW)

   └─> Return to user space
       (both processes now share memory)

2. Child writes to shared page


   ├─> Page fault (write to read-only page)

   ├─> pageFaultHandler detects COW bit set

   ├─> CowHandler.handleFault()
   │   │
   │   ├─> Check refcount:
   │   │   │
   │   │   ├─> refcount == 1:
   │   │   │   └─> Just mark writable (fast path)
   │   │   │
   │   │   └─> refcount > 1:
   │   │       ├─> Allocate new physical page
   │   │       ├─> Copy 4KB of data
   │   │       ├─> Update page table entry
   │   │       ├─> Decrement old page refcount
   │   │       └─> Increment new page refcount
   │   │
   │   └─> Clear COW bit, set writable

   ├─> Invalidate TLB (invlpg or shootdown on SMP)

   └─> Resume execution
       (write completes normally)

Reference Counting

pub const PageRefCount = struct {
    const COW_BIT: u3 = 0x1;
    // Global array: 4096 entries for 16MB of tracked memory
    var ref_counts: [4096]atomic.AtomicU32;

    pub fn inc(phys_addr: u64) void {
        _ = ref_counts[index].fetchAdd(1, .Monotonic);
    }

    pub fn dec(phys_addr: u64) u32 {
        return ref_counts[index].fetchSub(1, .Monotonic) - 1;
    }

    pub fn get(phys_addr: u64) u32 {
        return ref_counts[index].load(.Monotonic);
    }
};

TLB Shootdown

Location: apic.zig:TlbShootdownManager

On SMP systems, modifying page tables requires invalidating TLB entries on all CPUs:

CPU 0 unmaps page X:

├─> flushLocal(X)  // Invalidate on local CPU

├─> Create TlbShootdownRequest
│   ├─> address = X
│   ├─> cpu_mask = CPUs that need flush
│   ├─> generation = unique ID
│   └─> completed = atomic counter

├─> Send IPI (vector 0xFD) to each CPU in mask

├─> Wait for completion
│   │
│   └─> Spin until completed == num_cpus

└─> Done

CPU 1 receives IPI 0xFD:

├─> handleShootdownIpi()
│   ├─> Retrieve TlbShootdownRequest
│   ├─> invlpg(address)  // Invalidate TLB entry
│   ├─> Increment completed counter
│   └─> sendEoi()  // Acknowledge interrupt

└─> Resume normal execution

Process Management

Process Structure

Location: process.zig:Process

pub const Process = struct {
    // Identity
    pid: u32,
    ppid: u32,
    state: ProcessState,  // Ready, Running, Blocked, Terminated

    // Memory
    page_table: _PageTable,
    vma_list: ArrayList(VMA),  // Virtual Memory Areas
    heap_start: usize,
    heap_end: usize,
    stack_top: usize,

    // File Descriptors
    fd_table: [MAX_FDS]?_FileDescriptor,  // 0=stdin, 1=stdout, 2=stderr
    cwd: []const u8,  // Current working directory

    // Scheduling
    priority: u8,       // 0-255, higher = more priority
    time_slice: u64,    // Nanoseconds
    cpu_affinity: u64,  // Bit mask of allowed CPUs
    cpu: u8,            // Currently assigned CPU

    // Context (saved registers)
    context: Context,

    // Relations
    parent: ?_Process,
    children: ArrayList(_Process),

    // Synchronization
    wait_queue: ?*WaitQueue,
};

Process States

    ┌────────┐
    │  New   │
    └────┬───┘
         │ schedule()

    ┌────────┐
    │ Ready  │←──────────────────┐
    └────┬───┘                   │
         │                       │ wakeup()
         │ dispatch()            │
         ↓                       │
    ┌─────────┐              ┌──┴─────┐
    │ Running │─────────────→│ Blocked│
    └────┬────┘  block()     └────────┘
         │       (I/O wait,
         │        sleep, etc.)
         │ exit()

    ┌──────────┐
    │Terminated│ (becomes zombie)
    └──────────┘
         │ parent wait()

    (deallocated)

Scheduler

Location: scheduler.zig

Multi-Level Feedback Queue

Priority 255 (Highest):  [P1] → [P2] → NULL
Priority 254:            [P3] → NULL
...
Priority 128 (Default):  [P4] → [P5] → [P6] → NULL
...
Priority 1:              [P7] → NULL
Priority 0 (Lowest):     [P8] → [P9] → NULL

Algorithm:

  1. Select highest priority non-empty queue
  2. Dequeue first process (FIFO within priority)
  3. Run for time quantum (10ms default)
  4. On preemption: enqueue at back of same priority
  5. Adjust priority dynamically:
    • I/O-bound tasks: boost priority
    • CPU-bound tasks: lower priority

SMP Scheduling

Per-CPU Run Queues:

CPU 0: ┌─────────────────┐
       │ Run Queue 0     │
       │ [P1]→[P2]→[P3] │
       └─────────────────┘

CPU 1: ┌─────────────────┐
       │ Run Queue 1     │
       │ [P4]→[P5]      │
       └─────────────────┘

Load Balancer (periodic):
├─> Calculate load per CPU
├─> If imbalance > threshold:
│   ├─> Select tasks to migrate
│   └─> Move to underloaded CPU
└─> Respect CPU affinity masks

File Systems

Virtual File System (VFS)

Location: fs/src/vfs.zig

Mount Table

Mount Point          Filesystem    Device
/                    ext2          /dev/sda1
/boot                FAT32         /dev/sda2
/home                ext2          /dev/sda3

Inode Cache

pub const InodeCache = struct {
    const CACHE_SIZE = 1024;
    entries: HashMap(u64, _Inode),  // ino → inode
    lru_list: LinkedList(_Inode),
    lock: sync.Mutex,

    pub fn get(ino: u64) ?*Inode {
        // Check cache, load from disk if miss
    }

    pub fn evict() void {
        // Evict LRU inode if refcount == 0
    }
};

ext2 Filesystem

Location: fs/src/ext2.zig

On-Disk Layout

┌─────────────────────────────────────────────────────────┐
│ Block 0 (1024 bytes): Boot Block                       │
├─────────────────────────────────────────────────────────┤
│ Block 1: Superblock                                     │
│   - Total inodes/blocks                                 │
│   - Block size                                          │
│   - Blocks per group                                    │
│   - Magic number (0xEF53)                               │
├─────────────────────────────────────────────────────────┤
│ Block 2+: Block Group Descriptor Table                  │
│   - Block bitmap location                               │
│   - Inode bitmap location                               │
│   - Inode table location                                │
│   - Free blocks/inodes count                            │
├─────────────────────────────────────────────────────────┤
│ Block Group 0:                                          │
│   ├─ Block Bitmap (1 block)                             │
│   ├─ Inode Bitmap (1 block)                             │
│   ├─ Inode Table (variable)                             │
│   └─ Data Blocks                                        │
├─────────────────────────────────────────────────────────┤
│ Block Group 1:                                          │
│   ...                                                   │
└─────────────────────────────────────────────────────────┘

Inode Block Pointers

Inode (128 bytes):
├─ i_mode (file type + permissions)
├─ i_uid, i_gid
├─ i_size
├─ i_atime, i_mtime, i_ctime
├─ i_blocks (512-byte blocks)
├─ i_block[0..11]:  Direct blocks      → 12 × 4KB = 48KB
├─ i_block[12]:     Single indirect    → 1K blocks = 4MB
├─ i_block[13]:     Double indirect    → 1M blocks = 4GB
└─ i_block[14]:     Triple indirect    → 1G blocks = 4TB

Max file size: ~4TB (on 32-bit systems with 4KB blocks)

FAT32 Filesystem

Location: fs/src/fat32.zig

Boot Sector

Offset  Size  Field
0x00    3     Jump instruction
0x03    8     OEM name
0x0B    2     Bytes per sector
0x0D    1     Sectors per cluster
0x0E    2     Reserved sectors
0x10    1     Number of FATs
0x20    4     Total sectors (32-bit)
0x24    4     FAT size (sectors)
0x2C    4     Root cluster
0x1FE   2     Boot signature (0xAA55)

FAT Entry Values

Entry Value         Meaning
0x00000000         Free cluster
0x00000002-        Used cluster (next in chain)
0x0FFFFFEF
0x0FFFFFF7         Bad cluster
0x0FFFFFF8-        End of cluster chain
0x0FFFFFFF

Directory Entry (32 bytes)

Offset  Size  Field
0x00    11    Short name (8.3 format)
0x0B    1     Attributes (R/W/H/S/D/A)
0x14    2     First cluster (high)
0x1A    2     First cluster (low)
0x1C    4     File size

Network Stack

Layer Architecture

┌────────────────────────────────────┐
│ Application Layer                  │
│ (Socket API)                       │
│ socket(), bind(), connect(),       │
│ send(), recv(), etc.               │
└────────┬───────────────────────────┘

┌────────┴───────────────────────────┐
│ Transport Layer                    │
│ ┌────────────┐  ┌────────────┐    │
│ │    TCP     │  │    UDP     │    │
│ │ Connection │  │ Datagram   │    │
│ │  Oriented  │  │  Service   │    │
│ └────────────┘  └────────────┘    │
└────────┬───────────────────────────┘

┌────────┴───────────────────────────┐
│ Network Layer                      │
│ ┌────────────┐  ┌────────────┐    │
│ │    IPv4    │  │   ICMP     │    │
│ │  Routing,  │  │ Diagnostics│    │
│ │Fragmenting │  │            │    │
│ └────────────┘  └────────────┘    │
└────────┬───────────────────────────┘

┌────────┴───────────────────────────┐
│ Link Layer                         │
│ ┌────────────┐  ┌────────────┐    │
│ │    ARP     │  │  Ethernet  │    │
│ │  Address   │  │   Frames   │    │
│ │ Resolution │  │            │    │
│ └────────────┘  └────────────┘    │
└────────┬───────────────────────────┘

┌────────┴───────────────────────────┐
│ Physical Layer                     │
│ (e1000 Driver)                     │
└────────────────────────────────────┘

TCP Connection State Machine

CLOSED

  │ passive open / listen

LISTEN

  │ SYN received

SYN_RCVD ──────────┐
  │                │
  │ ACK received   │ timeout / RST
  ↓                │
ESTABLISHED ←──────┘

  │ close / FIN sent

FIN_WAIT_1

  │ ACK received

FIN_WAIT_2

  │ FIN received

TIME_WAIT (2MSL = 120s)

  │ timeout

CLOSED

Packet Flow (Receive)


1. Network card receives Ethernet frame



2. e1000 driver copies to ring buffer



3. Raise interrupt (IRQ)



4. Ethernet layer: validate MAC, extract EtherType



5. If EtherType == 0x0806 (ARP):

   ├─> Update ARP cache
   ├─> If ARP request: send ARP reply
   └─> Done

6. If EtherType == 0x0800 (IPv4):



7. IPv4 layer: validate checksum, TTL, destination



8. If protocol == 17 (UDP):

   ├─> Validate UDP checksum
   ├─> Find socket by (dest IP, dest port)
   ├─> Copy to socket receive buffer
   └─> Wake up waiting process

9. If protocol == 6 (TCP):

   ├─> Validate TCP checksum
   ├─> Find connection by (src IP, src port, dest IP, dest port)
   ├─> Process based on state machine
   ├─> Update sequence numbers
   ├─> Copy data to receive buffer
   ├─> Send ACK if needed
   └─> Wake up waiting process

Device Drivers

AHCI Driver (SATA)

Location: drivers/src/ahci.zig

HBA Memory Registers

Offset    Register
0x00      CAP (Capabilities)
0x04      GHC (Global HBA Control)
0x08      IS (Interrupt Status)
0x0C      PI (Ports Implemented)
0x10      VS (Version)
...
0x100+    Port 0 Registers
0x180+    Port 1 Registers
...

Port Registers

Offset    Register
0x00      CLB (Command List Base)
0x08      FB (FIS Base)
0x10      IS (Interrupt Status)
0x14      IE (Interrupt Enable)
0x18      CMD (Command and Status)
0x20      TFD (Task File Data)
0x28      SIG (Signature)
0x2C      SSTS (SATA Status)

Read/Write Flow


1. Build Command FIS (Frame Information Structure)

   ├─ Type: H2D Register FIS
   ├─ Command: READ DMA / WRITE DMA
   ├─ LBA (Logical Block Address)
   └─ Sector count

2. Build PRDT (Physical Region Descriptor Table)

   ├─ DMA buffer physical address
   └─ Byte count

3. Build Command Header

   ├─ CFL (Command FIS Length)
   ├─ PRDTL (PRDT Length)
   └─ Command Table Base Address

4. Write to Port Command Issue register



5. Wait for completion (poll or interrupt)

   ├─ Check Interrupt Status
   ├─ Check Task File Data
   └─ Handle errors if any

6. Copy DMA buffer to user buffer (for reads)

NVMe Driver

Location: drivers/src/nvme.zig

Controller Registers

Offset    Register
0x00      CAP (Capabilities)
0x08      VS (Version)
0x0C      INTMS (Interrupt Mask Set)
0x10      INTMC (Interrupt Mask Clear)
0x14      CC (Controller Configuration)
0x1C      CSTS (Controller Status)
0x24      AQA (Admin Queue Attributes)
0x28      ASQ (Admin Submission Queue Base)
0x30      ACQ (Admin Completion Queue Base)

Queue Pair

Submission Queue (ring buffer):
┌────────────────┬────────────────┬────────────────┐
│ SQ Entry 0     │ SQ Entry 1     │ SQ Entry 2     │ ...
│ (64 bytes)     │ (64 bytes)     │ (64 bytes)     │
└────────────────┴────────────────┴────────────────┘
       ↑ SQ Tail (doorbell register)

Completion Queue (ring buffer):
┌────────────────┬────────────────┬────────────────┐
│ CQ Entry 0     │ CQ Entry 1     │ CQ Entry 2     │ ...
│ (16 bytes)     │ (16 bytes)     │ (16 bytes)     │
└────────────────┴────────────────┴────────────────┘
       ↑ CQ Head (driver updates)

Interrupt Handling

Interrupt Descriptor Table (IDT)

Location: interrupts.zig

Vector Assignments

Vector   Exception/Interrupt          Handler Function
0        Division Error (#DE)         divisionError()
1        Debug (#DB)                  debugException()
3        Breakpoint (#BP)             breakpoint()
6        Invalid Opcode (#UD)         invalidOpcode()
8        Double Fault (#DF)           doubleFault()
13       General Protection (#GP)     generalProtection()
14       Page Fault (#PF)             pageFault()
...
32-47    Hardware IRQs (PIC)          (device-specific)
48+      Software interrupts
0xFD     TLB Shootdown IPI            handleShootdownIpi()

Page Fault Error Code

Bit 0 (P):    0 = Not present, 1 = Protection violation
Bit 1 (W/R):  0 = Read, 1 = Write
Bit 2 (U/S):  0 = Supervisor, 1 = User
Bit 3 (RSVD): 1 = Reserved bit violation
Bit 4 (I/D):  1 = Instruction fetch

Synchronization

Spinlock

pub const Spinlock = struct {
    locked: atomic.AtomicBool = atomic.AtomicBool.init(false),

    pub fn acquire(self: _Spinlock) void {
        while (self.locked.swap(true, .Acquire)) {
            while (self.locked.load(.Monotonic)) {
                asm volatile ("pause");  // x86-64: reduce power
            }
        }
    }

    pub fn release(self: _Spinlock) void {
        self.locked.store(false, .Release);
    }
};

Boot Sequence

x86-64 Boot Flow


1. BIOS/UEFI

   ├─ Power-on self-test (POST)
   ├─ Initialize hardware
   └─ Load bootloader from MBR

2. Bootloader (GRUB/Limine)

   ├─ Load kernel into memory
   ├─ Set up initial page tables
   ├─ Switch to long mode (64-bit)
   └─ Jump to kernel entry (_start)

3. Kernel Initialization

   ├─ Initialize GDT (Global Descriptor Table)
   ├─ Initialize IDT (Interrupt Descriptor Table)
   ├─ Set up TSS (Task State Segment)
   ├─ Initialize memory manager
   │   ├─ Bump allocator (early boot)
   │   ├─ Page tables (4-level)
   │   ├─ Buddy allocator (general heap)
   │   └─ Slab allocator (kernel objects)
   ├─ Initialize APIC/x2APIC
   ├─ Enable interrupts
   ├─ Initialize devices
   │   ├─ PCI enumeration
   │   ├─ AHCI (SATA)
   │   ├─ NVMe
   │   ├─ e1000 (network)
   │   └─ xHCI (USB)
   ├─ Initialize filesystems
   │   ├─ Mount root (ext2)
   │   └─ Mount boot (FAT32)
   ├─ Initialize network stack
   └─ Launch init process

4. Init Process

   ├─ Mount additional filesystems
   ├─ Start system services
   └─ Launch login/shell

Performance Characteristics

Benchmarks

SubsystemOperationPerformance
MemoryBump alloc5 ns
MemorySlab alloc20 ns
MemoryBuddy alloc150 ns
MemoryCOW fork500 μs (10MB)
PagingTLB shootdown2 μs (4 CPUs)
SchedulerContext switch1 μs
File System (ext2)4KB read50 μs
File System (ext2)4KB write80 μs
Network (TCP)Throughput800 Mbps
Network (UDP)Throughput900 Mbps
NetworkLatency100 μs

References

  • Intel® 64 and IA-32 Architectures Software Developer's Manual
  • ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture profile
  • The ext2 Filesystem Specification
  • Microsoft FAT32 Filesystem Specification
  • TCP/IP Illustrated, Volume 1: The Protocols
  • Serial ATA AHCI Specification, Revision 1.3.1
  • NVM Express Base Specification, Revision 1.4
  • eXtensible Host Controller Interface for Universal Serial Bus (xHCI), Revision 1.2
  • Intel® 82540EP/EM Gigabit Ethernet Controller Datasheet

Released under the MIT License.