Table of Contents

You use an operating system every day. But do you know what actually happens between pressing the power button and your first process running?

Fireship’s video compresses every major OS concept into about 15 minutes, using the boot-to-shutdown lifecycle as a narrative backbone — turning what textbooks spread across dozens of chapters into a single coherent story. This post follows the same arc.

TL;DR

An operating system is the software layer between hardware and applications, managing CPU, memory, storage, and I/O. The best way to understand it is to follow a computer from power-on to shutdown — each phase maps to a specific OS subsystem.

What It Is

An operating system intermediates between applications and hardware. Its four core responsibilities:

  1. Resource management — who gets CPU time, how much memory, which disk blocks
  2. Isolation — one crashing program shouldn’t take down the system
  3. Abstraction — applications don’t need to know which CPU model or disk format they’re running on
  4. Interface — standard APIs (syscalls, file system, network) that applications can target

Why It Matters

Without an OS, every application would need to handle CPU scheduling, memory allocation, and hardware drivers itself — a practically impossible requirement. The OS absorbs that complexity so developers can focus on application logic.

Understanding OS internals makes you a better systems programmer: you can reason about why fork() is cheap but exec() is expensive, why many small files are slower than one large file, why context switches create performance bottlenecks.

How It Works: Boot to Shutdown

Firmware

When you press the power button, the first thing the CPU executes isn’t Linux or Windows — it’s firmware, a low-level program burned into a chip on the motherboard.

Modern machines use UEFI (Unified Extensible Firmware Interface); older machines use BIOS. Firmware’s job:

  • POST (Power-On Self Test): verify CPU, RAM, and storage are functional
  • Initialize hardware devices
  • Locate the bootloader and hand over control

UEFI is a significant upgrade over legacy BIOS: it supports disks over 2TB (GPT partition tables), provides a graphical interface, and enables Secure Boot.

Bootloader

Firmware finds the bootloader on the boot disk (GRUB on Linux systems) and hands control to it. The bootloader’s only job:

  1. Read the OS kernel image from disk
  2. Load the kernel into RAM
  3. Transfer control to the kernel

This takes a few seconds and is the bridge between the firmware world and the operating system world.

Kernel

The kernel is the OS core, running in kernel mode with direct access to all hardware. It owns everything that follows:

Kernel
├── Process Management
├── Memory Management
├── File System (VFS)
├── Device Drivers
└── System Call Interface

Linux is a monolithic kernel — all subsystems share one memory space, maximizing call efficiency. macOS’s XNU is a hybrid kernel, running some components in user space for stability.

Process Management

Once the kernel starts, it begins creating processes. Each process is an independent execution instance with its own:

  • Virtual address space
  • Open file descriptors
  • Process ID (PID)
  • At least one thread

Processes are isolated from each other — a crash in one process doesn’t directly kill others. Threads are the execution units within a process; all threads in the same process share memory, making them efficient for cooperative parallel work (but requiring locks to prevent data races).

CPU Scheduling

A machine might have dozens of processes “running” simultaneously, but CPU cores are finite. The scheduler decides who runs and for how long:

  • Preemptive scheduling: the scheduler can forcibly interrupt a running process and give the CPU to another
  • Time slice: each process typically gets a few milliseconds of CPU time per turn
  • Priority: real-time tasks (audio playback, input handling) run before background work

Linux uses the CFS (Completely Fair Scheduler), which tracks each process’s “virtual runtime” and always schedules the one that has run the least — preventing any process from starving indefinitely.

Memory Management

Each process sees a virtual address space, not physical memory addresses. The OS uses paging to maintain a mapping table between virtual addresses and physical page frames.

Three benefits of this design:

  • Isolation: process A cannot read process B’s memory even on the same machine
  • Demand paging: physical page frames are only allocated when memory is actually accessed, speeding up startup
  • Swap: when physical RAM is full, the OS evicts infrequently-used pages to disk to free space for active processes

Inter-Process Communication (IPC)

Processes are isolated, but sometimes they need to cooperate. The OS provides several IPC mechanisms:

MechanismUse Case
PipeParent-child processes, one-way data flow (cmd1 | cmd2)
Unix SocketBidirectional local communication
Shared MemoryHigh-throughput data exchange
SignalLightweight notifications (SIGTERM, SIGKILL)
Message QueueAsynchronous message passing

File System

To applications, all persistent data is accessed as “files.” The OS provides a unified interface via the Virtual File System (VFS) — the underlying storage can be ext4, APFS, NTFS, tmpfs, or NFS, but the API looks the same to applications.

Linux’s “everything is a file” philosophy exposes hardware devices (/dev/sda), process information (/proc/1234/status), and kernel settings (/sys/) all as readable/writable file paths — one consistent interface for the entire system.

System Calls

Applications run in user mode and cannot directly access hardware or kernel data structures. Any time an application needs OS services (reading a file, opening a socket, spawning a process), it must make a system call that switches to kernel mode:

open()   // open a file, get a file descriptor
read()   // read data from fd into a buffer
write()  // write buffer data to fd
fork()   // clone the current process
exec()   // replace the current process image with a new program
exit()   // terminate the process, release resources

Every syscall involves a user mode → kernel mode context switch, which has measurable overhead. This is why high-performance I/O frameworks like epoll and io_uring are designed explicitly to reduce syscall count.

strace is the go-to tool for intercepting syscalls and seeing exactly what a process is asking the OS to do:

strace -e openat,read,write ls /tmp

Boot to Shutdown at a Glance

graph LR
    A[Power Button] --> B[UEFI / BIOS]
    B --> C[Bootloader]
    C --> D[Kernel]
    D --> E[Process Management]
    D --> F[Memory Management]
    D --> G[VFS / File System]
    E --> H[User Processes]
    H -->|syscall| D

How OS Differs from VMs and Containers

Operating SystemVirtual MachineContainer
KernelOwn kernelOwn kernelShares host kernel
Isolation layerHardwareHypervisorcgroups + namespaces
Startup timeSecondsSeconds–minutesMilliseconds–seconds
OverheadLowHighVery low

Containers (Docker, Podman) aren’t “lightweight VMs” — they’re isolated processes sharing the host kernel, using Linux cgroups for resource limits and namespaces for visibility isolation. This is why Docker on macOS and Windows requires a Linux VM underneath: neither OS has a Linux kernel.

Summary

The OS has a clear logical chain: firmware initializes hardware → bootloader loads the kernel → kernel establishes process and memory management → processes access OS services via syscalls.

Each layer solves one specific problem: firmware abstracts hardware variation, the kernel abstracts resource contention, VFS abstracts storage backends, and the syscall interface abstracts privileged mode switching. Understanding this abstraction chain lets you reason about program behavior at the OS level rather than treating it as a black box.

References

🇺🇸 English

Every single day you press a power button and expect magic to happen. But between that button press and the moment your browser opens — there's an entire story playing out, and it maps almost perfectly to every major concept in operating systems.

Fireship made a video that compresses all of it into 15 minutes. Let's walk through that same arc.

---

So what even is an operating system? At its core, it's the software layer sitting between your hardware and your applications. It has four jobs: manage resources — who gets CPU time, memory, disk space. Provide isolation — so one crashing app doesn't take everything else with it. Abstract away the hardware — your app shouldn't need to know if it's running on an Intel chip or an ARM chip. And expose a standard interface — a set of APIs that every application can rely on.

Without this, every developer would have to write their own CPU scheduler and memory allocator. The OS absorbs that complexity so the rest of us can focus on building things.

---

**The boot sequence is where the story starts.**

The moment you hit that power button, the CPU doesn't run Linux or Windows — it runs firmware. On modern machines, that's UEFI. On older machines, BIOS. The firmware does something called POST — Power-On Self Test — which is just the machine checking that its CPU, RAM, and storage are actually working. Then it hands control to the bootloader.

UEFI is meaningfully better than legacy BIOS, by the way. It supports large disks over two terabytes, has a graphical interface, and enables Secure Boot — which prevents unsigned code from running during startup.

The bootloader — on Linux systems this is typically GRUB — has one job: find the kernel image on disk, load it into RAM, and get out of the way. It's a bridge between the firmware world and the OS world.

---

**Then the kernel takes over, and this is where things get interesting.**

The kernel runs in what's called kernel mode — it has direct, unrestricted access to every piece of hardware. Everything else — your apps, your shell, your browser — runs in user mode, which is sandboxed and limited. That distinction is fundamental to how modern OSes work.

The kernel itself is responsible for four big things: process management, memory management, the file system, and device drivers. Linux is what's called a monolithic kernel — all of those subsystems live in one shared memory space, which makes internal calls fast. macOS uses a hybrid approach, where some components run in user space for added stability.

---

**Processes.**

Once the kernel is running, it starts creating processes. A process is an independent execution instance — it gets its own virtual address space, its own set of open files, its own process ID. Crash one process and the others keep running, because they're isolated from each other.

Inside a process, you have threads — the actual units of execution. Threads within the same process share memory, which makes them efficient for parallelism. But it also means they can step on each other's data, which is why you need locks.

Now, with potentially dozens of processes wanting to run, the scheduler decides who gets CPU time and when. Linux uses something called CFS — the Completely Fair Scheduler. It tracks how much CPU time each process has used and always picks the one that's been waiting the longest. This prevents any single process from hogging the CPU indefinitely. Real-time tasks like audio playback get higher priority so they don't stutter.

---

**Memory management.**

Here's something subtle but important: when a process thinks about memory addresses, it's not looking at physical RAM directly. It sees a virtual address space. The OS maintains a mapping table — called a page table — that translates those virtual addresses to actual physical locations in RAM.

This gives you three powerful properties. Isolation — process A can't read process B's memory, even though they're on the same machine. Demand paging — physical memory isn't actually allocated until you touch it, which is why programs start fast even if they'd use a lot of memory eventually. And swap — when physical RAM fills up, the OS can quietly move pages that haven't been used recently out to disk, freeing space for what's actively running.

---

**IPC — how processes talk to each other.**

Processes are isolated, but sometimes they need to cooperate. The OS gives you several mechanisms for this.

Pipes are the one-directional flow you see in shell commands — pipe the output of one program into the input of another. Unix sockets give you bidirectional local communication. Shared memory is the fastest option — two processes literally map the same physical memory region. Signals are lightweight notifications, like when you hit Control-C to send SIGTERM. And message queues handle asynchronous passing.

---

**The file system.**

To your application, everything is a file. Whether it's data on an SSD, a network share, or even a device — the OS presents a uniform interface. That's the Virtual File System layer. Underneath, the actual storage could be ext4, APFS, NTFS — doesn't matter. The app talks to VFS, and VFS handles the rest.

Linux takes this further with its "everything is a file" philosophy. Hardware devices show up as file paths. Process information is readable as files. Kernel settings are files you can write to. One consistent interface for the entire system.

---

**System calls.**

This is how user space talks to the kernel. Whenever your app needs to do something privileged — open a file, create a socket, spawn a new process — it makes a system call. That triggers a context switch from user mode into kernel mode. The kernel does the work, then switches back.

That switch has overhead. It's small, but measurable. This is exactly why high-performance I/O frameworks are designed to minimize how many syscalls they make — batching work, using event loops, reducing the back-and-forth between user space and kernel space.

If you want to see what syscalls a process is making in real time, there's a tool called strace that intercepts them and prints them out. It's a brilliant way to understand what a program is actually asking the OS to do.

---

**And quickly — OS versus VMs versus containers.**

A virtual machine runs its own full kernel on top of a hypervisor. Full isolation, but real overhead and slower startup. A container is different — it's not a lightweight VM. It's an isolated process sharing the host's kernel. Linux uses cgroups to limit what resources a container can use, and namespaces to control what it can see. The result is near-native performance with fast startup.

This is also why Docker on macOS or Windows runs a Linux VM underneath. Neither of those operating systems has a Linux kernel — so containers need one imported.

---

**Three things to take away from all of this.**

First, the boot sequence is a clean handoff chain — firmware initializes hardware, the bootloader loads the kernel, the kernel takes control and never gives it back. Each layer solves one specific problem.

Second, isolation is the recurring theme. Processes are isolated from each other through virtual address spaces. User space is isolated from the kernel through mode switching and syscalls. Containers get isolation through cgroups and namespaces. The whole system is built in layers of controlled separation.

And third — understanding this chain changes how you think about performance. Context switches cost time. Syscalls cost time. Memory access patterns matter because the OS is paging behind the scenes. Once you see the OS as a pipeline instead of a black box, you can actually reason about why your code behaves the way it does.

🇹🇼 中文

按下電源鍵之後,你的程式真正開始執行之前,這台電腦到底在幹嘛?大部分人把這段時間叫做「開機」,然後就不管了。但如果你想真正理解作業系統,這段「開機到關機」的生命週期,其實是最好的切入點。

---

先定位一下作業系統在整個系統裡的角色。它是介於你的應用程式和底層硬體之間的那一層軟體。核心任務有四個:管理誰能用 CPU、隔離不同程式讓它們不會互相干擾、把底層硬體的差異抽象掉讓你不用管、然後提供一組標準介面給程式使用。沒有這一層,每個應用程式都要自己處理 CPU 排程和記憶體分配,基本上是不可能的任務。

---

**開機:從韌體開始**

電源鍵按下去,CPU 第一個跑的不是 Linux 也不是 Windows,而是燒在主機板上的韌體。現代電腦用的是 UEFI,舊機器是 BIOS。韌體先做 POST——就是自我檢查,確認 CPU、記憶體、硬碟都活著——然後找到開機磁碟,把控制權交給 Bootloader。

UEFI 比舊 BIOS 進步很多,支援超過兩 TB 的開機磁碟、圖形介面、還有 Secure Boot 安全開機機制。

**Bootloader 的工作其實很單純**,就是把 OS 核心映像檔從磁碟讀進記憶體,然後把控制權交出去。Linux 常見的是 GRUB。這幾秒鐘是從「韌體的世界」跨進「作業系統的世界」的關鍵橋樑。

---

**Kernel:作業系統的心臟**

Kernel 在特權模式下跑,可以直接存取所有硬體。它管理的東西幾乎涵蓋整個系統:行程管理、記憶體管理、檔案系統、裝置驅動、還有系統呼叫介面。

Linux 是所謂的單體核心,所有子系統在同一個記憶體空間,呼叫效率高。macOS 的 XNU 是混合核心,部分功能跑在使用者空間,換來更好的穩定性。不同設計哲學,各有取捨。

---

**行程管理**

Kernel 起來之後,系統開始建立行程。每個行程是一個獨立的執行實例,有自己的虛擬記憶體空間、開啟的檔案、行程 ID,還有至少一條執行緒。行程之間是隔離的,一個行程崩掉不會直接拖垮其他行程。

執行緒是行程裡面的執行單元,同一個行程的執行緒共享記憶體,適合需要高度協作的並行工作,但也因此需要鎖機制來避免資料競爭。

---

**CPU 排程**

一台電腦可能同時有幾十個行程在「跑」,但 CPU 核心就那幾個,排程器決定誰先執行、執行多久。現代 OS 用的是搶佔式排程,排程器可以強制中斷一個行程,把 CPU 交給別人,每次輪到的時間通常只有幾毫秒。Linux 用的 CFS——完全公平排程器——根據每個行程的虛擬執行時間來排序,確保沒有任何行程被長期餓死。

---

**記憶體管理**

每個行程看到的都是虛擬位址空間,不是真實的實體記憶體位址。OS 透過分頁機制維護對照表,把虛擬位址映射到實體記憶體。這帶來三個重要好處:行程 A 無法直接讀寫行程 B 的記憶體;記憶體頁只在真正被存取時才分配,啟動更快;當實體記憶體不夠時,OS 可以把比較少用的頁面暫時換到磁碟,騰出空間給活躍的行程——這就是 Swap。

---

**行程間通訊**

行程隔離很好,但有時候需要協作。OS 提供幾種機制:Pipe 適合父子行程之間的單向資料流,就是 shell 裡常見的管線符號;Unix Socket 適合本機行程間的雙向通訊;共享記憶體適合大量資料、效能要求高的場景;Signal 是輕量通知,像是你在終端機按 Ctrl+C 發出的 SIGTERM 或 SIGKILL。

---

**檔案系統**

對應用程式而言,所有持久化資料都透過「檔案」存取。OS 透過虛擬檔案系統 VFS 提供統一介面,底層可以是 ext4、APFS、NTFS,甚至網路檔案系統——對應用程式來說 API 都一樣。

Linux 有個很有趣的哲學:一切皆檔案。硬體裝置、行程資訊、核心設定,全部都暴露成可讀寫的檔案介面,讓 shell 工具可以用同一套 I/O API 操作幾乎所有系統資源。

---

**系統呼叫**

應用程式跑在使用者模式,無法直接碰硬體或核心資料結構。每當需要 OS 服務——讀檔、開 Socket、建行程——就要透過系統呼叫切換到 Kernel Mode。開檔、讀資料、寫資料、fork 出子行程、exec 執行新程式、exit 結束行程,這些都是經典的 syscall。

每次 syscall 都涉及使用者模式到核心模式的切換,這個開銷不小。這也是為什麼高效能 I/O 框架的設計目標之一,就是盡量減少 syscall 的次數。如果你想看某個程式到底在對 OS 要求什麼,`strace` 這個工具可以攔截並顯示所有的 syscall,除錯很好用。

---

**容器和 VM 的差別**

最後快速提一下容器和 VM 的區別,因為很多人搞混。虛擬機是有自己的 Kernel 的,靠 Hypervisor 隔離,啟動要秒到分鐘,資源開銷高。容器——像 Docker——完全不同,它們其實是共享宿主機 Kernel 的隔離行程,隔離靠的是 Linux 的 cgroups 做資源限制、namespaces 做視野隔離。所以容器啟動可以快到毫秒級,資源開銷極低。

這也解釋了為什麼 Docker 在 macOS 和 Windows 上要跑一個 Linux VM——因為那兩個系統根本沒有 Linux Kernel,容器沒辦法直接共享。

---

整理一下今天的核心脈絡。

第一,作業系統的結構有一條清晰的抽象鏈:韌體抽象硬體差異,Kernel 抽象資源競爭,VFS 抽象儲存後端,syscall 抽象特權模式切換。每一層都在解決一個明確的問題。

第二,行程是 OS 最核心的抽象單位,理解行程的隔離機制、排程邏輯、記憶體映射,就能解釋很多效能問題的根源。

第三,容器不是輕量 VM,而是共享 Kernel 的隔離行程,搞清楚這個區別,對理解雲端基礎設施非常重要。

理解這條鏈之後,下次你遇到效能瓶頸或奇怪的系統行為,就不會只是猜,而是能有根據地往正確的方向找問題。

Tags

Related Articles