Test Kernel changes on QEMU
Tags: linux, kernel, qemu, testing
Published: 2022-04-23 13:26:52


This is all about testing Linux kernel changes on a QEMU virtual machine in cycles of _build, install and run_ shortest than 5 minutes.

The Internet is full of tutorials about building the Linux Kernel, yet I found less content about _applying the changes_ to a virtualized environment, so that will be the goal of this post.

## Running QEMU virtual image

Also this content is quite common, so I will be short

```shell
# Create the disk: a qcow2 format image of 2G
$ qemu-img create -f qcow2 alpine.img 2G

# Download a live CD ISO image (e.g. Ubuntu, Alpine, whatever), then run the live image and install
# it into the disk created above.
$ qemu-system-x86_64 -cdrom alpine-downloaded.iso alpine.img -m 512M -enable-kvm

# Run the newly installed image from the disk
$ qemu-system-x86_64 -enable-kvm -m 512M -smp 4 -cpu host -drive file=alpine.img
```

## Running QEMU with a custom kernel

You downloaded and built the Linux Kernel under `~/workspace/linux`, that is you know have a `/linux/arch/x86_64/boot/bzImage`, the command to run it in QEMU is

```bash
$ qemu-system-x86_64 \
        -enable-kvm -m 512M -smp 4 -cpu host \
        -kernel ~/workspace/linux/arch/x86_64/boot/bzImage \
        -append "root=/dev/sda3 console=ttyS0 rw" \
        -drive file=alpine.img
```

## Make a change and test it

Consider now you made a change to the kernel. Any change, maybe even so silly like the one below

```diff
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e7755d9cf..534e8051e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2138,7 +2138,7 @@ static struct usb_serial_driver option_1port_device = {
 		.owner =	THIS_MODULE,
 		.name =		"option1",
 	},
-	.description       = "GSM modem (1-port)",
+	.description       = "it's me, Mario!",
 	.id_table          = option_ids,
 	.num_ports         = 1,
 	.probe             = option_probe,
```
How do you test it on your QEMU VM?

First, mount the VM image on the host

```bash
$ mkdir /tmp/alpine
$ guestmount --add alpine.img --root /dev/sda3 /tmp/alpine
$ ls /tmp/alpine
bin   dev  home  lost+found  mnt  proc  run   srv   sys  usr
boot  etc  lib   media       opt  root  sbin  swap  tmp  var
```

Second and last, during the build, tell the kernel to install the modules inside the mounted image
```bash
$ make -j$(nproc)
...
$ make -j$(nproc) modules
$ INSTALL_MOD_PATH=/tmp/alpine make modules_install
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/drivers/thermal/intel/x86_pkg_temp_thermal.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/drivers/usb/serial/option.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/drivers/usb/serial/usb-serial-simple.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/drivers/usb/serial/usb_wwan.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/drivers/usb/serial/usbserial.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/fs/efivarfs/efivarfs.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/ipv4/netfilter/iptable_nat.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/nf_log_syslog.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/xt_LOG.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/xt_MASQUERADE.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/xt_addrtype.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/xt_mark.ko
INSTALL /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty/kernel/net/netfilter/xt_nat.ko
DEPMOD  /tmp/alpine/lib/modules/5.18.0-rc2-custom-ga1901b464e7e-dirty
```

**don't forget to UNMOUNT the image**
```bash
$ umount /tmp/alpine
```

Run again your kernel, the change (at least the one above) will be visible loading "option" module.

## Final words
This process is so fast that one can test changes to the kernel in few seconds, moreover you are going to have a wide range of debug features provided by QEMU and, not less important, your machine is preserved.