Skip to main content

Running VirtualBox with an existing Windows 7 partition

At work I received a new laptop, and installed linux on it. However, I needed to continue .NET development some of the time, and Visual Studio doesn't play nicely with Wine. So I decided I would run Windows 7 from a virtual machine. This is all well and good, but I didn't want to get another license for it when I already had it installed on the hard drive! While this might be against the terms of the license (I haven't checked), technically the installed Windows 7 copy could only be run as a single instance at any given time. So with some finagling, I was able to get VirtualBox to point to the existing install of Windows 7. There are also purportedly some significant I/O speedups when using VirtualBox directly with a hard drive rather than from a file on the host system.

For reference, I installed NixOS on the laptop, but any operating system should work in a similar way (the method I took wasn't very host specific). On a slight tangent, I recommend NixOS to those who like hands-on system administration. This was my first stab at using it, and I found the ideology and organization of the operating system to be really cohesive and worthwhile. There are some things I miss (such as being able to use python pip in the usual way), but often the reason you can't just do things the traditional unix way is for reasons of system reproducibility and package isolation.

One detail that may or may not be important is that I resized the windows NTFS partition from within Windows, so it was aware of the new partition table. I don't think this should make a difference, but it wouldn't be the first time that windows failed to boot for reasons of different saved state of the hardware.

The easiest way to get VirtualBox to point to the existing partition (let's call it /dev/sda2) is to use the VirtualBox command-line tool VBoxManage. Good reference for this can be found here, but I'll summarize. We need a VirtualBox disk drive which looks like a drive with a Windows 7 MBR and appropriate partition table, but that actually uses our drive.

Making a Windows 7 MBR

First we need a 512-byte file which has a Windows 7 MBR. The ms-sys tool can be used with a device to write a valid Windows 7 MBR (you'd have to mount a file as a loopback to use it with ms-sys), but I opted to create the MBR using some documentation I found in a link a few steps off the ms-sys page. I simply mounted the windows drive (to /mnt for explanation purposes) and found the stored MBR in vdsutil.dll with the output from

$ hexdump -C /mnt/Windows/System32/vdsutil.dll

The start address was something like 0x27730, so I copied the MBR to a file with

$ dd if=/mnt/Windows/System32/vdsutil.dll of=win7.mbr bs=1 count=512 skip=161584

since 2773016 = 16158410.

However, this stored Windows 7 MBR doesn't have a partition table, or the correct label for the drive (Windows looks for this label when booting, read the MBR guide for more info). So, I copied the existing partition table and disk label from the existing MBR of the system with

$ dd if=/dev/sda of=win7.mbr bs=1 count=72 seek=440 skip=440 conv=notrunc

Note that conv=notrunc is necessary so that our existing MBR data isn't cleared by dd.

Making the VMDK drive

Now that the MBR is ready to go, we create the drive with

$ VBoxManage internalcommands createrawvmdk -file /path/to/output.vmdk 
     -rawdisk /dev/sda -partitions 2 -relative -mbr win7.mbr

Note that you might have to run this command as root, because the command looks at the partition table of /dev/sda when creating the VMDK file.

To allow Windows to access more partitions, you could give a comma-separated list of partitions to the -partitions arguments. For instance, I let windows see all partitions except the linux one (at /dev/sda4), so I actually had -partitions 1,2,3, where those correspond to /dev/sda1, /dev/sda2, and /dev/sda3. With the -relative argument, the virtual machine will only have access to those partitions, and if it tries to read from partition 4 (which is in the partition table, after all), it will just read zeros.

Making the Virtual Machine

At this point, I made a new Windows 7 Virtual Machine and selected the VMDK file I created. I configured the VM with a few of the recommended settings (such as enabling VT-x/AMD-V and the I/O APIC), and started it up. Can you guess what I saw?

Bluescreen

Naturally, a bluescreen from Windows! Have no fear though, I expected this. This is a Stop 0x7B error, indicating that Windows couldn't find the boot device. Windows does an interesting, and unnecessary, thing when installing to your computer: it looks at what drive controllers it needs, and then installs only those controllers, and disables other controllers from working. Why Windows does this is beyond me, but the problem here is that Windows does in fact see the drive, but can't load it because the drive controller installed was for the drive controller in the laptop, not the controller that VirtualBox is emulating.

Fixing the Virtual Machine

I couldn't get Windows to work with the SATA controller in VirtualBox at all, so I replaced it with an IDE controller (in the VM settings). Then, when Windows booted I chose to go into recovery mode (which worked just fine, because it's setup to run no matter what controller Windows was installed with), and made some changes to the registry.

I loaded the registry with

> reg load HKLM\Computer_System C:\Windows\system32\config\system

where the actual Windows system drive was mounted on C:\.

Then with regedit I edited each of

  • HKEY_LOCAL_MACHINE\Computer_System\ControlSet001\services\atapi\Start
  • HKEY_LOCAL_MACHINE\Computer_System\ControlSet001\services\amdide\Start
  • HKEY_LOCAL_MACHINE\Computer_System\ControlSet001\services\amdsata\Start
  • HKEY_LOCAL_MACHINE\Computer_System\ControlSet001\services\intelide\Start
  • HKEY_LOCAL_MACHINE\Computer_System\ControlSet001\services\pciide\Start

To give each a value of 0. This allows Windows to check for and possibly use each of these drivers for the drive controller (silly, right?). I may have changed a few more that I didn't write down (it took a couple tries until I got it right); basically anything with ide in the name I changed, and then a few other ones with sata or ata.

After editing the registry, I unloaded it with

> reg unload HKLM\Computer_System

A working VM

After some trial and error, I finally got Windows 7 to boot, and I have to say that it has been running really, really smoothly. I've only given it two cores and 4GB of RAM, but it seems to be running just fine. I've heard that having the virtual machine directly access the hard drive significantly decreases I/O time. I've never run a Windows 7 VM before, let alone from a VMDK that wasn't pointing to a drive, so I can't say whether this is true. But it seems just as responsive as when I ran it on the metal, and works great for my development needs. I just added a shared network drive through VirtualBox to share files between host and guest and installed the Oracle USB drivers; it basically functions as if I've booted on metal.

Comments