What is an Operating System?
An operating system (OS) is the foundational software layer that manages hardware resources and provides a consistent interface for application programs. It sits between the bare metal (CPU, memory, disks, network cards) and the software you actually run, turning raw hardware into a set of clean, reusable abstractions.
Without an OS, every program would have to negotiate directly with hardware: twiddling interrupt controllers, writing to device registers, and manually partitioning memory. The OS centralizes that work so that programs get a clean virtual machine: a private address space, a virtual CPU via scheduling, and named files and sockets instead of raw disk blocks and wire signals.
The OS pursues two jobs at once:
- Resource manager — fairly and safely divides CPU time, memory, storage, and I/O among competing programs.
- Abstraction provider — gives applications portable, hardware-independent interfaces (processes, files, sockets) via system calls.
Why Do We Need an OS?
- Safety: applications must not crash each other or corrupt the kernel. The OS enforces isolation so one buggy program can’t read another process’s memory.
- Fairness & efficiency: without scheduling, a runaway loop would starve everything else. The OS multiplexes scarce resources.
- Portability: a program written against POSIX system calls runs on Linux, macOS, and BSD alike — the OS hides the hardware differences beneath it.
- Convenience: files, directories, pipes, and sockets are far more usable than “track 42, sector 7.”
The Kernel
The kernel is the core of the OS — the always-resident portion that runs in privileged mode and has unrestricted access to hardware. Everything else is system software (shells, compilers, daemons) or user applications.
The kernel is responsible for:
- Process & thread management — creation, scheduling, context switching, and synchronization.
- Memory management — virtual address spaces, paging, and protection.
- File systems & storage — organizing persistent data into files and directories.
- Device drivers — mediating access to hardware through interrupts and register I/O.
- Networking & IPC — sockets, pipes, signals, and shared memory between processes.
- Security & access control — permissions, users, and capability checks on every operation.
User Mode vs Kernel Mode
Modern CPUs have at least two privilege levels. On x86 these are rings, with ring 0 (kernel) and ring 3 (user); most OSes use just two effectively.
- User mode: applications run here with restricted instructions and no direct hardware access. They only see their own virtual address space.
- Kernel mode: the OS runs here with access to all instructions, all memory, and all devices.
The transition between them is what makes the model safe. A user program cannot just jump into kernel code — it must go through controlled entry points (see below). When the CPU is in user mode, privileged instructions (like directly writing to the page table or disabling interrupts) are trapped and routed to the kernel.
System Calls
System calls are the only bridge from user space to kernel space. They are the API of the OS — the documented, controlled entry points through which a program requests kernel services.
The flow for every syscall:
- The program sets up arguments (registers or a memory block) and executes a special instruction (
syscallon x86-64,svcon ARM). - The CPU switches to kernel mode and jumps to a kernel handler for the syscall number.
- The kernel validates arguments, performs the operation (with permission checks), and returns to user mode with a result or error.
Common POSIX syscalls:
- Process:
fork,exec,wait,exit,kill - Files:
open,read,write,close,fsync - Memory:
mmap,munmap,brk - IPC/Networking:
pipe,socket,connect,send,recv
A syscall is not a function call: a library call (read() in glibc) may stay entirely in user space or wrap one syscall, and syscalls are far more expensive because they require a mode switch.
OS Abstractions
The OS virtualizes hardware into three core abstractions:
- Process — the OS’s virtual CPU. Each process believes it has the whole processor to itself; the scheduler interleaves many processes.
- File — the OS’s virtual storage. A file is a named, byte-addressed object; the kernel maps it onto disks, SSDs, pipes, or even other processes.
- Socket / pipe — the OS’s virtual network and IPC. Programs exchange bytes through these named channels without knowing the physical link underneath.
The key idea: virtualization. The OS makes a single piece of hardware look like an infinite supply of safe, independent resources.
Kernel Architectures
Kernels differ in how much they put in privileged space and how components talk to each other.
| Architecture | What runs in kernel | Strengths | Weaknesses |
|---|---|---|---|
| Monolithic (Linux, BSD) | Everything — scheduling, drivers, file systems, network stack | Fast, tight integration | A bug in any driver can crash the whole kernel |
| Microkernel (QNX, seL4, Minix) | Minimal core (IPC, scheduling, basic memory) only; drivers/services run as user-space processes | Strong isolation, fault tolerance | More IPC overhead, harder to build fast |
| Hybrid (Windows NT, macOS/XNU) | Core kernel + selected drivers/services in privileged space | Balance of speed and modularity | More attack surface than a microkernel |
Linux is monolithic in the classic sense but mitigates it with loadable kernel modules (LKM) — drivers can be inserted and removed at runtime without rebuilding the kernel, and modern hardening (KASLR, module signing) reduces the blast radius.
The Boot Sequence
How does the OS get from power-on to a running system?
- BIOS/UEFI runs from firmware, initializes hardware, and selects a boot device.
- The bootloader (GRUB, systemd-boot) loads the kernel image and an initial RAM disk into memory.
- The kernel decompresses and initializes CPU/memory structures, sets up page tables, and enables interrupt handling.
- The kernel mounts the real root file system and launches the first user-space process (init —
systemd,sysvinit, or a container runtime). initstarts services (daemons, network, display manager), and the system reaches a usable state — possibly letting you log in.
Everything that happens before the kernel hands off to init is largely invisible to user-space code, which is why boot is a common source of “it worked yesterday” mysteries.
Worked Example: A Single read() Call
Trace what happens when a C program reads from a file:
- The program calls
read(fd, buf, 100)— a glibc wrapper. - The wrapper issues a
syscallinstruction with the read syscall number. - The CPU traps to kernel mode; the kernel looks up the file descriptor, checks the process’s permissions and buffer validity.
- The kernel reads the data from the page cache or disk and copies it into the user buffer.
- The CPU returns to user mode;
readreturns the byte count.
That single call crosses the user/kernel boundary twice — the fundamental cost of using an OS.
Practice Trajectory
- Boot a Linux machine and run
dmesgandls /proc— identify what the kernel initialized and which processes are live. - Compare
cat /proc/cpuinfowith the output ofuname -a; note how the kernel abstracts the CPU. - Use
strace -e trace=open,read lsto watch a trivial command make syscalls — count the mode switches. - List every abstraction the OS provides that a bare-metal program would have to build itself.
- Explain the trade-off between a monolithic and a microkernel design for an embedded device vs a server.
When It’s the Right Tool
| Situation | Takeaway |
|---|---|
| Learning OS internals | Start from the kernel/syscall boundary — everything else hangs off it |
| Choosing a design for safety-critical systems | Microkernels (QNX, seL4) contain faults; monolithic kernels maximize throughput |
| General-purpose servers & cloud | Linux’s monolithic-plus-modules design is the pragmatic default |
| Debugging application issues | Trace the syscall boundary first: strace/perf separate app bugs from kernel behavior |