Linux Kernel: Is It Really Just a Program?

Through hands-on QEMU experiments, the author demonstrates that the Linux kernel is simply an executable file — demystifying it by booting a bare kernel, then providing it with a custom Go-based init process.

Many people treat the Linux kernel as some kind of mystical black box — incomprehensible magic happening deep inside the computer. But what if I told you it's just an executable file that can be launched like any other program? Let's prove it with experiments.

A Brief Word About the "Brain"

The kernel is a mediator between hardware and software. It provides three key functions:

  • A unified API for hardware communication — applications don't talk to devices directly; they ask the kernel, which translates requests through drivers.
  • Process scheduling and resource allocation — the kernel decides which process gets CPU time, how much memory each gets, and who accesses which devices.
  • Runtime for the entire computer — without the kernel, nothing runs. It's the first thing that starts and the last thing that stops.

Where to Find It

The kernel file typically lives in the /boot directory:

~$ cd /boot
/boot$ ls -1
System.map-6.12.48+deb13-amd64
vmlinuz-6.12.48+deb13-amd64   # Here it is!

The filename breaks down as: vm (virtual memory support) + linu (Linux) + z (compressed with gzip). It's just a file. You can copy it, move it, examine it. There's nothing magical about it.

Experiment 1: Bare-Bones Launch

Let's copy the kernel and try to boot it in a virtual machine using QEMU:

~$ mkdir kernel-play
~$ cd kernel-play/
~/kernel-play$ cp /boot/vmlinuz-6.12.48+deb13-amd64 .

Install QEMU if you don't have it:

~$ sudo apt update
~$ sudo apt install -y qemu-system-x86 qemu-utils

Now launch the kernel:

~/kernel-play$ qemu-system-x86_64 \
  -m 256M \
  -kernel vmlinuz-6.12.48+deb13-amd64 \
  -append "console=ttyS0" \
  -nographic

The kernel initializes successfully — it detects (virtual) hardware, sets up memory management, initializes subsystems. Then it panics:

[ 2.181875] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

This is actually a success. The kernel did everything it could — it booted, initialized all its subsystems, and then looked for the next step: a root filesystem and an init process to hand control to. It found neither, so it panicked. This proves the kernel is just a program that needs something to run after it finishes its own initialization.

Experiment 2: Giving the Kernel Its First Program

The kernel needs an init process — the very first userspace program, which always gets PID 1. Let's write a minimal one in Go that just prints a greeting and ticks every few seconds:

~/kernel-play$ mkdir init && cd init
~/kernel-play/init$ CGO_ENABLED=0 go build -o init .

The CGO_ENABLED=0 flag is critical — it produces a fully static binary with no external dependencies, which is essential since our minimal filesystem won't have any shared libraries.

Now we need to package this into an initramfs — an initial RAM filesystem that the kernel loads into memory at boot:

~/kernel-play$ mkdir -p rootfs/{proc,sys,dev}
~/kernel-play$ cp ./init/init rootfs/init
~/kernel-play$ sudo mknod rootfs/dev/console c 5 1

Package it into a cpio archive:

~/kernel-play$ ( cd rootfs && find . | cpio -H newc -o ) > initramfs.img

Now launch with our filesystem:

~/kernel-play$ qemu-system-x86_64 \
  -m 256M \
  -kernel vmlinuz-6.12.48+deb13-amd64 \
  -initrd initramfs.img \
  -append "console=ttyS0 rdinit=/init" \
  -nographic

And it works:

...
[ 2.672446] Run /init as init process
Hello from Go init!
PID: 1
tick 0
tick 1
...

Our Go binary received PID 1 and is running as the init process. The kernel successfully handed control to userspace.

What We've Proven

These two simple experiments establish four critical concepts:

  • The kernel is executable code — it can be loaded and run like any other binary. There's no magic, just software.
  • A Linux distribution = kernel + utilities + configuration — Ubuntu, Debian, Arch — they all use the same kernel. The difference is which packages, init system, and configurations ship alongside it.
  • PID 1 is the boundary — the init process (PID 1) is always the first userspace process. It's responsible for launching everything else — services, login prompts, desktop environments. In modern systems, this is usually systemd.
  • Kernel space vs. user space — the kernel runs in a privileged mode with direct hardware access. Once it launches init, it transitions to serving requests from userspace processes through system calls. This boundary is fundamental to Linux security and stability.

Understanding Linux doesn't require treating the kernel as an incomprehensible black box. It's a program. A complex, powerful, brilliantly designed program — but a program nonetheless. And as we've shown, you can boot it on your laptop in under five minutes.