Monolithic Architecture with Modular Extensions

Updated

October 30, 2026

Monolithic Architecture with Modular Extensions

Operating system kernels generally fall into two classic design philosophies: microkernels and monolithic kernels.

+-----------------------------------------------------------+
|              Microkernel Architecture (e.g. seL4)         |
|  Userspace: [ File System ]  [ Network Stack ]  [ Drivers]|
|                   IPC Message Passing                     |
|  Kernel Space: [ Low-level Memory & Task Scheduling Only ]|
+-----------------------------------------------------------+

+-----------------------------------------------------------+
|             Monolithic Architecture (Linux Kernel)        |
|  Userspace: [ Application ]                               |
|                   POSIX System Calls (Ring 3 -> Ring 0)   |
|  Kernel Space:                                            |
|   [ VFS ] [ TCP/IP Stack ] [ Memory Management ]          |
|   [ Process Scheduler ] [ Device Drivers & Loadable Mod ] |
+-----------------------------------------------------------+

Why Linux is Monolithic

In a pure microkernel, device drivers, filesystems, and network stacks run as isolated userspace server processes. While this isolates faults (a driver crash won’t crash the entire kernel), passing data across user-kernel boundaries requires expensive context switches and inter-process communication (IPC) overhead.

Linux is a monolithic kernel: - All core operating system services—process scheduling, memory allocation, virtual filesystems, network protocols, and hardware device drivers—execute within a single unified address space in supervisor mode (Ring 0 on x86). - System calls (syscall) transition the CPU from user mode (Ring 3) directly into kernel mode with minimal overhead. - Direct pointer dereferencing within kernel space makes Linux extraordinarily fast and responsive.

Loadable Kernel Modules (LKMs)

A purely static monolithic kernel would require recompiling and rebooting the entire operating system every time a new USB device, network card, or filesystem was attached.

To achieve flexibility without sacrificing bare-metal speed, Linux introduced Loadable Kernel Modules (LKMs): - Code compiled into .ko (Kernel Object) ELF binaries. - Dynamically inserted into the running kernel using init_module or finit_module syscalls (insmod or modprobe). - Linked into kernel memory at runtime, running with full Ring 0 privileges.

# Listing currently loaded modules in the running kernel:
$ lsmod | head -n 5
Module                  Size  Used by
overlay               151552  0
ext4                 1052672  1
crc32c_generic         16384  0
ahci                   45056  2

Built-In (=y) vs. Modular (=m) Drivers

When configuring a custom kernel for your distribution, you will constantly choose between: - =y (Built-in): The code is compiled directly into the executable kernel image (vmlinuz). It is permanently resident in RAM from boot time. - =m (Module): The code is compiled into a standalone /lib/modules/<version>/.../*.ko file on disk. It is loaded on demand when the hardware is discovered by udev.

The Golden Rule for Distribution Builders

If a driver is strictly necessary to mount the root filesystem (e.g., your SATA/NVMe controller driver, your root filesystem driver like ext4 or btrfs), it must either be compiled as built-in (=y) or included inside the initramfs. If it is compiled as =m and left on the root disk, the kernel cannot read the disk to load the driver needed to read the disk!