Sunday, May 10, 2015

Preparing a test VM - QEMU

We have our kernel and our filesystem. Now we need to utilize virtualization to run our OS.

I will not talk about how virtualization or emulation works. However you need to know a few details.

When IT people think what virtualization technology is all about, they often think how host CPUs are shared between VMs and how various memory tricks work, like ballooning or taking memory snapshots. After that storage or network infrastructure and configuration comes to mind. And of course, live migration, which looks like pure magic the first time you see it work (if you have a cluster of hosts)

For kernel development we are interested in different kind of stuff. Most of the time we need only one machine with fixed amount of memory, fixed amount of disk space and just one virtual CPU.

First I will introduce the full command-line to invoke QEMU:

sudo qemu-system-x86_64 -M pc -m 512M -smp 1\
-enable-kvm -cpu host \
-kernel your-kernel-dir/arch/x86/boot/bzImage \
-append "root=/dev/vda console=ttyS0,115200n8" \
-drive file=root.disk,if=virtio \
-net nic,model=e1000 -net tap,name=vif0,script=no,downscript=no \
-nographic

Now let's go line by line and see what may be of interest to us.

  • sudo qemu-system-x86_64: We are going to utilize an x86_64 cpu. You can use other architectures supported by QEMU via emulation as well but I plan to stick with x86_64 PC emulation in my tutorials for now. sudo part is needed to create network devices in host side.
  • -M pc: Basically the board we will use. When pc is selected, we are using an emulation of a motherboard chipset from 90's called i440fx. One can also use q35 parameter instead (which is a chipset from 2000's). pc is enough for us, you need to know that you can only use old PCI technology with it. I can write more about this some time later.
  • -m 512M -smp 1: The memory amount which will be directly allocated and cpu count. You can look at QEMU User Documentation on how to use multiple CPUs (as SMP of course). One may need to test on multiple CPUs to better investigate how concurrency works in a driver.
  • -enable-kvm -cpu host: Use host cpu with kvm virtualization. If we specify a CPU arch other than our host's then we use QEMU emulation (which is way slower than kvm)
  • -kernel .../bzImage -append ...options...: Boot using this kernel bzImage with these options passed to its command line. You need to use quotes if you are going to pass multiple cmdline options to the kernel. Here I tell the kernel that root disk will be the first virtio disk and to use serial console to output kernel messages. Also note that we are using the image under arch/x86 since our virtual machine is running on an Intel or AMD CPU.
  • -drive file=disk-file,if=if-type: You'd better read the QEMU documentation for all the interesting options. But only specifying a disk file and telling QEMU to present that file via virtio is enough for beginning.
  • -net nic,model=eth-if -net tap,name=ifname: We can add as many virtual interfaces as we want using this line. The -net nic part tells QEMU to represent a network interface of given model to our VM. -net tap part tells to create a tap interface in host side of the virtual ethernet cable between the host and VM. name is the name of the tap device to be created in host. You need to set script and downscript to "no" or else QEMU may use its pre-defined scripts every time the interface goes up and down. You can also use your own scripts. Read the documentation for other interesting networking scenarios some of which you will never be able to get to work :)
  • -nographic means do not emulate a video card. Other option is "-vga std" to emulate an old Cirrus Logic VGA card. You can try logging to both serial console and the emulated monitor. (You need to change append parameter to include console=tty0 to let kernel to print logs on the screen. Also you'll need to add serial port options to QEMU command)

I need to put a warning about serial console access. While I was trying to figure out how to use serial port in QEMU, I accidentally passed "/dev/ttyS0" to kernel and struggled to make it work for hours. There are many different combinations to use with QEMU serial port but really, just pass ttyS0,115200n8 to kernel and use the default serial port QEMU provides for beginning.

When you hit enter in the command-line your kernel messages need to be flowing if you managed to compile the kernel correctly. There are some basic mistakes which may prevent your kernel from booting but unfortunately I don't have the time to prepare an FAQ now. So you'll need to Google whatever error message you are getting.

If you did everything I told you in these series of articles you need to be able to login to your VM which you will be running your kernel level code.

Finally a few notes about QEMU console. When you start the VM with above command QEMU will start outputting the serial console content to your terminal. If you want to access QEMU console you need to press Ctrl+a and then c. You can type ? in QEMU console to see commands you can issue on-the-fly. Press Ctrl+a and c again to switch back to serial console. To quit QEMU immediately you can press Ctrl+a and then x.

In the next and final article I will show you how to write a simple module which prints "Hello, world!" when it is loaded (there are so many kernel development tutorials which does that. My point is to show you how to develop and run your code in the VM.) And I will talk about network configuration to upload our kernel modules to the VM and to access internet from within the VM (if we ever need that for some reason).

I will share all the VM start and network scripts I use for QEMU setup over GitHub.

No comments:

Post a Comment