Master the fundamental concepts of build a mini kernel through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksThe IDT maps interrupt vectors to handler addresses with privilege and gate type. CPU pushes error code and vector on fault; your stub saves registers and calls C handlers.
Per vector:
For example, vector 0x0E page fault pushes faulting address on stack for your handler to inspect CR2.
The IDT you're building here is what every x86 kernel uses to route hardware IRQs, CPU exceptions, and syscalls to handler code, and vector 128 (0x80) is the literal interrupt number Linux used for system calls for two decades before syscall/sysret replaced it. Forgetting to end a handler with iret instead of ret is a classic bug that corrupts the interrupted task's entire register and flag state.
Before you call the implementation done, walk failure modes on purpose. Test empty structures, single-element edge cases, maximum concurrency, and errno paths that must not crash the program. OS code usually fails in production when happy-path tests pass but invariants break under contention or memory pressure.
Keep structures small and name fields after kernel counterparts when possible. That lets you read man pages and kernel source side by side while you work. Print observable events during development; remove noisy logs once tests pass reliably.
You will load IDT with assembly stubs that dispatch to C. This exercise requires differentiating IRQ handlers from CPU exception handlers in your logging.
Build the kernel's Interrupt Descriptor Table and simulate how the CPU delivers interrupts through it. Each IDT entry is an 8-byte gate holding a handler address, a code-segment selector and a type byte. The CPU checks the gate on every delivery. A missing gate raises #NP. A software int into a gate whose DPL is below the caller's privilege raises #GP, which is how int 0x80 is opened to user space while int 0x20 isn't. A fault that occurs while delivering a fault becomes a double fault, and if that fails too, a triple fault resets the machine.
bits 0-15: handler offset low · 16-31: selector · 32-39: zero · 40-47: type_attr = P(7) DPL(6–5) 0 type(3–0) with type 0xE (interrupt gate) or 0xF (trap gate) · 48-63: offset high.
| Command | Meaning |
|---|---|
| `gate VEC OFFSET SEL interrupt | trap DPL` |
lidt BASE | load the IDT register (limit is always 0x7FF: 256 gates) |
int VEC [cpl N] | software interrupt from privilege level N (default 0) |
exception VEC [cpl N] | CPU exception 0-31 while running at CPL N |
irq N [cpl C] | hardware IRQ N (0-15), vector 32 + N |
stats | how many times each vector's handler ran |
vector V: no IDT loaded -> triple fault, CPU resets.#NP with error code V×8+2. A software int with gate DPL < CPL → #GP with error code V×8+2. (Exceptions and IRQs skip the DPL check.)fault while delivering a fault -> #DF double fault. Then run vector 8's handler if present, or print vector 8 not present -> triple fault, CPU resets.vector V: handler 0xSEL:0xOFFSET (interrupt gate, IF cleared) or (trap gate, IF unchanged). Append , ring N -> 0 stack switch when CPL > 0 and the selector's RPL is 0. For exceptions 8, 10-14 and 17, and for faults raised by the CPU itself, append , error code pushed.gate V (NAME): 0xVALUE (offset 0x…, selector 0x…, type_attr 0x…) (the name only for exceptions 0-17), lidt: base 0x… limit 0x7ff (256 gates), then per event a header line (int 0x80 from ring 3:, exception 14 (#PF page fault) in ring 3:, irq 1 (vector 33) in ring 0:) followed by the delivery lines. stats: delivered: V=N ... or delivered: none.
Exception names 0-17: #DE divide error, #DB debug, NMI, #BP breakpoint, #OF overflow, #BR bound, #UD invalid opcode, #NM no FPU, #DF double fault, coprocessor overrun, #TS invalid TSS, #NP segment not present, #SS stack fault, #GP general protection, #PF page fault, reserved, #MF x87 error, #AC alignment check; others are reserved.
Input:
cLoading…
Output:
cLoading…
Hidden tests cover a missing gate with a #NP handler, a missing gate without one (double fault handled by vector 8), a triple fault, trap versus interrupt gates, and interrupts before lidt.