Fast Linux Kernel Testing with QEMU
I’m currently reading Linux Kernel Development. To really understand the book, you have to modify, compile, and install new kernels. One way to do this is to update the kernel on the machine you are developing on. This method seems…scary and dangerous. Sweeping the rug out from under my Ubuntu installation seems wrought with peril.
A safer way is to build and run the Linux kernel inside of a simulated sandbox. The steps in this post will show you how to get your kernel running in a lightweight environment (Qemu) that boots in seconds, with no chance of corrupting your development machine installation.
Install required build tools on host machine
Fedora
sudo dnf install ncurses-devel kernel-devel kernel-headers openssl-devel
sudo dnf install gcc gcc-c++ glibc-static
sudo dnf install git
sudo dnf install qemu
Ubuntu
sudo apt install ncurses-dev build-essential libssl-dev libelf-dev
sudo apt install git
sudo apt install qemu
Prepare a working space for kernel development
cd $HOME
mkdir kdev
TOP=$HOME/kdev
Download source code
Download stable busybox, which will provide a basic set of tools for the kernel-under-test:
wget http://busybox.net/downloads/busybox-1.24.2.tar.bz2
tar xvf busybox-1.24.2.tar.bz2
rm busybox-1.24.2.tar.bz2
Clone Linux kernel:
git clone https://github.com/torvalds/linux.git
Configure busybox
cd $TOP/busybox-1.24.2
mkdir -p $TOP/build/busybox-x86
make O=$TOP/build/busybox-x86 defconfig
make O=$TOP/build/busybox-x86 menuconfig
Enable building BusyBox as a static binary:
> Busybox Settings
> Build Options
[*] Build BusyBox as a static binary (no shared libs)
Build and install busybox (local install, no sudo required)
cd $TOP/build/busybox-x86
make -j2
make install
Create minimal filesystem
mkdir -p $TOP/build/initramfs/busybox-x86
cd $TOP/build/initramfs/busybox-x86
mkdir -pv {bin,sbin,etc,proc,sys,usr}
cp -av $TOP/build/busybox-x86/_install/*.
Create simple init script
Create a file called init
with the following contents:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
exec /bin/sh</code></pre>
Make it executable:
chmod +x init
Generate initramfs
find . -print0 \
| cpio --null -ov --format=newc \
| gzip -9 > $TOP/build/initramfs-busybox-x86.cpio.gz
Configure Linux using simple defconfig and kvm options
cd $TOP/linux
make O=$TOP/build/linux-x86-basic x86_64_defconfig
make O=$TOP/build/linux-x86-basic kvmconfig
Build Linux
make O=$TOP/build/linux-x86-basic -j2
Boot with Qemu in seconds!
cd $TOP
qemu-system-x86_64 \
-kernel build/linux-x86-basic/arch/x86_64/boot/bzImage \
-initrd build/initramfs-busybox-x86.cpio.gz \
-nographic -append "console=ttyS0" \
-enable-kvm
If all goes well, this will boot the kernel and drop you into a prompt where you can start interacting with your minimal busybox system.
If you want to exit Qemu, use Ctrl-A X
.