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 legacy PIC cascades two chips delivering IRQ 0-15 to CPU vectors starting at 0x20. Kernel masks lines, acknowledges interrupts with EOI, and maps vectors away from CPU exceptions.
ICW1-4 workflow:
0x20 / 0x28For example, timer IRQ0 becomes vector 0x20 after remapping instead of conflicting with CPU exceptions at 0x0-0x1F.
Remapping the 8259 PIC's IRQ0-15 to vectors 32-47 is a mandatory step in every real x86 kernel, because without it hardware interrupts collide with CPU exception vectors 0-31 and a keyboard press could be misread as a divide-by-zero fault. Forgetting to send EOI after handling an interrupt is why a kernel's very first IRQ0 timer tick often silently hangs all future interrupts.
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 program PIC initialization and implement EOI in IRQ stubs. The task asks you to unmask timer IRQ only after handler registration is complete.
Program and simulate the two cascaded 8259 PICs that route IRQs to the CPU on every PC. At boot they deliver IRQ 0-7 on vectors 0x08-0x0F, which collide with CPU exceptions, so every kernel remaps them with the four initialisation words (ICW1. ICW4). After that the kernel masks/unmasks lines, and the PIC delivers the highest-priority pending interrupt. The handler must end with an end-of-interrupt (EOI) command, or lower-priority IRQs stay blocked forever. For slave IRQs the EOI must go to both chips.
Master: command 0x20, data 0x21. Slave: command 0xA0, data 0xA1. The slave's output is wired to master IRQ 2.
| Command | Behaviour |
|---|---|
remap M S | ICW1 0x11 to both command ports; ICW2 = vector offsets M/S (hex) to the data ports; ICW3 0x04 (master: slave on IRQ2) and 0x02 (slave identity); ICW4 0x01 (8086 mode) to both; then rewrite the current masks. Each port write is printed in exactly this order: master before slave for every ICW. |
mask N / unmask N | set/clear bit N mod 8 in the owning chip's IMR (both start at 0xFF, all masked), then write the IMR to its data port |
raise N | a device asserts IRQ N (sets its IRR bit) |
ack | the CPU acknowledges: deliver the highest-priority deliverable IRQ (see below) |
eoi N | the handler for IRQ N finishes: for N ≥ 8 send 0x20 to 0xA0 first, then always 0x20 to 0x20 |
state | print IRR/ISR/IMR of both chips |
The priority order is 0, 1, 8, 9, …, 15, 3, 4, 5, 6, 7, because slave IRQs sit at IRQ 2's position.
For ack, walk that order. Stop at the first IRQ that is in service, since everything below it is blocked. Skip slave IRQs while master ISR bit 2 is set. Deliver the first IRQ that is pending and unmasked (a slave IRQ also needs master IRQ 2 unmasked). Delivery clears the IRR bit and sets the ISR bit, and for a slave IRQ it also sets master ISR bit 2. The vector is offset + (N mod 8) of the owning chip.
A non-specific EOI clears the chip's highest-priority ISR bit. On the slave, that is its lowest set bit. On the master, walk the priority order and clear the first set bit, but leave bit 2 set while the slave still has an IRQ in service.
cLoading…
Input:
cLoading…
Output:
cLoading…
outb(port, value) function that prints it.Hidden tests cover a slave IRQ blocked because master IRQ 2 is masked, nested delivery of a higher-priority IRQ while a lower one is in service, a forgotten EOI blocking everything below it, and a slave IRQ acknowledged only after both EOIs.