Build & Run Linux Kernel

1. Build Kernel

Set up a docker container with essential packages installed.

  
FROM ubuntu:22.04

RUN apt update
RUN apt install -y libncurses-dev make git exuberant-ctags bc libssl-dev
RUN apt install -y flex bison libelf-dev build-essential
RUN apt install -y cpio unzip rsync vim wget file xz-utils

CMD ["/bin/bash"]
  
  
$ docker build --tag kernel_builder .
  
  
$ mkdir /root/kernel
$ docker run -it -v /root/kernel:/root/kernel --name kbuilder kernel_builder
  
  
$ cd /root/kernel
$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.186.tar.xz
$ tar xf linux-5.15.186.tar.xz
  
  
$ docker exec -it kbuilder bash

$ cd /root/kernel/linux-5.15.186
$ make defconfig
$ make -j `nproc`
  
  
BUILD   arch/x86/boot/bzImage
Kernel: arch/x86/boot/bzImage is ready  (#1)
  
  
$ qemu-system-x86_64 -boot order=c -m 2048M \
    -kernel /root/kernel/linux-5.15.186/arch/x86/boot/bzImage \    
    -append "root=/dev/sda rw console=ttyS0,115200 nokaslr" \
    -nographic
  

2. Build Filesystem Image

  
$ cd /root/kernel
$ wget https://buildroot.org/downloads/buildroot-2025.05.tar.gz
$ tar xf buildroot-2025.05.tar.gz
  
  
$ cd buildroot-2025.05
$ make defconfig
  
  
$ make menuconfig
  
  
$ export FORCE_UNSAFE_CONFIGURE=1
$ make -j `nproc`
  
  
$ qemu-system-x86_64 -boot order=c -m 2048M \
    -kernel /root/kernel/linux-5.15.186/arch/x86/boot/bzImage \
    -hda /root/kernel/buildroot-2025.05/output/images/rootfs.ext2 \
    -append "root=/dev/sda rw console=ttyS0,115200 nokaslr" \
    -nographic
  

3. Hello World Program

Build the program on the host, then copy it to the QEMU VM and run it there.

File: hello.c

  
#include <stdio.h>

int main() {
    printf("Hello, Linux kernel on QEMU!\n");
    return 0;
}
  

The Linux kernel does not provide the C standard library (libc.so.6) or the dynamic linker (ld-linux.so), as they belong to user space. To run program in a minimal kernel setup without these components, static linking is used to bundle all dependencies into a single self-contained binary.

  
$ gcc -static -o hello hello.c
  

On the host, copy the program into the filesystem that the QEMU VM boots from.

  
$ mkdir /mnt/rootfs
$ mount /root/kernel/buildroot-2025.05/output/images/rootfs.ext2 /mnt/rootfs/

$ cp hello /mnt/rootfs/opt
  

Restart QEMU VM.

  
$ qemu-system-x86_64 -boot order=c -m 2048M \
    -kernel /root/kernel/linux-5.15.186/arch/x86/boot/bzImage \
    -hda /root/kernel/buildroot-2025.05/output/images/rootfs.ext2 \
    -append "root=/dev/sda rw console=ttyS0,115200 nokaslr" \
    -nographic
  

Run the program on QEMU VM.

  
$ /opt/demo
Hello, Linux kernel on QEMU!