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?
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