JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

The Kernel, User Mode, and the Great Divide

Every modern computer draws one line above all others: the boundary between your programs and the kernel. Meet the mode bit that enforces it, the system call that crosses it, and the handful of ways a kernel can be built.

One machine, two worlds

In the first guide we said an operating system is three things at once: a resource manager, an abstraction layer, and a control program. Now we look at how it pulls off the control part. The trick is that the OS does not really trust your programs, and the hardware helps it stay suspicious. At the heart of everything sits the kernel — the part of the OS that is always in memory, the building manager who has the master key to every room while the tenants (your apps) have keys only to their own.

Why the distrust? Because a single buggy or malicious program could otherwise overwrite another program's memory, hog the CPU forever, or scribble directly on the disk and corrupt everyone's files. So modern CPUs run in two distinct worlds. In one world a program can do anything to the hardware; in the other it can do almost nothing dangerous without asking permission. This split is called dual-mode operation, and it is the single most important boundary in all of computing.

The mode bit: one switch that changes everything

How does the CPU know which world it is in? With a single flag in a hardware register called the mode bit. By convention, 0 means kernel mode (also called supervisor or privileged mode) and 1 means user mode. Your application code runs with the bit set to user mode. The kernel runs with it cleared to kernel mode. One bit — that is the whole fence.

The bit matters because certain machine instructions are marked as privileged instructions: halt the CPU, change the mode bit itself, load the table that controls memory mapping, talk directly to a disk controller. If user-mode code tries to execute one of these, the CPU does not obey — it raises an exception that hands control straight to the kernel, which usually kills the offending program. So a program cannot simply flip the bit to grant itself power; the act of flipping it is itself privileged. The only legitimate way up is the doorway we meet next.

Crossing the line: the system call

If user programs cannot touch hardware, how do they ever read a file or print to the screen? They ask the kernel to do it for them. That request is a system call, and it is the one and only sanctioned door from the user world into the kernel world. Crucially, a system call does not work like an ordinary function call that jumps wherever you point it; that would let you land anywhere in the kernel. Instead the program executes a special trap instruction — a deliberate, controlled software interrupt that the CPU handles by switching to kernel mode and jumping to one fixed, pre-registered entry point that the kernel chose in advance.

Think of it like a bank teller window. You cannot walk into the vault, but you can slide a slip under the glass: "please give me 100 from account 42." The teller (the kernel) checks that you are allowed, does the dangerous part safely on your behalf, and hands back a result. Here is the trip a call like read(fd, buf, n) takes, step by step.

  1. The program puts the call's identity and arguments where the kernel expects them — a call number (say, the one for read) goes in a register, and the file descriptor fd, the buffer address buf, and the count n go in others.
  2. It executes the trap instruction. The CPU switches the mode bit to kernel mode and jumps to the kernel's fixed entry point — the program does not get to pick where it lands.
  3. The kernel reads the call number, looks it up in a table, and runs the matching handler. It validates everything first: is fd really an open file? Does buf point into memory this program is actually allowed to write?
  4. It performs the privileged work — talking to the device, copying bytes into your buffer — then puts a return value in a register, flips the mode bit back to user mode, and resumes your program right after the trap. From the program's point of view, it simply called a function and got an answer.

One subtlety worth getting straight early: the read() you write in your code is usually not the system call itself. It is a thin library wrapper provided by your language or the C library, which arranges the registers and executes the trap for you. That distinction — the friendly API versus the underlying system call — is why the same program can often run on different systems: the API stays the same even when the trap details differ underneath.

Sharing the machine: many programs, one CPU

Once the kernel safely owns the hardware, it can do something wonderful: let several programs share one computer. The first step was multiprogramming — keep several jobs loaded in memory at once, so that the moment one job stops to wait for a slow disk read, the CPU immediately switches to another job instead of sitting idle. The expensive CPU stays busy; throughput soars.

Time-sharing, which we call multitasking today, took this further. Instead of waiting for a job to pause on its own, the kernel uses a hardware timer that fires an interrupt every few milliseconds. On each tick the kernel can yank the CPU away from the running program and give it to another. The switches happen so fast that to you, music, a browser, and an editor all appear to run at once. Be honest about what this is, though: with a single CPU core it is concurrency (progress interleaved in time), not parallelism (literally two things at the very same instant). True parallelism needs more than one core.

The act of saving one program's state — its registers, its program counter — and loading another's so it can resume exactly where it left off is a context switch. It is the kernel quietly bookmarking your place. It is not free; every switch costs a little time and is pure overhead, which is one reason a timer slice is not made vanishingly small.

How kernels are built

We have been speaking of "the kernel" as one thing, but there is real choice in how a kernel is structured. The oldest and still most common design is the monolithic kernel: nearly all the OS — process scheduling, memory management, file systems, device drivers, the network stack — lives together in one big privileged program. Everything runs in kernel mode, so the pieces call each other directly and it is fast. Linux is the famous example. The risk: a bug in any one driver runs with full power and can crash the whole machine.

The other end of the spectrum is the microkernel. Here the privileged core is shrunk to the bare minimum — just enough to handle the mode switch, basic memory, and message passing. The file system, the drivers, even parts of memory management are moved out into ordinary user-mode processes that talk to each other by sending messages. Now a crashed driver is just one user process dying; the kernel restarts it and the system survives. The cost is that those messages must cross the user/kernel line constantly, and that inter-process communication is slower than a direct in-kernel call.

MONOLITHIC                    MICROKERNEL
+----------------------+      +-------+ user processes
| app   app   app      |      | app   app   app      |
+----------------------+      | FS  driver  net      |  (user mode)
|  scheduler  memory   |      +----------------------+
|  file sys   drivers  |      | sched  mem  IPC      |  (kernel mode)
|  net stack  ...      |      +----------------------+
+----------------------+      tiny core; rest talks by messages
big core, all in kernel mode
Same jobs, two layouts: a monolithic kernel keeps everything inside the privileged box; a microkernel pushes most of it out into user-mode servers.

Most real systems land in between as a hybrid kernel: a largely monolithic core for speed, but with some services modularized or pushed out, blending the two philosophies. Windows and macOS sit roughly here. Resist the tempting conclusion that the microkernel is simply "better": it trades raw speed for robustness and is the right call only when isolation matters more than the IPC cost. There is no free lunch — only a choice about what you are willing to pay for.