Chapter 38 Exercises: Capstone — A Minimal OS Kernel

Track A Exercises (Core MinOS)

Exercise 38.1 — Boot sequence tracing Trace the execution path from power-on to the MinOS shell prompt. For each stage, identify: a) The CPU mode (real mode / protected mode / long mode) b) What code is executing (BIOS / bootloader / kernel) c) The approximate address range being executed from d) What the code does to prepare the next stage

Exercise 38.2 ⭐ — GDT construction Write the 8-byte GDT descriptor for each entry: a) 64-bit kernel code segment (DPL=0, present, executable, readable) b) 64-bit kernel data segment (DPL=0, present, writable) c) 64-bit user code segment (DPL=3, present, executable, readable) d) 64-bit user data segment (DPL=3, present, writable)

For each, explain the meaning of each significant bit.

Exercise 38.3 — A20 line a) Why does the A20 address line need to be enabled? b) What address wraps without A20? c) Describe the three methods for enabling A20 (BIOS INT, keyboard controller, fast A20 via port 0x92) d) Which method does the MinOS bootloader use, and why is it the fastest?

Exercise 38.4 ⭐ — IDT entry layout A 64-bit IDT gate descriptor is 16 bytes. For an interrupt gate at handler address 0x0000000000401196 using kernel code selector 0x08:

a) Draw the 16-byte layout showing which bits go where b) Write the two uint64_t values that represent this gate in memory c) What is the type byte value for a 64-bit interrupt gate? d) What does the IST field do, and when would you use it?

Exercise 38.5 — VGA text mode a) The VGA text buffer is at physical address 0xB8000. How many bytes does the 80×25 screen require? b) Write the C expression to compute the offset of character at column x, row y c) What are the attribute byte meanings for: white text on black, green text on blue, blinking red on white? d) What are the CRT controller port numbers for setting the hardware cursor position?


Track B Exercises (Scheduler and Memory)

Exercise 38.6 ⭐ — Context switch mechanics The MinOS context switch saves and restores CPU state through the interrupt stack. Describe:

a) What registers must be saved for a kernel thread context switch? b) What registers does the CPU automatically save on an interrupt? c) Why does the scheduler change the saved RSP value in the process table rather than directly modifying registers? d) Draw the stack state of both process A and process B at the moment of the context switch

Exercise 38.7 — Physical memory bitmap The physical memory bitmap allocator uses 1 bit per 4KB page.

a) How many bytes of bitmap are needed to track 64MB of physical memory? b) Write the C code to mark page frame N as "used" c) Write the C code to find the first free page frame d) Why must kernel memory be marked "used" before the allocator is initialized?

Exercise 38.8 ⭐ — Timer interrupt chain Trace the complete execution path when the PIT fires IRQ0:

a) The CPU detects the interrupt. What state saves happen automatically? b) The IDT lookup finds the handler. What address does it jump to? c) The handler stub saves registers. Why are general-purpose registers not saved automatically? d) timer_handler() calls scheduler_tick(). Under what condition does the scheduler switch processes? e) iretq restores state. What exactly does iretq pop from the stack?

Exercise 38.9 — Round-robin scheduling MinOS uses round-robin scheduling with a 10-tick timeslice (100ms at 100Hz).

a) With 4 processes (A, B, C, D, all READY), write out the first 40 ticks of scheduling (which process runs when?) b) Process C blocks waiting for keyboard input. How does the scheduler handle it? c) Process D finishes and exits. How should the scheduler handle DEAD processes? d) What is "priority starvation" and how could you modify the round-robin scheduler to prevent it?

Exercise 38.10 ⭐ — Page table setup MinOS uses 4-level paging (PML4 → PDPT → PD → PT).

a) For an identity-mapped first 2MB using 2MB pages (huge pages), how many page table structures are needed? b) What are the flags for a present, writable, kernel-accessible 2MB page? c) Why can the bootloader use 2MB pages but the kernel may want 4KB pages for fine-grained control? d) Write the assembly to load CR3 with the PML4 base address


Track C Exercises (Advanced)

Exercise 38.11 — User/kernel separation MinOS Track C adds user mode (ring 3) processes.

a) What prevents a user-mode process from executing cli (disable interrupts)? b) What prevents a user-mode process from reading [0xB8000] (VGA buffer)? c) How does a user-mode process invoke a kernel service? d) What is the SYSCALL/SYSRET mechanism, and what MSRs does it use?

Exercise 38.12 ⭐ — System call implementation Implement the skeleton for a read system call in MinOS Track C:

The user-mode calling convention: syscall number in RAX, args in RDI, RSI, RDX. Syscall 0 = write(fd, buf, count).

Write: a) The NASM assembly entry point that saves registers and calls the C handler b) The C handler function signature and return convention c) How the kernel validates that the user-space buffer pointer is valid before reading it d) How the return value gets back to user space

Exercise 38.13 — FAT12 filesystem MinOS Track C can optionally include a FAT12 filesystem reader.

a) What is the structure of a FAT12 boot sector? b) How does FAT12 chain clusters to represent files? c) Why is FAT12 appropriate for MinOS (hint: floppy disk, 512-byte sectors)? d) Write pseudocode for read_file(filename, buffer, max_size) using FAT12

Exercise 38.14 ⭐ — ELF loading MinOS Track C can load simple ELF executables. Describe:

a) The structure of an ELF64 file header (magic, class, type, entry, program header offset) b) How program headers describe memory segments to load c) The steps to load an ELF binary: open, read headers, map segments, transfer control d) What additional memory management is required to run ELF programs at user virtual addresses?


Extension Exercises

Exercise 38.15 — ARM64 port conceptual Describe the major differences required to port MinOS to ARM64 running on QEMU qemu-system-aarch64:

a) ARM64 boot: UEFI vs. BIOS. What does UEFI provide that the BIOS does not? b) ARM64 exception levels vs. x86-64 privilege rings: how are they equivalent? c) ARM64 MMU: how do ARM64 page tables differ from x86-64 4-level paging? d) ARM64 interrupts: GIC (Generic Interrupt Controller) vs. x86-64 PIC/APIC

Exercise 38.16 ⭐ — Debug MinOS with GDB Using the make debug target (QEMU with GDB stub on port 1234):

a) Write the GDB commands to connect to QEMU and break at kernel_main b) Write a GDB command to display the first 5 IDT entries in a readable format c) Write a GDB command to show the current process table contents d) How would you set a watchpoint on a kernel variable to detect when a value changes?

Exercise 38.17 — MinOS extension: adding a memtest command Design and implement a memtest shell command:

a) The command should iterate through all free pages b) Write a test pattern (e.g., address XOR 0xDEADBEEF) to each page c) Read it back and verify d) Report: total pages tested, any failures, and total memory tested

Implement this as a C function and integrate it with the shell command dispatcher.

Exercise 38.18 ⭐ — Interrupt latency analysis Using the serial port as a timestamp output (serial writes are fast and non-blocking):

a) Log a timestamp (timer_get_ticks()) at the start of the keyboard IRQ handler b) Compare the timestamp between when the key was pressed (you know the time from the PIT) and when the handler ran c) What factors contribute to interrupt latency in MinOS? d) How would adding more processes affect keyboard interrupt latency?

Exercise 38.19 — SMP extension (research) The MinOS scheduler is single-processor. Describe what would be required to support two CPUs (SMP):

a) How would QEMU launch with two CPUs? (-smp 2) b) How does the Application Processor (AP) start up in x86-64 SMP? (hint: SIPI) c) What kernel data structures need per-CPU copies? d) Why do alloc_page() and free_page() need spinlock protection in SMP?

Exercise 38.20 ⭐ — Complete MinOS reflection After completing your chosen track of MinOS:

a) What was the most difficult debugging problem you encountered, and how did you solve it? b) Which component was most educational to implement, and why? c) What is one feature you would add next to make MinOS more useful? d) How does having written a bootloader change your understanding of what happens when a production OS (Linux, Windows) boots?