Skip to content

Latest commit

 

History

History
224 lines (168 loc) · 9.27 KB

File metadata and controls

224 lines (168 loc) · 9.27 KB

Kernel Development Roadmap — notlinuxkernel

Current State

  • 32-bit x86, Multiboot v1, boots via GRUB into protected mode
  • VGA text terminal (80x25, 16 colors, scrolling)
  • Serial COM1 output (38400 baud)
  • Port I/O helpers (inb/outb)
  • Dual-mode test framework (host + QEMU)
  • No GDT, IDT, paging, heap, or drivers of its own

Roadmap (dependency-ordered)

Phase 1: CPU Foundations

These establish control over the CPU that GRUB currently manages for you.

Task 1: String & Memory Utilities (libc subset)

  • Implement memset, memcpy, memmove, memcmp, strlen, strcmp, strncmp, itoa/number formatting
  • Create kernel/string.h + kernel/string.c
  • Why first: nearly every subsequent task needs these
  • Test: unit tests for each function in host + QEMU modes

Task 2: Formatted Print (kprintf)

  • Implement a kernel printf supporting %d, %u, %x, %s, %c, %p, %%
  • Output to both VGA terminal and serial
  • Depends on: Task 1 (string/number formatting helpers)
  • Why: debugging everything that follows requires formatted output
  • Test: print various format strings, verify on serial and VGA

Task 3: Global Descriptor Table (GDT)

  • Set up your own GDT with: null descriptor, kernel code (ring 0), kernel data (ring 0), user code (ring 3), user data (ring 3)
  • Write gdt_flush in assembly to load GDTR and reload segment registers
  • Create kernel/gdt.h + kernel/gdt.c
  • Depends on: Task 2 (kprintf for debug output)
  • Why: you currently rely on GRUB's GDT which you don't control; needed before IDT
  • Test: verify boot still works after loading custom GDT; print segment register values

Task 4: Interrupt Descriptor Table (IDT) + ISR Stubs

  • Define 256-entry IDT
  • Write assembly ISR stubs for exceptions 0–31 (CPU exceptions) and IRQs 32–47
  • Common handler in C that dispatches based on interrupt number
  • Create kernel/idt.h + kernel/idt.c + kernel/isr.asm (or inline asm)
  • Depends on: Task 3 (GDT must be valid before loading IDT)
  • Why: required for hardware interrupts, exception handling, everything beyond polling
  • Test: trigger division by zero, verify handler fires and prints message

Task 5: Programmable Interrupt Controller (PIC) Remapping

  • Remap PIC so IRQ 0–15 map to interrupts 32–47 (avoiding CPU exception overlap)
  • Implement pic_init(), pic_send_eoi(), irq_set_mask(), irq_clear_mask()
  • Create kernel/pic.h + kernel/pic.c
  • Depends on: Task 4 (IDT must exist to register IRQ handlers)
  • Why: hardware interrupts won't work correctly without PIC remapping
  • Test: verify no spurious interrupts; PIC responds to EOI

Task 6: Programmable Interval Timer (PIT)

  • Configure PIT channel 0 for periodic ticks (e.g., 100 Hz or 1000 Hz)
  • Register IRQ 0 handler, maintain a global tick counter
  • Implement pit_init(), timer_get_ticks(), sleep_ms() (busy-wait on tick counter)
  • Create kernel/timer.h + kernel/timer.c
  • Depends on: Task 5 (PIC must be remapped so IRQ0 fires correctly)
  • Why: needed for scheduling, timeouts, delays
  • Test: print tick count; verify sleep_ms approximation

Task 7: Keyboard Driver (PS/2)

  • Register IRQ 1 handler
  • Implement scancode-to-ASCII translation (US QWERTY, scan code set 1)
  • Handle key press/release, shift state, caps lock
  • Ring buffer for key input; keyboard_getchar() blocking read
  • Create kernel/keyboard.h + kernel/keyboard.c
  • Depends on: Task 5 (PIC for IRQ1), Task 4 (IDT)
  • Why: first interactive I/O — makes kernel usable
  • Test: type characters, verify they echo on screen

Phase 2: Memory Management

With CPU control established, take ownership of memory.

Task 8: Physical Memory Manager (PMM)

  • Parse Multiboot memory map (passed in EBX at boot) to find usable RAM regions
  • Bitmap-based frame allocator (4 KiB frames)
  • pmm_init(), pmm_alloc_frame(), pmm_free_frame()
  • Create kernel/pmm.h + kernel/pmm.c
  • Depends on: Task 1 (memset), Task 2 (kprintf for debug), multiboot info parsing
  • Why: paging and heap both need physical frame allocation
  • Test: allocate and free frames; verify bitmap state; count available memory

Task 9: Paging (Virtual Memory)

  • Set up a page directory and page tables
  • Identity-map the first 4 MiB (or however much kernel uses)
  • Map VGA buffer at 0xB8000
  • Enable paging via CR0/CR3
  • Implement paging_init(), map_page(), unmap_page()
  • Create kernel/paging.h + kernel/paging.c
  • Depends on: Task 8 (PMM to allocate page table frames), Task 4 (IDT for page fault handler)
  • Why: memory protection, process isolation, higher-half kernel later
  • Test: access mapped memory; trigger page fault on unmapped address; verify handler fires

Task 10: Kernel Heap (kmalloc/kfree)

  • Simple heap allocator (e.g., first-fit linked list, or boundary tag)
  • kmalloc(size), kfree(ptr), optionally kmalloc_aligned()
  • Heap grows by requesting pages from PMM + mapping them
  • Create kernel/heap.h + kernel/heap.c
  • Depends on: Task 9 (paging, to map new heap pages), Task 8 (PMM)
  • Why: dynamic allocation needed for data structures, drivers, processes
  • Test: allocate various sizes; free and reallocate; stress test for fragmentation

Phase 3: Storage & Filesystem

With memory management, you can build data structures for storage.

Task 11: ATA/IDE Disk Driver (PIO Mode)

  • Detect ATA drives on primary/secondary bus
  • Implement PIO read/write of 512-byte sectors
  • ata_init(), ata_read_sectors(), ata_write_sectors()
  • Create kernel/ata.h + kernel/ata.c
  • Depends on: Task 1 (memcpy), Task 2 (kprintf), Task 5 (PIC for IRQ14/15 optionally)
  • Why: need disk access before any filesystem
  • Test: read sector 0 (MBR) from a test disk image; verify magic bytes 0x55AA

Task 12: Simple Filesystem (FAT16 or custom read-only fs)

  • Parse filesystem structures from disk
  • Implement directory listing, file open, file read
  • Start read-only; write support later
  • Create kernel/fs.h + kernel/fs.c
  • Depends on: Task 11 (ATA driver), Task 10 (heap for buffers and directory entries)
  • Why: loading programs, config files, enabling initrd
  • Test: create a FAT16 disk image with test files; read and print file contents

Phase 4: Userspace & Multitasking

Task 13: Task State Segment (TSS)

  • Add TSS entry to GDT
  • Initialize TSS with kernel stack pointer (for ring 3 → ring 0 transitions)
  • tss_init(), tss_set_kernel_stack()
  • Create kernel/tss.h + kernel/tss.c
  • Depends on: Task 3 (GDT), Task 9 (paging, for per-task stacks)
  • Why: required for user mode and context switching
  • Test: verify TSS loaded with ltr; no fault

Task 14: Context Switching & Kernel Threads

  • Define a task/process struct (registers, stack pointer, page directory, state)
  • Implement switch_to(old, new) in assembly (save/restore registers + ESP)
  • Simple round-robin scheduler: schedule() called from timer IRQ
  • Task creation: task_create(entry_function)
  • Create kernel/task.h + kernel/task.c + kernel/switch.asm
  • Depends on: Task 6 (timer for preemption), Task 10 (heap for task structs), Task 9 (per-task page directories)
  • Why: multitasking is fundamental to a real OS
  • Test: create 2+ kernel threads that print alternating messages

Task 15: User Mode

  • Ring 3 transition: set up user code/data segments, jump to user mode via iret
  • Separate user and kernel page mappings
  • Depends on: Task 13 (TSS), Task 14 (task switching), Task 9 (paging)
  • Why: process isolation, security boundary
  • Test: user mode program runs; accessing kernel memory causes page fault

Task 16: System Calls

  • Use int 0x80 (or sysenter) for user → kernel calls
  • Implement a syscall dispatcher and initial syscalls: sys_write, sys_exit, sys_getpid
  • Create kernel/syscall.h + kernel/syscall.c
  • Depends on: Task 15 (user mode), Task 4 (IDT for int 0x80)
  • Why: user programs need a safe way to request kernel services
  • Test: user program calls sys_write to print to terminal

Phase 5: Shell & User Experience

Task 17: Simple Shell

  • Command-line interface reading keyboard input
  • Built-in commands: help, clear, echo, meminfo, uptime, ls, cat
  • Command parsing (split by spaces)
  • Depends on: Task 7 (keyboard), Task 2 (kprintf), Task 6 (timer for uptime)
  • Why: interactive interface makes the kernel tangible and testable
  • Test: boot kernel, type commands, verify output

Task 18: ELF Binary Loader

  • Parse ELF32 headers from filesystem
  • Load program segments into user address space
  • Set up user stack, jump to entry point
  • Create kernel/elf.h + kernel/elf.c
  • Depends on: Task 12 (filesystem), Task 15 (user mode), Task 9 (paging)
  • Why: run real compiled programs instead of hardcoded functions
  • Test: compile a simple C program as freestanding ELF; load and execute it

Phase 6: Advanced (stretch goals, order flexible)

Task 19: VGA Scrollback Buffer

  • Keep a buffer of previous lines for scroll-up
  • Keyboard shortcuts (Shift+PgUp/PgDn)
  • Depends on: Task 7 (keyboard), Task 10 (heap)

Task 20: Serial Input (bidirectional)

  • Read from serial port, enable serial console
  • Depends on: Task 4 (IDT for IRQ4)

Task 21: ACPI Power Management

  • Parse ACPI tables for shutdown/reboot
  • Depends on: Task 9 (paging for ACPI table mapping), Task 1

Task 22: Networking (virtio-net or NE2000)

  • Very advanced; needs ring buffers, protocol stack
  • Depends on: Task 10 (heap), Task 4 (IDT), Task 5 (PIC)