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
# 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
$ 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 --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
$ 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
$ 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
$ 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.
Top comments (0)