Visual walkthrough — OS structure — monolithic, microkernel, hybrid
We will never use a symbol before we draw it. Let's start with the single wall the entire subject is built around.
Step 1 — The one wall: kernel mode vs user mode
WHAT. A modern CPU refuses to let ordinary programs touch hardware directly. It runs code in one of two privilege levels. Think of a wall running through the machine:
- On the outside is user mode — where your apps live. Restricted: they cannot poke the disk, the network card, or another program's memory.
- On the inside is kernel mode — trusted code that can do anything: touch any memory, command any device.
WHY this wall exists at all. Without it, one buggy app could overwrite the OS or another app. The wall contains damage. Every design decision on this page is about what you put on which side of this wall.
PICTURE. In the figure the wall is the vertical red line. Left of it: a user program. Right of it: the hardware (disk). The only way through the wall is a special guarded gate we'll meet in Step 2.

Step 2 — Crossing the wall costs something: define
WHAT. A user program cannot walk through the wall freely. It must ask the kernel by making a system call, which fires a trap — the CPU pauses the app, flips into kernel mode, and hands control to the OS. When the kernel is done it flips back to the app.
We must be precise about what we are counting, because the rest of the page depends on it:
WHY it is not free. Each one-way passage forces the CPU to:
- save the current side's registers (so it can resume later),
- switch privilege level and possibly switch address space,
- often copy data across the wall (neither side can see the other's memory).
All three are real work. We bundle their cost into a single number:
PICTURE. The red gate in the wall. The arrow going in (trap) is one crossing costing ; the arrow coming back out (return) is a separate crossing costing another . Two arrows ⇒ two crossings ⇒ .

Step 3 — Count the crossings for one job: define
WHAT. A single user request (say, "read a file") is rarely one crossing. The kernel may have to bounce the request between several services — the file-system code, then the disk-driver code — and each one-way passage through the wall is another crossing. Count them all for one request and call that count .
WHY this is the number that matters. The app doesn't care how the OS is organised internally — it cares how long its read() takes. The time spent at the wall is simply: number of one-way passages times the toll per passage.
PICTURE. A single request drawn as a path that pokes through the wall times; each poke is stamped "". The total length of red = .

Recall Why "
" and not "\approxn$.
Step 4 — Put services on the SAME side: the monolithic case
WHAT. In a monolithic kernel every core service — scheduler, memory manager, file system, device drivers — lives inside the wall, in kernel mode, as one program. When the file-system code needs the disk driver, it just calls it like an ordinary function.
WHY is tiny here. A function call inside kernel mode does not cross the wall — both pieces already live on the privileged side, sharing one address space. So the ONLY passages are the two unavoidable ones: the app trapping in, and the result returning out.
- The "in" passage: app → kernel (one ).
- Everything in between: plain function calls, zero passages.
- The "out" passage: kernel → app (one ).
PICTURE. All services drawn as boxes packed together on the kernel side. The request enters once (red), bounces between services with thin black function-call arrows (free — no wall between them), and exits once (red). Only two red pokes through the wall.

Step 5 — Put services on the OTHER side: the microkernel case
WHAT. In a microkernel, only the bare minimum stays inside the wall (low-level memory, thread scheduling, and IPC). The file system and the disk driver are kicked outside — they become ordinary user-mode server processes. Now for the FS code to reach the disk driver, its message must go out through the wall to the microkernel and back out to the other server — every hand-off is a real passage.
WHY explodes. Each pair of talking services now sits on opposite sides of a wall (or must relay through the kernel), so what was a free function call in Step 4 is now a full boundary passage costing .
Let's count it exactly, so the "4–6" is not hand-waved. A read() needs the app to reach the FS server, the FS server to reach the disk-driver server, and every reply to travel back. Each relay through the microkernel is one passage in + one passage out = 2 crossings.
- — the passage count, now several times .
- — same fixed toll; nothing about changed, only how many times we pay it.
PICTURE. The same request, but now the FS server and driver server are separate boxes outside the wall. Every arrow that used to be a free black function call is now a red poke through the wall. Count the red pokes — there are many.

Step 6 — The reliability flip-side: same wall, read backwards
WHAT. Everything above measured speed (). Now read the same picture for a different question: what happens when a service has a bug and crashes?
WHY the wall matters again. A crash of code inside kernel mode is a crash of the trusted core — it can corrupt any memory and take the whole machine down. A crash of code outside the wall is just a user process dying — the kernel isolates it and can restart it.
- Monolithic (Step 4): the buggy driver runs inside the wall → one bug can crash everything. Low reliability. Large trusted code base.
- Microkernel (Step 5): the buggy driver is a user process outside the wall → it dies alone, kernel survives, restarts it. High reliability. Tiny trusted core.
So the very thing that made monolithic fast (services inside the wall, small ) makes it fragile, and the very thing that made microkernel safe (services outside the wall) makes it slow (large ). One wall, two opposite consequences.
PICTURE. Two panels sharing the wall. Left: a driver crashing inside — a red shockwave spreading over the whole kernel side. Right: a driver crashing outside — the red damage stopped dead at the wall, everything else untouched.

Step 7 — The compromise: hybrid, and the degenerate edges
WHAT. A hybrid kernel keeps the modular, server-style layout of a microkernel but pulls the hot-path services (file system, graphics) back inside the wall to kill their passages. It chooses per-service which side of the wall to sit on.
WHY it wins in practice. For a service used constantly (graphics, FS), the extra passages dominate — so hybrids drag those inside (small , fast). For rarely-used or risky services, isolation outside the wall is worth the toll. Result: is small for the paths that matter.
Let's put a concrete number on it, so "in between" isn't vague. In a hybrid, the FS is inside the wall (like a monolith), so the file-system hop is a free function call — but a different service still living outside (say a printer or an audio server) does cost a relay.
Now the edge cases — check the formula never breaks in any degenerate scenario:
- Pull every service inside the wall (): the hybrid collapses into a monolith. The formula gives , the fastest possible non-trivial request. ✔ (Linux kernel modules show a monolith staying modular in source while everything still runs inside the wall — modularity of code is not the same as crossing the wall.)
- Push every service outside the wall ( maximal): the hybrid collapses into a pure microkernel, so is maximal. ✔ This is the opposite extreme of the same slider.
- A request needing no privileged work at all (): — a pure user-mode computation touches the wall zero times, so it pays zero crossing-time. ✔ The formula degrades gracefully to nothing.
- A magically free passage (): for every structure, and the speed distinction between monolith, hybrid and microkernel vanishes entirely — proving the whole trade-off lives inside the crossing toll , not anywhere else. ✔
So across every edge — everything inside, everything outside, zero work, free toll — the single relation keeps giving the right answer. The three named designs are just three points on one continuous slider, and the formula is the ruler that measures the whole slider.
PICTURE. A slider along the wall: at the far-left end everything is inside (monolith, ); at the far-right end everything is outside (microkernel, big ); the hybrid sits in the middle with hot-path boxes yanked inside (red) and cold services left outside.

Step 8 — The trade-off table you promised yourself
WHAT. We opened by claiming you'd be able to derive the whole comparison. Here it is — and every column below is just a reading of and the crash-blast-radius picture of Step 6. Check your own counting against it.
| Property | Monolithic | Hybrid | Microkernel |
|---|---|---|---|
| Services in kernel mode | All | Core + hot-path | Minimal (IPC, sched, mem) |
Passages for a read(), |
|||
| Cost | |||
| Communication style | function call | mix | IPC messages |
| Crash blast radius (Step 6) | whole machine | medium | one server |
| Reliability / isolation | Low | Medium | High |
| Trusted code base | Large | Medium | Tiny |
| Speed | Fastest | Middle | Slowest |
| Examples | Linux, UNIX | Windows NT, macOS | MINIX 3, QNX, L4 |
WHY this is the entire chapter. Read the row left-to-right: it only grows. Since with fixed, the cost row grows with it — that is the speed order MONO > HYBRID > MICRO. Read the blast-radius row: it only shrinks — that is the reliability order, exactly reversed. Two rows, one formula, whole trade-off.
PICTURE. One axis — "services inside the wall" — with the three kernels placed on it, speed labelled on top and reliability labelled below, so both orderings appear in a single glance.

Recall Feynman retelling — the whole walkthrough in plain words
There is a wall in every computer. Inside it, code can do anything; outside it, code must knock and ask. Each one-way knock through the wall has a fixed cost — call it the toll, (Step 2). A "knock in, answer out" is two knocks, so . To finish a job like "read a file," the request has to pass through the wall some number of times — call that (Step 3). The total time wasted at the wall is just tolls times passages: . Now here's the only choice an OS designer makes: which helpers live inside the wall?
- Put them all inside (monolith, Step 4): they chat for free, so only 2 passages — fast. But if any one goes crazy inside the wall, it wrecks the whole machine (Step 6) — fragile.
- Kick them all outside (microkernel, Step 5): now every chat is a passage, so 4–6 of them — slow. But a crazy helper outside just gets thrown out and restarted — safe.
- Hybrid (Step 7): keep the layout of "helpers outside," but drag the busiest ones back inside to skip their passages — so hot paths cost ~2, cold ones ~4. Fast enough, safe enough. Speed and safety pull the same rope: moving a helper outside to protect it is the very act that adds a passage. That's why you can't have both — and that single sentence, plus the table in Step 8, is the entire chapter.
Recall Self-check
A request crosses the wall 4 times, each one-way passage costs 5 units. What is ? ::: units. The same request in a monolith takes 2 passages. What is its ? ::: units — half the microkernel cost, matching . A hybrid handles that request on a hot path with 2 passages, but on a cold path with 4. What are the two costs at ? ::: Hot path ; cold path — sitting between monolith and microkernel, exactly as the table predicts. If a service is pure user-mode computation (), what is ? ::: — no wall passage, no crossing-time. Which single quantity, when it goes to zero, erases the whole speed trade-off? ::: The per-passage toll — if then for every structure.