Free lesson · Operating Systems
User Mode Vs Kernel Mode
Two Worlds Inside Your CPU
Your CPU does not treat all code equally. It has two distinct operating modes - user mode and kernel mode - and it behaves very differently depending on which mode it is in. Understanding these two modes is essential for interviews because they explain why system calls exist, why processes are isolated from each other, and why a bug in your application cannot crash the entire operating system.
In user mode, the CPU runs with restricted privileges. Your application code runs in user mode. In this mode, the CPU can execute normal instructions - arithmetic, logic, branching, function calls - but it cannot directly access hardware devices, modify page tables, change interrupt handlers, or access memory that belongs to other processes or the kernel. If user-mode code tries to execute a privileged instruction or access forbidden memory, the CPU raises an exception and the OS handles it - typically by killing the offending process with a segmentation fault.
In kernel mode, the CPU runs with full privileges. The operating system kernel runs in kernel mode. In this mode, the CPU can do anything - access any memory address, talk directly to hardware devices, modify page tables, enable and disable interrupts, and execute any instruction. Kernel mode is unrestricted because the OS needs unrestricted access to manage the hardware on behalf of all the processes running on the system.
The boundary between user mode and kernel mode is enforced by the CPU hardware itself, not by software. This is a critical design choice - it means that even a perfectly crafted exploit in user-mode code cannot bypass the boundary without finding a vulnerability in the kernel. The hardware is the ultimate enforcer.
graph TD
subgraph UM["User Mode (Ring 3)"]
A["Application Code<br/>────────────<br/>Can execute normal instructions<br/>Can access own memory only<br/>Cannot touch hardware<br/>Cannot modify page tables<br/>Cannot disable interrupts"]
end
subgraph BOUNDARY["Mode Switch Boundary"]
T["Triggered by:<br/>• System call (SYSCALL instruction)<br/>• Hardware interrupt<br/>• Exception (page fault, divide by zero)"]
end
subgraph KM["Kernel Mode (Ring 0)"]
K["OS Kernel Code<br/>────────────<br/>Can execute ALL instructions<br/>Can access ALL memory<br/>Can talk to hardware directly<br/>Can modify page tables<br/>Can enable/disable interrupts"]
end
UM --> BOUNDARY --> KM
KM --> BOUNDARY --> UM
This diagram shows two layers: user mode at the top and kernel mode at the bottom, separated by a mode switch boundary. User mode can execute normal instructions and access its own memory, but cannot touch hardware, modify page tables, or disable interrupts. Kernel mode can do everything - execute all instructions, access all memory, and talk directly to hardware. The boundary is crossed via system calls, hardware interrupts, or exceptions.
Why Two Modes Exist
The two-mode design solves three problems simultaneously: protection, stability, and security.
Protection. Without separate modes, any program could overwrite any other program's memory, corrupt the file system by writing random data to disk, or disable the OS's scheduling timer so it monopolizes the CPU forever. User mode prevents all of this by restricting what programs can do. Your buggy Python script cannot corrupt the kernel's data structures because it physically cannot access the memory where those data structures live.
Stability. If a user program crashes - accesses invalid memory, divides by zero, enters an infinite loop - only that process is affected. The OS is still running in kernel mode, managing all the other processes normally. The crash does not propagate. On a server handling 10,000 concurrent connections, one connection's crash does not bring down the other 9,999. This isolation is only possible because user-mode programs cannot affect kernel-mode operations.
Security. The mode boundary is the foundation of the OS's security model. When a process makes a system call, the kernel validates the request - does this process have permission to read this file? Is this process allowed to bind to this port? Is this process within its resource limits? Without the mode boundary, there would be no checkpoint where the OS could enforce these policies.
How Mode Switching Works
There are three events that cause the CPU to switch from user mode to kernel mode. Each one is a trap - a controlled transfer from user space to kernel space.
1. System Calls (Software Traps)
When a process needs an OS service, it executes a special instruction (syscall on x86-64) that triggers a trap. The CPU saves the process's state, switches to kernel mode, and jumps to the kernel's system call handler. This is the mechanism we covered in Topic 6 - it is the controlled entry point that programs use to request services from the OS.
The key word is controlled. A system call does not let user code jump to an arbitrary location in the kernel. The CPU jumps to a pre-configured handler address that the kernel set up at boot time. The user code has no influence over where in the kernel execution begins - it can only specify which system call it wants (via the syscall number) and provide arguments.
2. Hardware Interrupts
Hardware devices need to get the CPU's attention. When a disk completes a read, a network card receives a packet, or a keyboard key is pressed, the hardware device sends an interrupt signal to the CPU. The CPU pauses whatever user-mode process is currently running, switches to kernel mode, and runs the interrupt handler for that device.
Interrupts are essential for efficient I/O. Without interrupts, the CPU would have to constantly check (poll) every device to see if it had data ready - an enormous waste of CPU time. With interrupts, the CPU can focus on running processes and only switch to kernel mode when a device actually has something to report.
The timer interrupt is particularly important for multitasking. A hardware timer generates interrupts at regular intervals (typically every 1-10 milliseconds). Each timer interrupt causes a trap to kernel mode, where the scheduler checks whether the currently running process has exceeded its time slice. If it has, the scheduler preempts it and switches to another process. This is the mechanism that makes preemptive multitasking work - no user process can monopolize the CPU because the timer interrupt will always fire and give the scheduler a chance to intervene.
3. Exceptions (Faults and Traps)
An exception occurs when the CPU encounters a problem while executing a user-mode instruction. Common exceptions include a page fault (the process accessed a virtual memory address that is not currently mapped to physical memory - the kernel needs to load the data from disk or allocate a new page), a segmentation fault (the process accessed memory outside its allocated address space - the kernel terminates the process), a divide by zero (the process executed a division by zero - the kernel sends SIGFPE to the process), and an illegal instruction (the process tried to execute a privileged instruction in user mode - the kernel terminates the process).
Not all exceptions are fatal. Page faults are a normal part of virtual memory operation - they happen constantly as the OS loads data on demand. The kernel handles the page fault by loading the needed data into memory and then resumes the process as if nothing happened. This is an example of a benign mode switch: user mode → kernel mode (handle page fault, load page) → user mode (process continues).
Segmentation faults, on the other hand, are fatal. They mean the process did something it should not have, and the kernel terminates it. This is user mode protection in action - the hardware detected an access violation and trapped to the kernel, which enforced the boundary by killing the violating process.
sequenceDiagram
participant App as User Mode Process
participant CPU as CPU Hardware
participant Kernel as Kernel Mode
Note over App: Process running normally
App->>CPU: Accesses unmapped memory address
CPU->>CPU: Check page table: page not present
CPU->>Kernel: PAGE FAULT exception<br/>(switch to kernel mode)
alt Valid address, page on disk
Kernel->>Kernel: Load page from disk<br/>Update page table
Kernel->>App: Resume process<br/>(switch to user mode)
Note over App: Process continues,<br/>unaware of the fault
else Invalid address
Kernel->>App: Send SIGSEGV<br/>(segmentation fault)
Note over App: Process terminated
end
This sequence diagram shows two types of exceptions. A user mode process accesses an unmapped memory address. The CPU detects this and raises a page fault, switching to kernel mode. If the address is valid but the page is on disk, the kernel loads the page, updates the page table, and resumes the process in user mode - the process never knows the fault happened. If the address is invalid, the kernel sends a segmentation fault signal and the process is terminated.
The Cost of Mode Switches
Every transition between user mode and kernel mode has a performance cost. The CPU must save the user-mode state (registers, program counter, stack pointer), switch to the kernel stack, execute the kernel code, switch back to the user stack, and restore the user-mode state. This takes hundreds of nanoseconds - not much for a single transition, but it adds up when a program makes millions of system calls.
Beyond the direct CPU cost, mode switches cause indirect costs. The kernel code that runs during the switch may evict the user program's data from the CPU cache. When control returns to user mode, the program may experience cache misses as it reloads its data. On modern CPUs with speculative execution, mode switches also require flushing prediction buffers and other speculative state, which adds additional overhead.
This is why system call overhead is a real performance concern in high-throughput systems. Techniques like buffered I/O, memory-mapped files, io_uring, and batching system calls all exist to minimize the number of mode switches per operation.
Interview: The interviewer asks: "Explain user mode vs kernel mode."
"The CPU operates in two modes that differ in privilege level. User mode is for application code - it can execute normal instructions but cannot access hardware directly, modify page tables, or access other processes' memory. Kernel mode is for the OS - it has unrestricted access to all hardware and memory. The boundary is enforced by the CPU hardware, not software.
Three events cause a switch from user to kernel mode: system calls (when a program requests an OS service), hardware interrupts (when a device needs attention, like the timer interrupt that enables preemptive scheduling), and exceptions (like page faults or segmentation faults).
The purpose of this separation is protection - it ensures that a bug in any user program cannot corrupt the OS, crash the hardware, or access another program's data."
This answer covers the what (two modes with different privileges), the how (three types of traps), and the why (protection). That is the structure interviewers are looking for.
Protection Rings: The Full Picture
Some architectures, particularly x86, define more than two privilege levels. x86 defines four protection rings, numbered 0 through 3. Ring 0 is the most privileged (kernel mode). Ring 3 is the least privileged (user mode). Rings 1 and 2 were originally designed for device drivers and other intermediate-privilege code, but modern operating systems do not use them - they use only Ring 0 (kernel) and Ring 3 (user).
This simplification happened because the performance cost of using multiple rings was significant, and the complexity of managing intermediate privilege levels was not worth the security benefit. Modern OSes achieve the same security goals using virtual memory protection and careful kernel design instead.
However, the ring model became relevant again with the rise of virtualization. Virtual machine monitors (hypervisors like VMware or KVM) need a privilege level above the guest OS kernel. Some hypervisors use a technique where the hypervisor runs at Ring 0, the guest OS runs at Ring 1, and guest applications run at Ring 3. Modern CPUs solve this more cleanly with hardware virtualization extensions (Intel VT-x, AMD-V) that add a "Ring -1" - a privilege level above Ring 0 for the hypervisor. We cover virtualization in Module 13.
Real-World Implications for System Design
The user/kernel mode boundary has practical consequences that come up in system design interviews.
Network I/O and zero-copy. In a traditional network server, receiving data from the network and sending it to the client involves multiple mode switches: kernel receives data from the network (kernel mode), copies it to user buffer (mode switch to user), application processes it (user mode), copies it to kernel send buffer (mode switch to kernel), kernel sends it to the client (kernel mode). Each copy involves a mode switch. Zero-copy techniques like sendfile() let the kernel transfer data directly from one file descriptor to another without copying through user space, eliminating two mode switches. Apache Kafka uses this extensively, which is one reason it achieves high throughput with low latency.
System call batching. Linux's io_uring interface was designed specifically to reduce mode switch overhead. Instead of one system call per I/O operation, io_uring lets user programs submit many I/O requests to a shared ring buffer and collect many results from another ring buffer, all with a single system call or even zero system calls (using polling mode). This dramatically reduces mode switch overhead for I/O-intensive workloads.
Kernel bypass. Some extreme-performance systems bypass the kernel entirely for data-plane operations. Technologies like DPDK (Data Plane Development Kit) let user-mode programs talk directly to the network card without system calls. This eliminates mode switch overhead completely but sacrifices the protection the kernel provides. It is used in network routers, high-frequency trading systems, and other scenarios where microsecond latency matters more than protection. The trade-off is stark: you gain raw performance but lose the safety guarantees the kernel provides, which means a bug in your user-space network code can crash the network interface.
Tip: For system design interviews: Mentioning the user/kernel boundary when discussing performance optimization is a strong signal. If the interviewer asks how to optimize a data-intensive pipeline, you can say: "One option is to reduce mode switches by using memory-mapped I/O instead of read/write system calls, or using zero-copy I/O with sendfile() for data that passes through the system without modification."
Exercise: Starter: Think about what happens when you open a web browser and navigate to a website. How many mode switches occur? Consider: the browser process starts (fork/exec - mode switches), it opens a network socket (system call), it sends an HTTP request (system call), it receives the response (system call), it writes the page to the screen (system call). Each system call is a mode switch. Even a simple web page load involves dozens of mode switches.
Intermediate: On a Linux system, run
strace -c lsand look at the output. It shows a summary of all system calls made byls, including how much time was spent in each. The total time spent in system calls is time spent in kernel mode. Compare this to the total runtime. What percentage ofls's execution time is spent in kernel mode?Advanced: Research how
io_uringworks. How does it reduce the number of mode switches compared to traditionalread()/write()system calls? What trade-offs does it make? Why did Linux need this when it already hadepoll? Write a brief comparison (2-3 paragraphs) that you could use in a system design interview to explain when you would chooseio_uringover traditional I/O.