From 392c371a9dceb907abdc84ac46ed5b0b80e713cc Mon Sep 17 00:00:00 2001
From: Nikos Skalkotos <skalkoto@grnet.gr>
Date: Fri, 27 Jun 2014 17:07:19 +0300
Subject: [PATCH] windows: Support WIN8 virtio driver installation

Support installing virtio drivers in Windows 8, 8.1, 2012 and 2012R2
---
 image_creator/os_type/windows/__init__.py   | 42 ++++++++++++++++-----
 image_creator/os_type/windows/powershell.py | 11 +++++-
 image_creator/os_type/windows/vm.py         | 16 ++++++--
 3 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py
index d02f33a..377694b 100644
--- a/image_creator/os_type/windows/__init__.py
+++ b/image_creator/os_type/windows/__init__.py
@@ -23,7 +23,7 @@ from image_creator.util import FatalError
 from image_creator.os_type.windows.vm import VM
 from image_creator.os_type.windows.registry import Registry
 from image_creator.os_type.windows.winexe import WinEXE
-from image_creator.os_type.windows.powershell import DRVINST
+from image_creator.os_type.windows.powershell import DRVINST, SAFEBOOT
 
 import tempfile
 import random
@@ -611,14 +611,23 @@ class Windows(OSBase):
             admin = self.sysprep_params['admin'].value
             v_val = self.registry.reset_passwd(admin)
             self.registry.enable_autologon(admin)
-
-            self._install_viostor_driver(dirname)
             self._upload_virtio_drivers(dirname)
 
+            drvs_install = DRVINST.replace('\n', '\r\n')
+
+            if self.check_version(6, 1) <= 0:
+                self._install_viostor_driver(dirname)
+            else:
+                # In newer windows, in order to reduce the boot process the
+                # boot drivers are cached. To be able to boot with viostor, we
+                # need to reboot in safe mode.
+                drvs_install += SAFEBOOT.replace('\n', '\r\n')
+
+            drvs_install += "\r\nshutdown /s /t 0\r\n"
+
             remotedir = self.image.g.case_sensitive_path("%s/VirtIO" %
                                                          self.systemroot)
-            self.image.g.write(remotedir + "/InstallDrivers.ps1",
-                               DRVINST.replace('\n', '\r\n'))
+            self.image.g.write(remotedir + "/InstallDrivers.ps1", drvs_install)
 
             cmd = (
                 '%(drive)s:%(root)s\\System32\\WindowsPowerShell\\v1.0\\'
@@ -628,18 +637,32 @@ class Windows(OSBase):
                 {'root': self.systemroot.replace('/', '\\'),
                  'drive': self.systemdrive})
 
-            self.registry.runonce({'InstallDrivers': cmd})
+            # The value name of RunOnce keys can be prefixed with an asterisk
+            # (*) to force the program to run even in Safe mode.
+            self.registry.runonce({'*InstallDrivers': cmd})
 
         try:
-            self.vm.start()
+            if self.check_version(6, 1) <= 0:
+                self.vm.start()
+            else:
+                self.vm.interface = 'ide'
+                self.vm.start(extra_disk=('/dev/null', 'virtio'))
+                self.vm.interface = 'virtio'
+
             self.out.success("started (console on VNC display: %d)" %
                                  self.vm.display)
         finally:
             self.vm.stop(6000)
 
-            with self.mount(readonly=True, silent=True):
-                self.virtio_state = self._virtio_state()
+        if self.check_version(6, 1) > 0:
+            # Hopefully restart in safe mode.
+            try:
+                self.vm.start()
+            finally:
+                self.vm.stop(6000)
 
+        with self.mount(readonly=True, silent=True):
+            self.virtio_state = self._virtio_state()
 
     def _install_viostor_driver(self, dirname):
         """Quick and dirty installation of the VirtIO SCSI controller driver.
@@ -665,7 +688,6 @@ class Windows(OSBase):
 
         self.registry.add_viostor()
 
-
     def _upload_virtio_drivers(self, dirname):
         """Install the virtio drivers to the media"""
 
diff --git a/image_creator/os_type/windows/powershell.py b/image_creator/os_type/windows/powershell.py
index 4454cbd..958b6f2 100644
--- a/image_creator/os_type/windows/powershell.py
+++ b/image_creator/os_type/windows/powershell.py
@@ -18,6 +18,7 @@
 """This module hosts Windows PowerShell scripts that need to be injected into
 the windows image"""
 
+# Installs drivers found in a directory
 DRVINST = r"""
 #requires -version 2
 
@@ -41,7 +42,15 @@ if (Test-Path "$dirName/viostor.inf") {
 
 pnputil.exe -a "$dirname\*.inf"
 
-shutdown /s /t 5
 """
 
+# Reboots system in safe mode
+SAFEBOOT = r"""
+bcdedit /set safeboot minimal
+New-ItemProperty `
+    -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce `
+    -Name *snf-image-creator-restart -PropertyType String `
+    -Value 'cmd /q /c "bcdedit /deletevalue safeboot & shutdown /s /t 0"'
+
+"""
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
diff --git a/image_creator/os_type/windows/vm.py b/image_creator/os_type/windows/vm.py
index aebd016..7e3fd44 100644
--- a/image_creator/os_type/windows/vm.py
+++ b/image_creator/os_type/windows/vm.py
@@ -36,6 +36,7 @@ class VM(object):
 
         self.disk = disk
         self.params = params
+        self.interface = 'virtio'
 
         kvm, needed_args = get_kvm_binary()
         if kvm is None:
@@ -93,7 +94,7 @@ class VM(object):
         """Check if the VM is alive"""
         return self.process is not None and self.process.poll() is None
 
-    def start(self):
+    def start(self, **kwargs):
         """Start the windows VM"""
 
         args = []
@@ -105,12 +106,19 @@ class VM(object):
         if 'mem' in self.params:
             args.extend(['-m', str(self.params['mem'].value)])
 
-        args.extend([
-            '-drive', 'file=%s,format=raw,cache=unsafe,if=virtio' % self.disk])
+        args.extend(['-drive',
+                     'file=%s,format=raw,cache=unsafe,if=%s' %
+                     (self.disk, self.interface)])
 
         args.extend(
             ['-netdev', 'type=user,hostfwd=tcp::445-:445,id=netdev0',
-             '-device', 'virtio-net-pci,mac=%s,netdev=netdev0' % self.mac])
+             '-device', 'rtl8139,mac=%s,netdev=netdev0' % self.mac])
+
+        if 'extra_disk' in kwargs:
+            fname, iftype = kwargs['extra_disk']
+            args.extend(['-drive',
+                         'file=%s,format=raw,cache=unsafe,if=%s' %
+                         (fname, iftype)])
 
         args.extend(['-vnc', ":%d" % self.display])
 
-- 
GitLab