Skip to content

Architecture

Frank edited this page Apr 17, 2026 · 3 revisions

Architecture

cupid-os is a monolithic, single-address-space, ring-0 operating system for 32-bit x86. Every component - kernel, drivers, shell, applications - runs in the same flat memory space with full hardware access.


Boot Sequence

BIOS loads boot.asm at 0x7C00 (real mode, 16-bit)
    │
    ├── Set up stack at 0x7C00
    ├── Load kernel from disk (sectors 1+) to 0x10000
    ├── Set 640×480×32bpp via Bochs VBE I/O ports (0x01CE/0x01CF)
    ├── Read VBE LFB address from PCI BAR0 → store at 0x0500
    ├── Set up GDT (flat model: code + data segments)
    ├── Switch to protected mode (CR0 bit 0)
    └── Far jump to kernel entry at 0x10000
            │
            ├── idt_init()          - Interrupt Descriptor Table
            ├── pic_init()          - PIC remapping (IRQ0→32, IRQ8→40)
            ├── irq_init()          - IRQ handler registration
            ├── pmm_init()          - Physical memory manager
            ├── paging_init()       - Identity-mapped 4KB pages (32MB)
            │                         + maps VBE LFB region from 0x0500
            ├── heap_init()         - Kernel heap (2MB) with canaries
            ├── keyboard_init()     - PS/2 keyboard (IRQ1)
            ├── pit_init()          - PIT at 100Hz (IRQ0)
            ├── serial_init()       - COM1 at 115200 baud
            ├── rtc_init()          - CMOS Real-Time Clock
            ├── fat16_init()        - FAT16 filesystem + block cache
            ├── fs_init()           - In-memory filesystem
            ├── vfs_init()          - Virtual File System
            │   ├── Register ramfs, devfs, fat16 filesystem types
            │   ├── Mount ramfs at /
            │   ├── Create /bin, /tmp, /home directories
            │   ├── Mount devfs at /dev (null, zero, random, serial)
            │   ├── Mount fat16 at /home (ATA disk)
            │   └── Pre-populate /LICENSE.txt, /MOTD.txt
            ├── process_init()      - Process table, idle process (PID 1)
            ├── Register desktop as PID 2
            ├── vga_init_vbe()      - Init 640×480 32bpp framebuffer
            ├── mouse_init()        - PS/2 mouse (IRQ12)
            └── desktop_run()       - Main event loop

Memory Layout

0x00000000 ┌──────────────────────────┐
           │ Interrupt Vector Table   │ (not used - we use IDT)
0x00000500 ├──────────────────────────┤
           │ VBE LFB address          │ ← Written by bootloader
0x00001000 ├──────────────────────────┤
           │ Kernel Code + Data       │ ← Loaded by bootloader
           │ (.text, .data, .bss)     │ ← starts at 0x10000
           ├──────────────────────────┤
           │ Boot Stack               │ ← 0x7C00 (real mode)
0x00110000 ├──────────────────────────┤
           │ Stack Guard Region       │ ← 512KB kernel stack
0x00190000 ├──────────────────────────┤
           │ Kernel Heap              │ ← kmalloc/kfree, 2MB
           │ (canary-protected)       │ ← includes VBE back buffer
           ├──────────────────────────┤
           │ Process Stacks           │ ← kmalloc'd, 4KB+ each
           │ (canary at bottom)       │
0x000A0000 ├──────────────────────────┤
           │ VGA Text Memory          │ ← Text mode (legacy)
0x00100000 ├──────────────────────────┤
           │ Extended Memory          │ ← PMM bitmap manages this
           │ (pages allocated here)   │
0x02000000 ├──────────────────────────┤
           │ End of managed memory    │ (32MB total)
           └──────────────────────────┘
           ·
           · (unmapped gap)
           ·
0xFD000000 ┌──────────────────────────┐
           │ VBE Linear Framebuffer   │ ← 640×480×4 = 1.2MB
           │ (identity-mapped by      │   PCI BAR0, QEMU default
           │  paging_init)            │
0xFD140000 └──────────────────────────┘

Component Architecture

Kernel Core

Component Files Purpose
Kernel entry kernel.c/h VGA, init sequence, main print functions
IDT idt.c/h Interrupt descriptor table setup
ISR/IRQ isr.asm, irq.c/h Interrupt/exception dispatching
PIC pic.c/h Programmable interrupt controller
Memory memory.c/h, paging.c PMM, heap, paging, canaries, leak detection
VFS vfs.c/h Virtual filesystem, mount table, path resolution
Panic panic.c/h, assert.h Crash handler, assertions
Strings string.c/h strlen, strcmp, memcpy, memset
Math math.c/h 64-bit division, itoa, hex printing

Drivers

Driver Files IRQ Purpose
Keyboard keyboard.c/h IRQ1 PS/2 input with modifiers
Mouse mouse.c/h IRQ12 PS/2 mouse with cursor
Timer timer.c/h, pit.c/h IRQ0 100Hz PIT, uptime, sleep
VGA vga.c/h - VBE 640×480 32bpp, double buffering
ATA ata.c/h - PIO disk read/write
Serial serial.c/h - COM1 logging
Speaker speaker.c/h - PC speaker tones
RTC rtc.c/h - CMOS real-time clock

Subsystems

Subsystem Files Purpose
Shell shell.c/h 38-command interactive shell with CWD support
CupidScript cupidscript*.c/h Bash-like scripting language
Ed Editor ed.c/h Unix ed(1) line editor
VFS vfs.c/h Virtual File System with mount table and path resolution
RamFS ramfs.c/h In-memory filesystem (root, /bin, /tmp)
DevFS devfs.c/h Device filesystem (/dev/null, zero, random, serial)
FAT16 VFS fat16_vfs.c/h FAT16 VFS wrapper for /home
FAT16 fat16.c/h, blockdev.c/h, blockcache.c/h FAT16 driver with block cache
In-Memory FS fs.c/h Legacy read-only system file table
Exec exec.c/h CUPD program loader
Process Mgr process.c/h, context_switch.asm Scheduler, context switching
GUI gui.c/h, desktop.c/h, graphics.c/h, font_8x8.c/h Window manager, desktop
Terminal terminal_app.c/h GUI terminal application
Notepad notepad.c/h Text editor application (VFS file dialog)
Clipboard clipboard.c/h System clipboard
Calendar calendar.c/h Calendar math, time/date formatting, popup state

Interrupt Map

IRQ Vector Handler Purpose
IRQ0 32 timer_callback PIT timer tick (100Hz), scheduler flag
IRQ1 33 keyboard_handler PS/2 keyboard input
IRQ12 44 mouse_handler PS/2 mouse input
- 0 division_error Divide by zero exception
- 6 invalid_opcode Invalid opcode exception
- 13 general_protection GPF
- 14 page_fault Page fault (with CR2 reporting)

Execution Model

cupid-os uses deferred preemptive multitasking:

  1. PIT IRQ0 fires every 10ms → sets need_reschedule flag
  2. Flag is checked at safe voluntary points only:
    • Desktop main loop (before HLT)
    • process_yield() calls
    • Idle process loop
  3. Context switch happens via pure assembly context_switch():
    • Save EBP, EDI, ESI, EBX, EFLAGS on current stack
    • Store ESP into old process PCB
    • Load new process ESP and jump to new EIP

This avoids the complexity and stack corruption risks of switching inside interrupt handlers.


CupidScript Execution Pipeline

.cup file on disk
      │
      ▼
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│    Lexer     │───▶│    Parser    │───▶│  Interpreter │
│ (tokenize)   │     │ (build AST)  │     │ (execute AST)│
└──────────────┘     └──────────────┘     └──────┬───────┘
                                                  │
                           ┌──────────────────────┤
                           ▼                      ▼
                    ┌──────────────┐     ┌──────────────┐
                    │   Runtime    │     │    Shell     │
                    │ (variables,  │     │ (execute_    │
                    │  functions)  │     │  command())  │
                    └──────────────┘     └──────────────┘

See Also

Clone this wiki locally