Chapter 38 Key Takeaways: Capstone — A Minimal OS Kernel

  1. MinOS is a real, bootable OS — not a simulation or toy. It runs on QEMU with real emulated hardware, handles real interrupts, manages real memory pages, and runs real processes. Every instruction is understood because you wrote it.

  2. The boot sequence is a chain of handoffs: BIOS loads the MBR bootloader at 0x7C00 in 16-bit real mode → bootloader enables A20, loads kernel from disk, sets up GDT, switches to protected mode, enables paging, jumps to long mode → kernel entry loads 64-bit GDT, sets up stack, zeros BSS, calls kernel_main → kernel_main initializes each component in dependency order.

  3. Initialization order matters: VGA before IDT (so you can print error messages); GDT before IDT (IDT entries reference the GDT selector); IDT before enabling interrupts (sti); memory manager before any allocation; TSS before user-mode code. Getting the order wrong produces failures that are difficult to debug.

  4. The GDT in 64-bit mode is mostly ceremonial, but not entirely: in long mode, code and data segment base/limit are ignored. However, the DPL (privilege level), the L bit (64-bit mode flag), the P bit (present), and especially the TSS descriptor remain fully active.

  5. The TSS is essential for privilege transitions: the TSS holds RSP0 — the kernel stack pointer to use when an interrupt or system call occurs in ring 3. Without a valid TSS, a hardware interrupt in user mode has nowhere to switch the stack and will triple-fault.

  6. The IDT gate type determines interrupt behavior: interrupt gates (type 0x8E) clear the IF flag on entry (no nested interrupts unless you re-enable them). Trap gates do not. For most MinOS IRQ handlers, interrupt gates are correct.

  7. The PIT's base frequency is 1,193,182 Hz: to get 100Hz interrupts, load divisor 1193182 / 100 = 11932 into the PIT channel 0. Use command byte 0x36 (channel 0, access lobyte/hibyte, mode 3 square wave).

  8. Preemptive scheduling happens through the timer interrupt: each timer tick, scheduler_tick() decrements a counter. When it reaches zero, schedule() switches to the next READY process. The context switch is completed by the interrupt handler's register save/restore combined with changing which process's saved RSP is used on iretq.

  9. Context switch requires saving and restoring all general-purpose registers: RAX, RBX, RCX, RDX, RSI, RDI, RBP, R8-R15, plus the IRET frame (RIP, CS, RFLAGS, RSP, SS saved by hardware). The easiest implementation saves all this via the interrupt handler wrapper.

  10. VGA text mode at 0xB8000 is the most convenient debug output: it requires no hardware initialization beyond mapping the physical address. Each character is 2 bytes: ASCII + attribute. Writing to this region is immediate and visible.

  11. The QEMU -s -S flags attach a GDB server: -s opens GDB stub on port 1234; -S suspends until GDB connects. This makes the MinOS kernel debuggable with full GDB capabilities including breakpoints, single-stepping, and memory inspection.

  12. The physical memory bitmap allocator uses 1 bit per 4KB page: for 64MB of RAM, that is 64MB / 4KB / 8 = 2KB of bitmap. All pages within the kernel image (from address 0 to KERNEL_END) must be marked "used" before the allocator is ready.

  13. ARM64 MinOS differs primarily in hardware-interface code: UEFI boot (instead of BIOS MBR), system registers (instead of I/O ports), GIC interrupt controller (instead of PIC), TTBR0/TTBR1 (instead of CR3), SVC/ERET (instead of SYSCALL/SYSRET). The C kernel logic — scheduler, allocator, shell — ports unchanged.

  14. The three capstone tracks scale in complexity: Track A (bootloader + VGA + shell, ~1200 lines) proves you understand the boot process and basic I/O. Track B (+ scheduler, ~1700 lines) proves you understand interrupts and concurrency. Track C (+ virtual memory + system calls + filesystem, ~2700 lines) proves you understand the full OS primitive set.

  15. Completing MinOS is proof by construction: you cannot boot a kernel that contains misconceptions about the hardware. If the GDT is wrong, the mode switch faults. If the IDT is wrong, exceptions triple-fault. If the stack is wrong, every call fails. MinOS boots because every component is correct — and you wrote every component.