01 / Boot architecture

A kernel. Some RAM. The first instruction.

The direct Linux boot path skips a conventional firmware boot sequence. kube-vm prepares the environment a 64-bit Linux kernel expects, then lets KVM execute it.

From host files to guest execution

A kernel image is not a whole machine image. The loader combines a Linux bzImage, an optional initrd, a command line, and the VM's device layout into guest physical memory. The disk supplies the root filesystem; it does not have to contain a bootloader.

Direct kernel boot sequence The loader reads a bzImage and initrd, fills guest RAM with boot parameters and the kernel, configures vCPU zero, and enters Linux through KVM. Linux bzImage64-bit entry point Optional initrdearly userspace Guest RAM GDT + page tables zeropage + cmdline kernel @ 0x100000 initrd near top vCPU 0registers + long mode Linux runsKVM_RUN → guest
  1. Read the bzImage setup header, check its magic and 64-bit entry flag, and copy the protected-mode payload to guest address 0x100000.
  2. Install the GDT, initial page tables, E820 memory map and multiprocessor table. Place the command line and optional page-aligned initrd in RAM.
  3. Configure the bootstrap vCPU's segment and control registers for long mode. Its instruction pointer targets the kernel's 64-bit entry; RSI points at the zeropage.
  4. The vCPU run loop enters the guest. Linux discovers virtio-MMIO devices from command-line entries and mounts the root filesystem according to your boot arguments.
Conceptual boot order, not a timing benchmark. Select any step to freeze and inspect it.

The boot contract lives in memory

Zeropage and command line

The Linux boot-parameter structure is placed at 0x010000; the NUL-terminated command line is at 0x020000. The loader adds a virtio_mmio.device=SIZE@ADDRESS:IRQ argument for each device, followed by the configured user arguments.

A map, not just a byte count

The E820 map tells Linux which guest addresses are RAM. The x86 layout reserves the MMIO hole from 0xd0000000 to 0x100000000; large-memory VMs map additional RAM above it. Initial page tables establish the identity mapping needed to enter the kernel.

The bootstrap processor starts the rest

The Linux loader initializes vCPU 0's entry registers. The multiprocessor table describes the configured processors so the guest can bring up additional vCPUs. kube-vm supplies virtual interrupt-controller and timer state through KVM.

Choose what becomes PID 1

From the repository root, after make build, a direct initrd boot can look like this. Supply your own compatible kernel and initrd:

./bin/kube-vm -server=false \
  -kernel ./bzImage \
  -initrd ./initrd.cpio.gz \
  -mem 1024 -cpu 2 \
  -cmdline "console=hvc0 reboot=t"

An initrd normally supplies /init. For a raw ext4 root disk, attach it with -block or -cow-block and configure a root such as root=/dev/vda rw. The Docker disk chapter explains why this is vda, not vda1, for disks built by the Make target.

Kernel configuration matters. KVM runs the CPU; it does not supply missing Linux drivers. Build in virtio-MMIO, the needed virtio block/console drivers, and ext4, or make them available in an initrd. Firmware/ISO boot is a separate, experimental path—not this direct bzImage flow.

Read the implementation