Tag Archives: Windows

Using bridged networking with KVM/QEMU guests on a Linux host

Using KVM to virtualize guest operating systems under Linux is great, but the default networking configuration doesn’t allow incoming connections to the VM. This is not peculiar to KVM – this is the default for most (all?) virtualization technologies, including VirtualBox.

If, like me, you need to access you guest VM’s from the outside, then you need to setup bridge networking. There are plenty of resources on the web on how to do this, and this blog is simply a quick overview of the steps I took to enable bridge networking under KVM. It will serve as a reminder to my self of the steps I took, and possibly help others out as well.

Below is a list of the sites I used for setting up bridged networking with KVM under Linux:

https://help.ubuntu.com/community/NetworkConnectionBridge
http://drupal.bitfunnel.net/drupal/macosx-bridge-qemu
http://en.blog.guylhem.net/post/88201449689/running-qemu-with-tap0-and-nat-under-osx-109
http://superuser.com/questions/42249/how-to-bridge-two-ethernet-ports-on-mac-os-x

In a nutshell, setting up a bridge on Linux means installing the necessary bridge software and editing the /etc/network/interfaces file, both of which are described here:

https://help.ubuntu.com/community/NetworkConnectionBridge

If you’re like me, seeing a working config file gets you a long way, so below is my /etc/network/interfaces file. For reasons not related to bridging, my network is setup as a class B network, so you will probably have to adjust the various addresses accordingly:

$ cat /etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

iface eth0 inet manual

auto br0
iface br0 inet static
    address 172.16.0.190
    network 172.16.0.0
    netmask 255.255.0.0
    broadcast 172.16.0.255
    gateway 172.16.0.1
    dns-search mydomain.com
    dns-nameservers 172.16.0.10
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0
    bridge_maxwait 0

Once bridging is setup on the Linux host, all that needs to be done is start QEMU with the correct network options, and then edit the guest network settings. The options to use for QEMU are:

-net nic,vlan=0
-net tap,vlan=0,ifname=tap0

Note that these options replace the existing QEMU network options, and are not to be used in conjunction with them.

It is these args that inform QEMU that you wish to use bridged networking.

To use bridge networking on Windows 7, add the above two arguments to your QEMU start line and then setup your network manually within Windows 7. For example, if you use this command for non-bridge networking:

qemu-system-x86_64 -enable-kvm -m 8192M -cpu host -drive file=/dev/zvol/rpool/kvm/windows7/disk0 -netdev user,id=vlan0 -net nic,model=e1000,netdev=vlan0 -smp 2

Then use this for bridged networking:

qemu-system-x86_64 -enable-kvm -m 8192M -cpu host -drive file=/dev/zvol/rpool/kvm/windows7/disk0 -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -smp 2

Note that this assumes you have previously setup bridge networking support in Linux. Also, you must run QEMU as root in order to use bridge networking.

To use bridge networking on OS X Mountain Lion, use the above two arguments for networking in your QEMU start line. For example:

qemu-system-x86_64 -enable-kvm -m 4096 -cpu core2duo -machine q35 -usb -device usb-kbd -device usb-mouse -device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -kernel ./chameleon_svn2534_boot -smbios type=2 -device ide-drive,bus=ide.2,drive=MacHDD -drive id=MacHDD,if=none,format=raw,file=/dev/zvol/rpool/kvm/mountain-lion/disk0 -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -monitor stdio -smp 2

And then setup your network manually within Mountain Lion using these commands:

sudo ifconfig bridge0 create
sudo ifconfig bridge0 addm en0
sudo ifconfig bridge0 up

These commands aren’t necessary, but may be useful if you make a mistake:

sudo ifconfig bridge0 down
sudo ifconfig bridge0 deletem en0
sudo ifconfig bridge0 destroy

To use bridge networking on OS X Mavericks, use the OS X Network utility as described in the above posts to add a bridge, making sure to add your Ethernet device (en0) to it. Then add use the two QEMU networking options above in your QEMU command-line along with the virtio driver. For example:

qemu-system-x86_64 -enable-kvm -m 4096 -cpu core2duo -machine q35 -usb -device usb-kbd -device usb-mouse -device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -kernel ./chameleon_svn2534_boot -smbios type=2 -device ide-drive,bus=ide.2,drive=MacHDD -drive id=MacHDD,if=none,format=raw,file=/dev/zvol/rpool/kvm/mavericks/disk0 -net nic,model=virtio,vlan=0 -net tap,vlan=0,ifname=tap0 -monitor stdio -smp 2

Installing Windows 7 KVM/QEMU guest onto a Linux host zvol

Though Linux is my desktop of choice, some of my programming tasks require me to run other operating systems. Rather than have multiple machines running various operating systems and/or a single machine with several boot partitions, I have in the past opted for virtualizing these other operating systems using VirtualBox under Linux. That is, until recently, when I switched from using VirtualBox to KVM/QEMU. There’s nothing wrong with VirtualBox, but for what I do, KVM made more sense. And since I’m running ZFS under Linux, using a zvol for the operating systems seemed a natural fit.

Creating a Windows 7 KVM/QEMU guest on a zvol under Linux is easy. First, create the zvol:

zfs create -p -V 60G rpool/kvm/windows7/disk0

This will create a 60GB zvol named windows7 in dataset kvm in the zpool named rpool. You can of course substitute the zpool/dataset names as you see fit.

With the zvol created, insert a copy of Windows 7 into your CD drive and create the guest:

qemu-system-x86_64 -enable-kvm -m 8192M -cpu host -drive file=/dev/zvol/rpool/kvm/windows7/disk0 -cdrom /dev/cdrom -boot d -smp 2

With any luck, qemu will start the Windows 7 installation. Just follow the instructions as you would a normal Windows installation.

Once installation is complete, you can use this command to start the Windows 7 guest:

qemu-system-x86_64 -enable-kvm -m 8192M -cpu host -drive file=/dev/zvol/rpool/kvm/windows7/disk0 -netdev user,id=vlan0 -net nic,model=e1000,netdev=vlan0 -smp 2

This will give your Windows 7 VM a network using DHCP, in which you can communicate from the VM to the outside world, but not the other way around. If you wish to be able to access your VM from the outside, you will need to use bridge networking instead, which you can read about in my future post.

That’s all there is to it!

Note that the -cpu host option is critical – if you forget it, the installation will give you the dreaded BSOD with a STOP 0x0000005D error. And to use the -cpu host option, you must also specify the -enable-kvm option.

If you’d prefer to install to an image file rather than a zvol, you can do that simply by creating the image using QEMU and then substituting the image file for the zvol:

qemu-img create -f qcow2 windows7.img 60G

qemu-system-x86_64 -enable-kvm -m 8192M -cpu host -drive file=windows7.img -cdrom /dev/cdrom -boot d -smp 2

Madness and the Minotaur for Windows

With the major x86 UNIX derivatives out of the way (Linux, BSD, OS X), it’s time to bite the bullet and work on a Windows port. Obviously, Windows is unlike any of the UNIX derivatives and so should require the most work. However, after my escapades with OS X, particularly the alignment issue, I’m beginning to think the Windows port may be easier.

As mentioned elsewhere in my blog, during the Linux port I had planned ahead for future porting work and so tried to isolate all the platform specific stuff into a file called hardware.s. Now that I’ve actually ported Madness twice, I’ve decided that platform-unix.s would be a better name than hardware.s for the UNIX derivatives, and I would create a platform-windows.s module for the Windows stuff.

The first obstacle is going to be the tool chain. I originally chose the GNU assembler for the port because I am probably one of the few people who actually likes the AT&T assembly syntax, and because it is available on many platforms. Another obvious choice would have been NASM, as it too runs on many platforms. But since it uses the Intel syntax, I chose GNU.

So how am I going to compile GNU assembly on Windows? Fortunately, Cygwin (http://www.cygwin.com) is the answer. Normally, when programming in C/C++ and using Cygwin, the machine running the binary has to have the cygwin1.dll file installed somewhere on the path, as that is needed to perform the POSIX translation. However, since I’m using assembly, no such translation is needed – a binary created with the GNU assembler under Cygwin is the same as a native binary created with the MinGW assembler (http://www.mingw.org). As a test, I removed all the platform-specific code from Madness (so that it would assemble, since I haven’t ported it yet) and assembled/linked it using the Cygwin tools. Then I used the MinGW assembler and linker to build the same code, producing a native Windows binary without Cygwin. As it turns out, the binaries are just about identical. The file size of the Cygwin version is 12-bytes more and a cmp between the two binaries shows a difference of 788 bytes. However, a comparison of an objdump of each binary shows that the generated assembly is identical. So this means I can simply use Cygwin for assembling Madness and the resulting binary will run natively on Windows without the need for cygwin1.dll. Cygwin also supports git, so I am able to perform all my git operations from a Cygwin terminal as well.

Another plus to using Cygwin is that it provides an ssh server. This means I can ssh into my Windows machine from a Linux terminal, and use make, as, ld and vi as my development tools. Since about the only file I’ll be modifying is platform-windows.s, there’s really no need to have to log in to Windows and use an IDE. Plus I think the command-line tools are much better in Linux (and hence Cygwin) than those available through the Windows command prompt. If not better, at least more familiar to me.

With the infrastructure out of the way, it’s time to start the actual porting work. The way I’ve done all the ports so far was to first port the I/O routines, output first and then input. After that, I get the game timer to work. From there, I just fill in the remaining areas of functionality. Since this plan has worked so far, I’ll take the same approach for Windows.

The first decision to make is which mechanism to use to communicate with the operating system. The Linux and BSD ports are pure assembly, making system calls for all I/O and requiring no external linkage to libraries. The OS X port is almost pure assembly, but because of an issue I had with sigaction, it currently links with the C library so it can use the sigaction() function. Hopefully I will figure out why the sigaction system call didn’t work and when I do, OS X can be pure assembly as well. The decision to use pure assembly was a conscious one, and I’d like to use pure assembly for the Windows port as well. This means using system calls on Windows.

After researching the topic of making direct system calls on Windows, it seems the consensus is “you should never do that”. Apparently, the Windows system call numbers change from version to version, and sometimes even between builds of the same version. Because of this, I couldn’t find anyone who suggested using system calls. Instead, most people say use the Win32 API, as that’s what it’s meant for. Two other options would be to use the NT API, which is a level below Win32, or use the C library. In keeping with the spirit of the UNIX ports, I’d prefer not use the C library, which leaves Win32 or the NT API. Even though the NT API is a level below Win32, most people say to use the Win32 API, as the NT API is largely undocumented and may change. So Win32 it is.

Surprisingly, the port to Windows was quite easy. Once I substituted all of the UNIX system calls with the appropriate Win32 API calls, it just worked. I simply replaced my read syscall with ReadFile and my write syscall with WriteFile. For the game timer, I used CreateTimerQueueTimer in place of sigaction and setitimer. The only snag I ran into was the kbhit-like functionality Madness has when starting and exiting. For UNIX, this wasn’t hard to do – all that had to be done was put the terminal in raw mode. For Windows, this was a nightmare. I wanted kbhit() functionality without having to link with a library to use kbhit(), since I’m trying to write in pure assembly. I tested kbhit() and it did work, but I wanted to roll my own using Win32. There are plenty of resources on the web, including MSDN, on how to do this, but none of them seemed to work for me. After spending hours of trying sample programs using the WaitForSingleObject(), GetAsyncKeyState(), GetNumberOfConsoleInputEvents() and other Win32 API calls to implement kbhit(), I took a step back and thought about why Madness needed this functionality. As it turns out, the sole reason for needing non-blocking input was so that Madness would have a way of generating a seed that could be used in its random number generator. The idea was to use the indeterminate amount of time it takes a user to “press any key to continue” as the seed for the generator. Thinking about it, I realized that such a processing loop could consume 100% of the CPU when left waiting for a key press, which is undesirable on today’s multiprocessing systems. Besides, there is a much easier way to generate a seed – the rdtsc instruction. So I removed the non-blocking input code from Madness and instead substituted it with code that blocked until one character was read. After that, I called rdtsc, took the low-order return value in eax mod 8192 (the size of the random data) and voila – I had a random number generator whose seed was based off of rdtsc rather than user input. Not only is this much cleaner and efficient, but it let me remove one of the hardest pieces of code to port – the non-blocking input routine.

With that out of the way, the rest of the Windows port fell into place, and is now finished. You can find the binaries for Windows, as well as the source code, here:

http://www.frijid.net/madness/madness.html