Architecture & Internals
This document provides a deep dive into the internal architecture of TilekarOS. It covers the boot sequence, memory organization, and the interrupt handling mechanism, supported by detailed diagrams.
1. The Boot Sequence
The transition from a powered-off machine to the executing kernel involves several stages. TilekarOS relies on a Multiboot-compliant bootloader (like GRUB) to handle the initial hardware setup.
Detailed Boot Flowchart
flowchart TD
%% --- Hardware / Bootloader ---
subgraph SystemStart ["System Start"]
direction TB
BIOS["BIOS / UEFI"]:::hardware --> GRUB[GRUB Bootloader]:::hardware
GRUB -- Multiboot Magic --> ProtMode["32-bit Protected Mode"]:::hardware
end
%% --- Low Level Entry ---
subgraph BootASM ["boot.asm _start"]
direction TB
Stack["Setup Stack (esp = stack_top)"]:::asm
Stack --> InitHub{Init Sequence}:::asm
end
SystemStart --> BootASM
%% --- Modules ---
%% TTY
InitHub -- 1 --> TTY["tty.c: init_terminal"]:::c_module
%% GDT
subgraph GDT_Scope ["gdt.c: init_gdt"]
direction LR
G_Ld[Load GDTR]:::c_func --> G_TSS[Install TSS]:::c_func
G_TSS --> G_TR[Load TR]:::c_func
end
InitHub -- 2 --> GDT_Scope
%% IDT
subgraph IDT_Scope ["idt.c: init_idt"]
direction LR
I_PIC["Remap PIC (0x20 / 0x28)"]:::c_func --> I_Fill[Fill Gates]:::c_func
I_Fill --> I_Ld[Load IDTR]:::c_func
end
InitHub -- 3 --> IDT_Scope
%% Kernel Main
subgraph Kernel_Scope ["kernel.c: kernel_main"]
direction TB
AppLogic["Print Banner & Run Tests"]:::kernel --> Halt((Infinite Loop)):::hardware
end
InitHub -- 4 --> Kernel_Scope
%% FORCE LEFT-TO-RIGHT ORDERING
TTY ~~~ G_Ld ~~~ I_PIC ~~~ AppLogic
Steps Explained
- Bootloader Handoff: GRUB ensures the CPU is in Protected Mode (A20 line enabled, Paging disabled). It places the Multiboot Information Structure in memory and puts the "Magic Number" in
EAX. - Stack Setup: Since C functions require a stack,
boot.asmpoints the Stack Pointer (ESP) to the top of a reserved 16KiB block in the.bsssection. - Global Descriptor Table (GDT): We replace the GDT provided by GRUB with our own to ensure we have full control over the memory segments and to set up the TSS (Task State Segment) for future ktask-mode switching. See Global Descriptor Table.
- Interrupt Descriptor Table (IDT): We configure the IDT to handle exceptions (like Divide-by-Zero) and hardware interrupts. The 8259 PIC is remapped to avoid IDT collisions. See Interrupt Descriptor Table.
2. Memory Organization
TilekarOS uses a Flat Memory Model. Paging is currently disabled (Linear Address = Physical Address). See Memory Map (x86).
Memory Layout Diagram
block-beta
columns 1
block:high_mem
space
text["High Memory (Available for Allocation)"]
space
end
block:kernel_space
block:sections
columns 3
stack["Kernel Stack<br>(16 KB)"]
bss[".bss Section<br>(Uninitialized)"]
data[".data Section<br>(Initialized)"]
end
code[".text Section<br>(Kernel Code)"]
end
block:reserved
vga["VGA Video Memory<br>(0xB8000 - 0xBFFFF)"]
bios["BIOS Data Area & EBDA<br>(Reserved)"]
end
GDT Entry Structure
The GDT defines the characteristics of the various memory segments.
packet-beta
0-15: "Limit (0-15)"
16-31: "Base (0-15)"
32-39: "Base (16-23)"
40-47: "Access Byte"
48-51: "Limit (16-19)"
52-55: "Flags"
56-63: "Base (24-31)"
- Base: The starting linear address of the segment (0x0 for Flat Model).
- Limit: The size of the segment.
- Access Byte: Defines presence, privilege level (Ring 0 vs 3), and type (Code vs Data).
- Flags: Granularity (4KiB blocks vs 1 Byte) and Operand size (32-bit vs 16-bit).
3. Interrupt Handling System
The interrupt system allows the CPU to pause current execution to handle urgent events (Exceptions, Hardware Signals, Syscalls).
Interrupt Dispatch Pipeline
When an interrupt (e.g., IRQ 1 - Keyboard) occurs:
sequenceDiagram
participant HW as Hardware (Keyboard)
participant CPU
participant IDT as IDT (Table)
participant ASM as ASM Wrapper (isr_common)
participant C as C Handler (irq_handler)
HW->>CPU: Signals Interrupt (IRQ 1)
Note over CPU: 1. Push EFLAGS, CS, EIP<br>2. Read IDT Entry 33
CPU->>ASM: Jump to ISR Stub (irq1)
activate ASM
ASM->>ASM: Push Interrupt Number (33)
ASM->>ASM: PushAll (EAX, ECX, EDX...)
ASM->>ASM: Load Kernel Data Segment
ASM->>C: Call irq_handler(registers)
activate C
C->>C: Look up registered handler
C-->>C: Handle Event (Read Scancode)
C->>HW: Send EOI (End of Interrupt)
C->>ASM: Return
deactivate C
ASM->>ASM: Restore Registers (PopAll)
ASM->>CPU: IRET (Interrupt Return)
deactivate ASM
CPU->>HW: Resume Execution
IDT Configuration
The IDT is an array of 256 8-byte entries.
| Vector Range | Usage | Description |
|---|---|---|
| 0 - 31 | CPU Exceptions | Faults, Traps, and Aborts (e.g., Page Fault, GPF). |
| 32 - 47 | Hardware IRQs | Remapped PIC interrupts. IRQ0=32 (Timer), IRQ1=33 (Keyboard). |
| 48 - 127 | Reserved | Available for custom use. |
| 128 (0x80) | Syscall | Typical Linux-style system call entry point. |
| 177 | Syscall | Alternate system call entry point. |
The PIC Remapping Issue
By default, the 8259 PIC maps IRQs 0-7 to Interrupt Vectors 0-7. This conflicts with CPU Exceptions (e.g., INT 0 is Divide-by-Zero). Solution: We reprogram the PIC to offset IRQs to start at vector 32 (0x20).
- Master PIC (IRQs 0-7) \(\rightarrow\) Vectors 32-39
- Slave PIC (IRQs 8-15) \(\rightarrow\) Vectors 40-47
4. Kernel Execution & Testing
The kernel_main function serves as the entry point for the OS after initialization. Currently, it performs the following actions:
- Banner Display: Prints the OS welcome message using
terminal_writestring. - Exception Test: Intentionally triggers a Divide-by-Zero exception (
1/0).- Purpose: To verify that the IDT is correctly loaded and the ISR for Vector 0 is firing.
- Expected Behavior: The OS should catch the exception, print a debug message (if implemented), and halt or panic, rather than triple-faulting or resetting.