How I got Windows 7 to be bootable both natively and within Linux (as a VM)

I was able to get my Windows 7 install running as a VM inside of Linux, and then when I want to play games (note to my advisor: by games, I mean research!), I can boot into it natively. Furthermore, I wanted to do this from 1 hard drive (two partitions). Some commercial products can do this (I think), but I wanted to do it for free, cause I'm cheap. In retrospect, this was fairly easy. I haven't used it too much, but it seems to be working. As I write this, I'm updating some Steam games and chatting a bit.


Remember to always back up any important files (preferably an off site backup!).


I make no guarantees/warranties about whether this'll actually work for you, or whether you will not lose data/damage your computer


The way that I do this requires root privileges, as we're doing some risky things with the hard drive.


With my previous attempts to get Windows 7 to boot in a VM and bootable outside the VM, I kept getting blue screens with an error code of 0x7E (which is related to not being able to read the storage media). These steps fixed that problem for me.


Side note: this 'solution' may require Intel VT-X or AMD-V process (hardware based virtualization support). Here's a simple way to check for this. I am merely documenting how I was able to get Windows 7 to be bootable both in a VM and natively. It may not be the best way. Some steps may not be necessary, but I really don't feel like redoing things and finding out if any steps are not necessary.

  1. Install Windows onto a hard drive partition
  2. Install Linux on another hard drive partition (hopefully Grub detects your Win 7 install)
  3. Confirm that you can switch between them by restarting your computer and using Grub's menu
  4. Update Windows 7
  5. Make sure you do NOT install any extra software that lets your Windows 7 install read your Linux file systems. Bad things can come about if two OSes are using the same partition at the same time.
  6. Now go to http://www.boot-land.net/forums/index.php?showtopic=9196 and download the usbbootfix.bat script and the storagebootstart.bat script. Save them to your Windows partition (either by mounting the partition in Linux, or just boot into Windows to do this step). For posterity, I'm mirrored them here (usbbootfix) and here (storagebootstart). I honestly do not know if both are needed. I suspect only the second is needed.
  7. Boot into Windows and start up a command prompt as administrator (Start, Accessories, right click Command Prompt and choose Run as Admin). Navigate to where you saved those .bat files and run first usbbootfix.bat then StorageBootStart.bat.
  8. Hopefully you won't see any errors.
  9. Restart your computer at least twice (for good measure), booting into Windows each time. It should still be working. The usbbootfix.bat, I believe, schedules to run something on the next boot up, so, you should let it do its thing. According to where I got those scripts, they may slightly increase your native boot time because it'll cause Windows to load some extra drivers.
  10. In Linux, install KVM and python-virtinstall (I'm using Ubuntu 9.10)
  11. Find out which hard drive your Windows 7 install is on (e.g., /dev/sda).
  12. Recommended: Setup Grub to NOT automatically boot into one of your operating systems. You do NOT want to accidentally boot into your Ubuntu install while you're running your Ubuntu install.
  13. I wrote a bash script to startup my Windows 7 install:

#!/bin/bash

 sudo virt-install -r 2000 --vcpus=2 --os-type=windows --import --disk path=/dev/sda,bus=ide,sparse=false --name Win7-Dual-Boot --sdl --accelerate -v
 


You may have to change a few things:

  • Where it says "-r 2000" that's how much RAM to give to Windows 7. I'm giving it 2GB. You may want to give it more or less. Windows loves RAM, so don't be skimpy.
  • Where it says "–vcpus=2" that's how many CPUs to give to Windows 7. You do not have to give Windows as many CPUs as it would have when you natively boot into it.
  • The "–import" means to just try to boot the hard drive (i.e., don't try to install anything as we've already installed things).
  • You should point the disk path option ("path=/dev/sda") to be the hard drive you're using (i.e., the hard drive that has your Linux partition and your Windows 7 partition on it). Because you'll be accessing the hard drive directly, you'll (as we'll soon see) need to run the VM as root.
  • The "–name" part doesn't matter.
  • The "–accelerate" tries to make use of some kernel extension (KVM or KQEMU) in order to increase performance. Even so, my Windows 7 VM is rather slow but its fast enough to do what I need it to do (keep games updated via the Internet, and perform automated backups). If you don't have hardware virtualization, you will have to get rid of the "-v" argument.
  • Optionally: You can add the "–sound" argument. But, it caused my machine's sound to skip/crackle a lot in Linux.


If you run the script you should hopefully see your normal Grub menu. Then, be sure to select Windows 7/the Windows boot loader entry from the list. Things might hopefully work. I did get a blue screen once (seemingly related to graphics drivers) but after a restart of the VM (see below) I was able to login to the VM.

Restarting Your Host Machine

I'm not KVM expert, so maybe this is overkill, but each time I want to leave Linux, I explicitly shutdown and kill the VM. After all, all of its data is saved on the hard drive. To see how I kill the VM, see the script below.


If your Windows 7 VM Blue Screens

If your Windows 7 VM blue screens, I use a script like the following to shut it down. It's a bit stupid, but it works.


Be sure to set the VM= line to use whatever name you used in your virt-install command.

 #!/bin/bash
 VM='Win7-Dual-Boot'
 #ask the VM to shutdown nicely (if it hasn't blue screened, it probably will comply)
 sudo virsh shutdown $VM 
 #Give it 60 seconds to comply
 echo Sleeping for 60s...
 sleep 60
 #Rip the power cord away from the VM
 sudo virsh destroy $VM
 #Remove the VM configuration from the system
 sudo virsh undefine $VM