Merge remote branch 'cros/upstream' into tempbranch2

Merged to trunk@4816.

BUG=
TEST=we will build a new autotest server instance, and keep cautotest running and then later do a cname switch.

Review URL: http://codereview.chromium.org/3511003

Change-Id: Iee5f52f45f28f84927d6c6f9a74edc370d40288a
diff --git a/client/tests/aio_dio_bugs/aio_dio_bugs.py b/client/tests/aio_dio_bugs/aio_dio_bugs.py
index 41ea0b9..4324111 100644
--- a/client/tests/aio_dio_bugs/aio_dio_bugs.py
+++ b/client/tests/aio_dio_bugs/aio_dio_bugs.py
@@ -26,7 +26,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make ' + '"CFLAGS=' + self.gcc_flags + '"')
+        utils.make('"CFLAGS=' + self.gcc_flags + '"')
 
 
     def execute(self, args = ''):
diff --git a/client/tests/bash_shared_mapping/bash_shared_mapping.py b/client/tests/bash_shared_mapping/bash_shared_mapping.py
index 40c0df2..e8f604f 100644
--- a/client/tests/bash_shared_mapping/bash_shared_mapping.py
+++ b/client/tests/bash_shared_mapping/bash_shared_mapping.py
@@ -10,7 +10,7 @@
         utils.extract_tarball_to_dir(self.tarball, self.srcdir)
 
         os.chdir(self.srcdir)
-        utils.system('make bash-shared-mapping usemem')
+        utils.make('bash-shared-mapping usemem')
 
 
     def initialize(self):
diff --git a/client/tests/bonnie/bonnie.py b/client/tests/bonnie/bonnie.py
index af58b4c..e7f4917 100644
--- a/client/tests/bonnie/bonnie.py
+++ b/client/tests/bonnie/bonnie.py
@@ -38,8 +38,8 @@
 
         os_dep.command('g++')
         utils.system('patch -p1 < ../bonnie++-1.03a-gcc43.patch')
-        utils.system('./configure')
-        utils.system('make')
+        utils.configure()
+        utils.make()
 
 
     def run_once(self, dir=None, extra_args='', user='root'):
diff --git a/client/tests/cerberus/cerberus.py b/client/tests/cerberus/cerberus.py
index c8a0b19..64ad916 100644
--- a/client/tests/cerberus/cerberus.py
+++ b/client/tests/cerberus/cerberus.py
@@ -53,7 +53,7 @@
             p2 = 'patch -p1 < ../0002-Fix-CTCS2-build-in-64-bit-boxes.patch'
             utils.system(p2)
 
-        utils.system('make')
+        utils.make()
 
         # Here we define the cerberus suite control file that will be used.
         # It will be kept on the debug directory for further analysis.
diff --git a/client/tests/cyclictest/cyclictest.py b/client/tests/cyclictest/cyclictest.py
index a4399d5..8e1b40d 100644
--- a/client/tests/cyclictest/cyclictest.py
+++ b/client/tests/cyclictest/cyclictest.py
@@ -14,7 +14,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def execute(self, args = '-t 10 -l 100000'):
diff --git a/client/tests/dbt2/dbt2.py b/client/tests/dbt2/dbt2.py
index 9f341ef..5a74262 100644
--- a/client/tests/dbt2/dbt2.py
+++ b/client/tests/dbt2/dbt2.py
@@ -23,18 +23,16 @@
         #
         utils.system('cp -pR ' + self.srcdir + ' ' + self.srcdir + '.mysql')
         os.chdir(self.srcdir + '.mysql')
-        utils.system('./configure --with-mysql=%s/deps/mysql/mysql' \
-                        % self.autodir)
-        utils.system('make')
+        utils.configure('--with-mysql=%s/deps/mysql/mysql' % self.autodir)
+        utils.make()
 
         #
         # Extract one copy of the kit for PostgreSQL.
         #
         utils.system('cp -pR ' + self.srcdir + ' ' + self.srcdir + '.pgsql')
         os.chdir(self.srcdir + '.pgsql')
-        utils.system('./configure --with-postgresql=%s/deps/pgsql/pgsql' \
-                        % self.autodir)
-        utils.system('make')
+        utils.configure('--with-postgresql=%s/deps/pgsql/pgsql' % self.autodir)
+        utils.make()
 
         # Create symlinks to autotest's results directory from dbt-2's
         # preferred results directory to self.resultsdir
diff --git a/client/tests/ebizzy/ebizzy.py b/client/tests/ebizzy/ebizzy.py
index a594e39..50d6473 100644
--- a/client/tests/ebizzy/ebizzy.py
+++ b/client/tests/ebizzy/ebizzy.py
@@ -16,7 +16,7 @@
         os.chdir(self.srcdir)
 
         utils.system('[ -x configure ] && ./configure')
-        utils.system('make')
+        utils.make()
 
 
     # Note: default we use always mmap()
diff --git a/client/tests/flail/control b/client/tests/flail/control
new file mode 100644
index 0000000..82a27bd
--- /dev/null
+++ b/client/tests/flail/control
@@ -0,0 +1,17 @@
+AUTHOR = "Pradeep Kumar Surisetty <psuriset@linux.vnet.ibm.com>"
+NAME = "flail"
+TEST_CATEGORY = "Stress"
+TEST_CLASS = "General"
+TEST_TYPE = "client"
+TIME = 'MEDIUM'
+EXPERIMENTAL = "True"
+
+DOC='''
+flail is a  systemcall fuzzer tool. This test simply runs flail.
+Fuzzing is slang for fault injection . It runs all system calls
+for that kernel version with random args.
+The goal is to find bugs in software without reading code or
+designing detailed test cases.
+'''
+
+job.run_test('flail')
diff --git a/client/tests/flail/flail-0.2.0.tar.gz b/client/tests/flail/flail-0.2.0.tar.gz
new file mode 100644
index 0000000..a95c5a4
--- /dev/null
+++ b/client/tests/flail/flail-0.2.0.tar.gz
Binary files differ
diff --git a/client/tests/flail/flail.py b/client/tests/flail/flail.py
new file mode 100644
index 0000000..5b32fe6
--- /dev/null
+++ b/client/tests/flail/flail.py
@@ -0,0 +1,42 @@
+import os
+from autotest_lib.client.bin import test, utils
+
+
+class flail(test.test):
+    """
+    This autotest module runs the flail system call fuzzer.
+
+    Fuzzing is slang for fault injection . It runs all system calls for that
+    kernel version with random args. The goal is to find bugs in software
+    without reading code or designing detailed test cases.
+
+    @author: Pradeep K Surisetty (psuriset@linux.vnet.ibm.com)
+    @see: http://www.risesecurity.org/ (Website of Ramon Valle, flail's creator)
+    """
+    version = 1
+
+    def initialize(self):
+        self.job.require_gcc()
+
+
+    def setup(self, tarball = 'flail-0.2.0.tar.gz'):
+        """
+        Compiles flail with the appropriate parameters.
+
+        @param tarball: Path or URL for the flail tarball.
+        """
+        tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
+        utils.extract_tarball_to_dir(tarball, self.srcdir)
+        os.chdir(self.srcdir)
+        utils.make()
+
+
+    def run_once(self, fstype = 'iso9660'):
+        """
+        Runs flail with the appropriate parameters.
+
+        @param fstype: Filesystem type you wish to run flail on.
+        """
+        args = fstype + ' 1'
+        flail_cmd = os.path.join(self.srcdir, 'flail %s' % args)
+        utils.system(flail_cmd)
diff --git a/client/tests/fs_mark/fs_mark.py b/client/tests/fs_mark/fs_mark.py
index 937694e..6bebd13 100644
--- a/client/tests/fs_mark/fs_mark.py
+++ b/client/tests/fs_mark/fs_mark.py
@@ -15,7 +15,7 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
 
-        utils.system('make')
+        utils.make()
 
 
     def run_once(self, dir, args = None):
diff --git a/client/tests/fsfuzzer/fsfuzzer.py b/client/tests/fsfuzzer/fsfuzzer.py
index 1c6e5e8..ca67f84 100644
--- a/client/tests/fsfuzzer/fsfuzzer.py
+++ b/client/tests/fsfuzzer/fsfuzzer.py
@@ -15,7 +15,7 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
 
-        utils.system('make')
+        utils.make()
 
 
     def run_once(self, fstype = 'iso9660'):
diff --git a/client/tests/fsstress/fsstress.py b/client/tests/fsstress/fsstress.py
index 9f81af6..f6dedef 100644
--- a/client/tests/fsstress/fsstress.py
+++ b/client/tests/fsstress/fsstress.py
@@ -16,7 +16,7 @@
 
         os.chdir(self.srcdir)
         utils.system('patch -p1 < ../fsstress-ltp.patch')
-        utils.system('make fsstress')
+        utils.make('fsstress')
 
 
     def run_once(self, testdir = None, extra_args = '', nproc = '1000', nops = '1000'):
diff --git a/client/tests/interbench/interbench.py b/client/tests/interbench/interbench.py
index e988882..a32d5f2 100644
--- a/client/tests/interbench/interbench.py
+++ b/client/tests/interbench/interbench.py
@@ -14,7 +14,7 @@
         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def run_once(self, args = ''):
diff --git a/client/tests/iosched_bugs/iosched_bugs.py b/client/tests/iosched_bugs/iosched_bugs.py
index 2b2b304..f919fcc 100644
--- a/client/tests/iosched_bugs/iosched_bugs.py
+++ b/client/tests/iosched_bugs/iosched_bugs.py
@@ -14,7 +14,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def execute(self):
diff --git a/client/tests/iozone/iozone.py b/client/tests/iozone/iozone.py
index 79178e1..4fbec26 100755
--- a/client/tests/iozone/iozone.py
+++ b/client/tests/iozone/iozone.py
@@ -37,13 +37,13 @@
 
         arch = utils.get_current_kernel_arch()
         if (arch == 'ppc'):
-            utils.system('make linux-powerpc')
+            utils.make('linux-powerpc')
         elif (arch == 'ppc64'):
-            utils.system('make linux-powerpc64')
+            utils.make('linux-powerpc64')
         elif (arch == 'x86_64'):
-            utils.system('make linux-AMD64')
+            utils.make('linux-AMD64')
         else:
-            utils.system('make linux')
+            utils.make('linux')
 
 
     def run_once(self, dir=None, args=None):
diff --git a/client/tests/iperf/iperf.py b/client/tests/iperf/iperf.py
index c487e8c..a240122 100644
--- a/client/tests/iperf/iperf.py
+++ b/client/tests/iperf/iperf.py
@@ -19,7 +19,7 @@
 
         os.chdir(self.srcdir)
         utils.configure()
-        utils.system('make')
+        utils.make()
         utils.system('sync')
 
 
diff --git a/client/tests/kvm/deps/whql_delete_machine_15.cs b/client/tests/kvm/deps/whql_delete_machine_15.cs
new file mode 100644
index 0000000..c7015cc
--- /dev/null
+++ b/client/tests/kvm/deps/whql_delete_machine_15.cs
@@ -0,0 +1,82 @@
+// DTM machine deletion tool
+// Author: Michael Goldish <mgoldish@redhat.com>
+// Based on sample code by Microsoft.
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using Microsoft.DistributedAutomation.DeviceSelection;
+using Microsoft.DistributedAutomation.SqlDataStore;
+
+namespace automate0
+{
+    class AutoJob
+    {
+        static int Main(string[] args)
+        {
+            if (args.Length != 2)
+            {
+                Console.WriteLine("Error: incorrect number of command line arguments");
+                Console.WriteLine("Usage: {0} serverName clientName",
+                    System.Environment.GetCommandLineArgs()[0]);
+                return 1;
+            }
+            string serverName = args[0];
+            string clientName = args[1];
+
+            try
+            {
+                // Initialize DeviceScript and connect to data store
+                Console.WriteLine("Initializing DeviceScript object");
+                DeviceScript script = new DeviceScript();
+                Console.WriteLine("Connecting to data store");
+                script.ConnectToNamedDataStore(serverName);
+
+                // Find the client machine
+                IResourcePool rootPool = script.GetResourcePoolByName("$");
+                Console.WriteLine("Looking for client machine '{0}'", clientName);
+                IResource machine = rootPool.GetResourceByName(clientName);
+                if (machine == null)
+                {
+                    Console.WriteLine("Client machine not found");
+                    return 0;
+                }
+                Console.WriteLine("Client machine '{0}' found ({1}, {2})",
+                    clientName, machine.OperatingSystem, machine.ProcessorArchitecture);
+
+                // Change the client machine's status to 'unsafe'
+                Console.WriteLine("Changing the client machine's status to 'Unsafe'");
+                try
+                {
+                    machine.ChangeResourceStatus("Unsafe");
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("Warning: " + e.Message);
+                }
+                while (machine.Status != "Unsafe")
+                {
+                    try
+                    {
+                        machine = rootPool.GetResourceByName(clientName);
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine("Warning: " + e.Message);
+                    }
+                    System.Threading.Thread.Sleep(1000);
+                }
+
+                // Delete the client machine from datastore
+                Console.WriteLine("Deleting client machine from data store");
+                script.DeleteResource(machine.Id);
+                return 0;
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("Error: " + e.Message);
+                return 1;
+            }
+        }
+    }
+}
diff --git a/client/tests/kvm/deps/whql_delete_machine_15.exe b/client/tests/kvm/deps/whql_delete_machine_15.exe
new file mode 100755
index 0000000..7f57134
--- /dev/null
+++ b/client/tests/kvm/deps/whql_delete_machine_15.exe
Binary files differ
diff --git a/client/tests/kvm/deps/whql_submission_15.cs b/client/tests/kvm/deps/whql_submission_15.cs
new file mode 100644
index 0000000..8fa6856
--- /dev/null
+++ b/client/tests/kvm/deps/whql_submission_15.cs
@@ -0,0 +1,289 @@
+// DTM submission automation program
+// Author: Michael Goldish <mgoldish@redhat.com>
+// Based on sample code by Microsoft.
+
+// Note: this program has only been tested with DTM version 1.5.
+// It might fail to work with other versions, specifically because it uses
+// a few undocumented methods/attributes.
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using Microsoft.DistributedAutomation.DeviceSelection;
+using Microsoft.DistributedAutomation.SqlDataStore;
+
+namespace automate0
+{
+    class AutoJob
+    {
+        static int Main(string[] args)
+        {
+            if (args.Length != 5)
+            {
+                Console.WriteLine("Error: incorrect number of command line arguments");
+                Console.WriteLine("Usage: {0} serverName clientName machinePoolName submissionName timeout",
+                    System.Environment.GetCommandLineArgs()[0]);
+                return 1;
+            }
+            string serverName = args[0];
+            string clientName = args[1];
+            string machinePoolName = args[2];
+            string submissionName = args[3];
+            double timeout = Convert.ToDouble(args[4]);
+
+            try
+            {
+                // Initialize DeviceScript and connect to data store
+                Console.WriteLine("Initializing DeviceScript object");
+                DeviceScript script = new DeviceScript();
+                Console.WriteLine("Connecting to data store");
+
+                script.ConnectToNamedDataStore(serverName);
+
+                // Find client machine
+                IResourcePool rootPool = script.GetResourcePoolByName("$");
+                Console.WriteLine("Looking for client machine '{0}'", clientName);
+                IResource machine = null;
+                while (true)
+                {
+                    try
+                    {
+                        machine = rootPool.GetResourceByName(clientName);
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine("Warning: " + e.Message);
+                    }
+                    // Make sure the machine is valid
+                    if (machine != null &&
+                        machine.OperatingSystem != null &&
+                        machine.OperatingSystem.Length > 0 &&
+                        machine.ProcessorArchitecture != null &&
+                        machine.ProcessorArchitecture.Length > 0 &&
+                        machine.GetDevices().Length > 0)
+                        break;
+                    System.Threading.Thread.Sleep(1000);
+                }
+                Console.WriteLine("Client machine '{0}' found ({1}, {2})",
+                    clientName, machine.OperatingSystem, machine.ProcessorArchitecture);
+
+                // Create machine pool and add client machine to it
+                // (this must be done because jobs cannot be scheduled for machines in the
+                // default pool)
+                try
+                {
+                    script.CreateResourcePool(machinePoolName, rootPool.ResourcePoolId);
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("Warning: " + e.Message);
+                }
+                IResourcePool newPool = script.GetResourcePoolByName(machinePoolName);
+                Console.WriteLine("Moving the client machine to pool '{0}'", machinePoolName);
+                machine.ChangeResourcePool(newPool);
+
+                // Reset client machine
+                if (machine.Status != "Ready")
+                {
+                    Console.WriteLine("Changing the client machine's status to 'Reset'");
+                    while (true)
+                    {
+                        try
+                        {
+                            machine = rootPool.GetResourceByName(clientName);
+                            machine.ChangeResourceStatus("Unsafe");
+                            System.Threading.Thread.Sleep(5000);
+                            machine.ChangeResourceStatus("Reset");
+                            break;
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine("Warning: " + e.Message);
+                        }
+                        System.Threading.Thread.Sleep(5000);
+                    }
+                    Console.WriteLine("Waiting for client machine to be ready");
+                    while (machine.Status != "Ready")
+                    {
+                        try
+                        {
+                            machine = rootPool.GetResourceByName(clientName);
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine("Warning: " + e.Message);
+                        }
+                        System.Threading.Thread.Sleep(1000);
+                    }
+                }
+                Console.WriteLine("Client machine is ready");
+
+                // Get requested device regex and look for a matching device
+                Console.WriteLine("Device to test: ");
+                Regex deviceRegex = new Regex(Console.ReadLine(), RegexOptions.IgnoreCase);
+                Console.WriteLine("Looking for device '{0}'", deviceRegex);
+                IDevice device;
+                DateTime endTime = DateTime.Now.AddSeconds(120);
+                while (DateTime.Now < endTime)
+                {
+                    machine = rootPool.GetResourceByName(clientName);
+                    Console.WriteLine("(Client machine has {0} devices)", machine.GetDevices().Length);
+                    foreach (IDevice d in machine.GetDevices())
+                    {
+                        if (deviceRegex.IsMatch(d.FriendlyName))
+                        {
+                            device = d;
+                            goto deviceFound;
+                        }
+                    }
+                    System.Threading.Thread.Sleep(5000);
+                }
+                Console.WriteLine("Error: device '{0}' not found", deviceRegex);
+                return 1;
+
+            deviceFound:
+                Console.WriteLine("Found device '{0}'", device.FriendlyName);
+
+                // Get requested jobs regex
+                Console.WriteLine("Jobs to run: ");
+                Regex jobRegex = new Regex(Console.ReadLine(), RegexOptions.IgnoreCase);
+
+                // Create submission
+                Object[] existingSubmissions = script.GetSubmissionByName(submissionName);
+                if (existingSubmissions.Length > 0)
+                {
+                    Console.WriteLine("Submission '{0}' already exists -- removing it",
+                        submissionName);
+                    script.DeleteSubmission(((ISubmission)existingSubmissions[0]).Id);
+                }
+                Console.WriteLine("Creating submission '{0}'", submissionName);
+                ISubmission submission = script.CreateHardwareSubmission(submissionName,
+                    newPool.ResourcePoolId, device.InstanceId);
+
+                // Get DeviceData objects from the user
+                List<Object> deviceDataList = new List<Object>();
+                while (true)
+                {
+                    ISubmissionDeviceData dd = script.CreateNewSubmissionDeviceData();
+                    Console.WriteLine("DeviceData name: ");
+                    dd.Name = Console.ReadLine();
+                    if (dd.Name.Length == 0)
+                        break;
+                    Console.WriteLine("DeviceData data: ");
+                    dd.Data = Console.ReadLine();
+                    deviceDataList.Add(dd);
+                }
+
+                // Set the submission's DeviceData
+                submission.SetDeviceData(deviceDataList.ToArray());
+
+                // Get descriptors from the user
+                List<Object> descriptorList = new List<Object>();
+                while (true)
+                {
+                    Console.WriteLine("Descriptor path: ");
+                    string descriptorPath = Console.ReadLine();
+                    if (descriptorPath.Length == 0)
+                        break;
+                    descriptorList.Add(script.GetDescriptorByPath(descriptorPath));
+                }
+
+                // Set the submission's descriptors
+                submission.SetLogoDescriptors(descriptorList.ToArray());
+
+                // Create a schedule
+                ISchedule schedule = script.CreateNewSchedule();
+                Console.WriteLine("Scheduling jobs:");
+                int jobCount = 0;
+                foreach (IJob j in submission.GetJobs())
+                {
+                    if (jobRegex.IsMatch(j.Name))
+                     {
+                        Console.WriteLine("  " + j.Name);
+                        schedule.AddDeviceJob(device, j);
+                        jobCount++;
+                    }
+                }
+                if (jobCount == 0)
+                {
+                    Console.WriteLine("Error: no submission jobs match pattern '{0}'", jobRegex);
+                    return 1;
+                }
+                schedule.AddSubmission(submission);
+                schedule.SetResourcePool(newPool);
+                script.RunSchedule(schedule);
+
+                // Wait for jobs to complete
+                Console.WriteLine("Waiting for all jobs to complete (timeout={0})", timeout);
+                endTime = DateTime.Now.AddSeconds(timeout);
+                int numCompleted = 0, numFailed = 0;
+                while (numCompleted < submission.GetResults().Length && DateTime.Now < endTime)
+                {
+                    // Sleep for 30 seconds
+                    System.Threading.Thread.Sleep(30000);
+                    // Count completed submission jobs
+                    numCompleted = 0;
+                    foreach (IResult r in submission.GetResults())
+                        if (r.ResultStatus != "InProgress")
+                            numCompleted++;
+                    // Report results in a Python readable format and count failed schedule jobs
+                    // (submission jobs are a subset of schedule jobs)
+                    Console.WriteLine();
+                    Console.WriteLine("---- [");
+                    numFailed = 0;
+                    foreach (IResult r in schedule.GetResults())
+                    {
+                        Console.WriteLine("  {");
+                        Console.WriteLine("    'id': {0}, 'job': r'''{1}''',", r.Job.Id, r.Job.Name);
+                        Console.WriteLine("    'logs': r'''{0}''',", r.LogLocation);
+                        if (r.ResultStatus != "InProgress")
+                            Console.WriteLine("    'report': r'''{0}''',",
+                                submission.GetSubmissionResultReport(r));
+                        Console.WriteLine("    'status': '{0}',", r.ResultStatus);
+                        Console.WriteLine("    'pass': {0}, 'fail': {1}, 'notrun': {2}, 'notapplicable': {3}",
+                            r.Pass, r.Fail, r.NotRun, r.NotApplicable);
+                        Console.WriteLine("  },");
+                        numFailed += r.Fail;
+                    }
+                    Console.WriteLine("] ----");
+                }
+                Console.WriteLine();
+
+                // Cancel incomplete jobs
+                foreach (IResult r in schedule.GetResults())
+                    if (r.ResultStatus == "InProgress")
+                        r.Cancel();
+
+                // Set the machine's status to Unsafe and then Reset
+                try
+                {
+                    machine = rootPool.GetResourceByName(clientName);
+                    machine.ChangeResourceStatus("Unsafe");
+                    System.Threading.Thread.Sleep(5000);
+                    machine.ChangeResourceStatus("Reset");
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("Warning: " + e.Message);
+                }
+
+                // Report failures
+                if (numCompleted < submission.GetResults().Length)
+                    Console.WriteLine("Some jobs did not complete on time.");
+                if (numFailed > 0)
+                    Console.WriteLine("Some jobs failed.");
+
+                if (numFailed > 0 || numCompleted < submission.GetResults().Length)
+                    return 1;
+
+                Console.WriteLine("All jobs completed.");
+                return 0;
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("Error: " + e.Message);
+                return 1;
+            }
+        }
+    }
+}
diff --git a/client/tests/kvm/deps/whql_submission_15.exe b/client/tests/kvm/deps/whql_submission_15.exe
new file mode 100755
index 0000000..4f30aa8
--- /dev/null
+++ b/client/tests/kvm/deps/whql_submission_15.exe
Binary files differ
diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py
index 53c11ae..5412aac 100644
--- a/client/tests/kvm/kvm_test_utils.py
+++ b/client/tests/kvm/kvm_test_utils.py
@@ -259,23 +259,47 @@
             result of the regex filter.
     @return: A tuple containing the host time and guest time.
     """
-    host_time = time.time()
-    session.sendline(time_command)
-    (match, s) = session.read_up_to_prompt()
-    if not match:
-        raise error.TestError("Could not get guest time")
+    if len(re.findall("ntpdate|w32tm", time_command)) == 0:
+        host_time = time.time()
+        session.sendline(time_command)
+        (match, s) = session.read_up_to_prompt()
+        if not match:
+            raise error.TestError("Could not get guest time")
 
-    try:
-        s = re.findall(time_filter_re, s)[0]
-    except IndexError:
-        logging.debug("The time string from guest is:\n%s" % s)
-        raise error.TestError("The time string from guest is unexpected.")
-    except Exception, e:
-        logging.debug("(time_filter_re, time_string): (%s, %s)" %
-                       (time_filter_re, s))
-        raise e
+        try:
+            s = re.findall(time_filter_re, s)[0]
+        except IndexError:
+            logging.debug("The time string from guest is:\n%s" % s)
+            raise error.TestError("The time string from guest is unexpected.")
+        except Exception, e:
+            logging.debug("(time_filter_re, time_string): (%s, %s)" %
+                           (time_filter_re, s))
+            raise e
 
-    guest_time = time.mktime(time.strptime(s, time_format))
+        guest_time = time.mktime(time.strptime(s, time_format))
+    else:
+        s , o = session.get_command_status_output(time_command)
+        if s != 0:
+            raise error.TestError("Could not get guest time")
+        if re.match('ntpdate', time_command):
+            offset = re.findall('offset (.*) sec',o)[0]
+            host_main, host_mantissa = re.findall(time_filter_re, o)[0]
+            host_time = time.mktime(time.strptime(host_main, time_format)) \
+                        + float("0.%s" % host_mantissa)
+            guest_time = host_time + float(offset)
+        else:
+            guest_time =  re.findall(time_filter_re, o)[0]
+            offset = re.findall("o:(.*)s", o)[0]
+            if re.match('PM', guest_time):
+                hour = re.findall('\d+ (\d+):', guest_time)[0]
+                hour = str(int(hour) + 12)
+                guest_time = re.sub('\d+\s\d+:', "\d+\s%s:" % hour,
+                                    guest_time)[:-3]
+            else:
+                guest_time = guest_time[:-3]
+            guest_time = time.mktime(time.strptime(guest_time, time_format))
+            host_time = guest_time - float(offset)
+
     return (host_time, guest_time)
 
 
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index bdc9aab..135d08e 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -235,9 +235,10 @@
             return cmd
 
         def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
-            cmd = " -net nic,vlan=%d" % vlan
             if has_option(help, "netdev"):
-                cmd +=",netdev=%s" % netdev_id
+                cmd = " -net nic,netdev=%s" % netdev_id
+            else:
+                cmd = " -net nic,vlan=%d" % vlan
             if model: cmd += ",model=%s" % model
             if mac: cmd += ",macaddr='%s'" % mac
             return cmd
diff --git a/client/tests/kvm/scripts/unattended.py b/client/tests/kvm/scripts/unattended.py
index a630fbc..ba7d80b 100755
--- a/client/tests/kvm/scripts/unattended.py
+++ b/client/tests/kvm/scripts/unattended.py
@@ -3,10 +3,14 @@
 Simple script to setup unattended installs on KVM guests.
 """
 # -*- coding: utf-8 -*-
-import os, sys, shutil, tempfile, re
+import os, sys, shutil, tempfile, re, ConfigParser, glob, inspect
 import common
 
 
+SCRIPT_DIR = os.path.dirname(sys.modules[__name__].__file__)
+KVM_TEST_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
+
+
 class SetupError(Exception):
     """
     Simple wrapper for the builtin Exception class.
@@ -14,6 +18,227 @@
     pass
 
 
+def find_command(cmd):
+    """
+    Searches for a command on common paths, error if it can't find it.
+
+    @param cmd: Command to be found.
+    """
+    for dir in ["/usr/local/sbin", "/usr/local/bin",
+                "/usr/sbin", "/usr/bin", "/sbin", "/bin"]:
+        file = os.path.join(dir, cmd)
+        if os.path.exists(file):
+            return file
+    raise ValueError('Missing command: %s' % cmd)
+
+
+def run(cmd, info=None):
+    """
+    Run a command and throw an exception if it fails.
+    Optionally, you can provide additional contextual info.
+
+    @param cmd: Command string.
+    @param reason: Optional string that explains the context of the failure.
+
+    @raise: SetupError if command fails.
+    """
+    print "Running '%s'" % cmd
+    cmd_name = cmd.split(' ')[0]
+    find_command(cmd_name)
+    if os.system(cmd):
+        e_msg = 'Command failed: %s' % cmd
+        if info is not None:
+            e_msg += '. %s' % info
+        raise SetupError(e_msg)
+
+
+def cleanup(dir):
+    """
+    If dir is a mountpoint, do what is possible to unmount it. Afterwards,
+    try to remove it.
+
+    @param dir: Directory to be cleaned up.
+    """
+    print "Cleaning up directory %s" % dir
+    if os.path.ismount(dir):
+        os.system('fuser -k %s' % dir)
+        run('umount %s' % dir, info='Could not unmount %s' % dir)
+    if os.path.isdir(dir):
+        shutil.rmtree(dir)
+
+
+def clean_old_image(image):
+    """
+    Clean a leftover image file from previous processes. If it contains a
+    mounted file system, do the proper cleanup procedures.
+
+    @param image: Path to image to be cleaned up.
+    """
+    if os.path.exists(image):
+        mtab = open('/etc/mtab', 'r')
+        mtab_contents = mtab.read()
+        mtab.close()
+        if image in mtab_contents:
+            os.system('fuser -k %s' % image)
+            os.system('umount %s' % image)
+        os.remove(image)
+
+
+class Disk(object):
+    """
+    Abstract class for Disk objects, with the common methods implemented.
+    """
+    def __init__(self):
+        self.path = None
+
+
+    def setup_answer_file(self, filename, contents):
+        answer_file = open(os.path.join(self.mount, filename), 'w')
+        answer_file.write(contents)
+        answer_file.close()
+
+
+    def copy_to(self, src):
+        dst = os.path.join(self.mount, os.path.basename(src))
+        if os.path.isdir(src):
+            shutil.copytree(src, dst)
+        elif os.path.isfile(src):
+            shutil.copyfile(src, dst)
+
+
+    def close(self):
+        os.chmod(self.path, 0755)
+        cleanup(self.mount)
+        print "Disk %s successfuly set" % self.path
+
+
+class FloppyDisk(Disk):
+    """
+    Represents a 1.44 MB floppy disk. We can copy files to it, and setup it in
+    convenient ways.
+    """
+    def __init__(self, path):
+        print "Creating floppy unattended image %s" % path
+        try:
+            qemu_img_binary = os.environ['KVM_TEST_qemu_img_binary']
+        except KeyError:
+            qemu_img_binary = os.path.join(KVM_TEST_DIR, qemu_img_binary)
+        if not os.path.exists(qemu_img_binary):
+            raise SetupError('The qemu-img binary that is supposed to be used '
+                             '(%s) does not exist. Please verify your '
+                             'configuration' % qemu_img_binary)
+
+        self.mount = tempfile.mkdtemp(prefix='floppy_', dir='/tmp')
+        self.virtio_mount = None
+        self.path = path
+        clean_old_image(path)
+        if not os.path.isdir(os.path.dirname(path)):
+            os.makedirs(os.path.dirname(path))
+
+        try:
+            c_cmd = '%s create -f raw %s 1440k' % (qemu_img_binary, path)
+            run(c_cmd, info='Could not create floppy image')
+            f_cmd = 'mkfs.msdos -s 1 %s' % path
+            run(f_cmd, info='Error formatting floppy image')
+            m_cmd = 'mount -o loop,rw %s %s' % (path, self.mount)
+            run(m_cmd, info='Could not mount floppy image')
+        except:
+            cleanup(self.mount)
+
+
+    def _copy_virtio_drivers(self, virtio_floppy):
+        """
+        Copy the virtio drivers on the virtio floppy to the install floppy.
+
+        1) Mount the floppy containing the viostor drivers
+        2) Copy its contents to the root of the install floppy
+        """
+        virtio_mount = tempfile.mkdtemp(prefix='virtio_floppy_', dir='/tmp')
+
+        pwd = os.getcwd()
+        try:
+            m_cmd = 'mount -o loop %s %s' % (virtio_floppy, virtio_mount)
+            run(m_cmd, info='Could not mount virtio floppy driver')
+            os.chdir(virtio_mount)
+            path_list = glob.glob('*')
+            for path in path_list:
+                self.copy_to(path)
+        finally:
+            os.chdir(pwd)
+            cleanup(virtio_mount)
+
+
+    def setup_virtio_win2003(self, virtio_floppy, virtio_oemsetup_id):
+        """
+        Setup the install floppy with the virtio storage drivers, win2003 style.
+
+        Win2003 and WinXP depend on the file txtsetup.oem file to install
+        the virtio drivers from the floppy, which is a .ini file.
+        Process:
+
+        1) Copy the virtio drivers on the virtio floppy to the install floppy
+        2) Parse the ini file with config parser
+        3) Modify the identifier of the default session that is going to be
+           executed on the config parser object
+        4) Re-write the config file to the disk
+        """
+        self._copy_virtio_drivers(virtio_floppy)
+        txtsetup_oem = os.path.join(self.mount, 'txtsetup.oem')
+        if not os.path.isfile(txtsetup_oem):
+            raise SetupError('File txtsetup.oem not found on the install '
+                             'floppy. Please verify if your floppy virtio '
+                             'driver image has this file')
+        parser = ConfigParser.ConfigParser()
+        parser.read(txtsetup_oem)
+        if not parser.has_section('Defaults'):
+            raise SetupError('File txtsetup.oem does not have the session '
+                             '"Defaults". Please check txtsetup.oem')
+        default_driver = parser.get('Defaults', 'SCSI')
+        if default_driver != virtio_oemsetup_id:
+            parser.set('Defaults', 'SCSI', virtio_oemsetup_id)
+            fp = open(txtsetup_oem, 'w')
+            parser.write(fp)
+            fp.close()
+
+
+    def setup_virtio_win2008(self, virtio_floppy):
+        """
+        Setup the install floppy with the virtio storage drivers, win2008 style.
+
+        Win2008, Vista and 7 require people to point out the path to the drivers
+        on the unattended file, so we just need to copy the drivers to the
+        driver floppy disk.
+        Process:
+
+        1) Copy the virtio drivers on the virtio floppy to the install floppy
+        """
+        self._copy_virtio_drivers(virtio_floppy)
+
+
+class CdromDisk(Disk):
+    """
+    Represents a CDROM disk that we can master according to our needs.
+    """
+    def __init__(self, path):
+        print "Creating ISO unattended image %s" % path
+        self.mount = tempfile.mkdtemp(prefix='cdrom_unattended_', dir='/tmp')
+        self.path = path
+        clean_old_image(path)
+        if not os.path.isdir(os.path.dirname(path)):
+            os.makedirs(os.path.dirname(path))
+
+
+    def close(self):
+        g_cmd = ('mkisofs -o %s -max-iso9660-filenames '
+                 '-relaxed-filenames -D --input-charset iso8859-1 '
+                 '%s' % (self.path, self.mount))
+        run(g_cmd, info='Could not generate iso with answer file')
+
+        os.chmod(self.path, 0755)
+        cleanup(self.mount)
+        print "Disk %s successfuly set" % self.path
+
+
 class UnattendedInstall(object):
     """
     Creates a floppy disk image that will contain a config file for unattended
@@ -25,144 +250,188 @@
         """
         Gets params from environment variables and sets class attributes.
         """
-        script_dir = os.path.dirname(sys.modules[__name__].__file__)
-        kvm_test_dir = os.path.abspath(os.path.join(script_dir, ".."))
-        images_dir = os.path.join(kvm_test_dir, 'images')
-        self.deps_dir = os.path.join(kvm_test_dir, 'deps')
-        self.unattended_dir = os.path.join(kvm_test_dir, 'unattended')
+        images_dir = os.path.join(KVM_TEST_DIR, 'images')
+        self.deps_dir = os.path.join(KVM_TEST_DIR, 'deps')
+        self.unattended_dir = os.path.join(KVM_TEST_DIR, 'unattended')
 
-        tftp_root = os.environ.get('KVM_TEST_tftp', '')
-        if tftp_root:
-            self.tftp_root = os.path.join(kvm_test_dir, tftp_root)
-            if not os.path.isdir(self.tftp_root):
-                os.makedirs(self.tftp_root)
-        else:
-            self.tftp_root = tftp_root
+        attributes = ['kernel_args', 'finish_program', 'cdrom_cd1',
+                      'unattended_file', 'medium', 'url', 'kernel', 'initrd',
+                      'nfs_server', 'nfs_dir', 'pxe_dir', 'pxe_image',
+                      'pxe_initrd', 'install_virtio', 'tftp',
+                      'floppy', 'cdrom_unattended']
+        for a in attributes:
+            self._setattr(a)
 
-        self.kernel_args = os.environ.get('KVM_TEST_kernel_args', '')
-        self.finish_program= os.environ.get('KVM_TEST_finish_program', '')
-        cdrom_iso = os.environ.get('KVM_TEST_cdrom_cd1')
-        self.unattended_file = os.environ.get('KVM_TEST_unattended_file')
+        if self.install_virtio == 'yes':
+            v_attributes = ['virtio_floppy', 'virtio_storage_path',
+                            'virtio_network_path', 'virtio_oemsetup_id',
+                            'virtio_network_installer']
+            for va in v_attributes:
+                self._setattr(va)
 
-        self.qemu_img_bin = os.environ.get('KVM_TEST_qemu_img_binary')
-        if not os.path.isabs(self.qemu_img_bin):
-            self.qemu_img_bin = os.path.join(kvm_test_dir, self.qemu_img_bin)
-        self.cdrom_iso = os.path.join(kvm_test_dir, cdrom_iso)
-        self.floppy_mount = tempfile.mkdtemp(prefix='floppy_', dir='/tmp')
-        self.cdrom_mount = tempfile.mkdtemp(prefix='cdrom_', dir='/tmp')
-        self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', dir='/tmp')
-        floppy_name = os.environ['KVM_TEST_floppy']
-        self.floppy_img = os.path.join(kvm_test_dir, floppy_name)
-        floppy_dir = os.path.dirname(self.floppy_img)
-        if not os.path.isdir(floppy_dir):
-            os.makedirs(floppy_dir)
+        # Silly attribution just to calm pylint down...
+        self.tftp = self.tftp
+        if self.tftp:
+            self.tftp = os.path.join(KVM_TEST_DIR, self.tftp)
+            if not os.path.isdir(self.tftp):
+                os.makedirs(self.tftp)
 
-        self.pxe_dir = os.environ.get('KVM_TEST_pxe_dir', '')
-        self.pxe_image = os.environ.get('KVM_TEST_pxe_image', '')
-        self.pxe_initrd = os.environ.get('KVM_TEST_pxe_initrd', '')
+        self.cdrom_cd1 = os.path.join(KVM_TEST_DIR, self.cdrom_cd1)
+        self.cdrom_cd1_mount = tempfile.mkdtemp(prefix='cdrom_cd1_', dir='/tmp')
+        if self.medium == 'nfs':
+            self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', dir='/tmp')
 
-        self.medium = os.environ.get('KVM_TEST_medium', '')
-        self.url = os.environ.get('KVM_TEST_url', '')
-        self.kernel = os.environ.get('KVM_TEST_kernel', '')
-        self.initrd = os.environ.get('KVM_TEST_initrd', '')
-        self.nfs_server = os.environ.get('KVM_TEST_nfs_server', '')
-        self.nfs_dir = os.environ.get('KVM_TEST_nfs_dir', '')
-        self.image_path = kvm_test_dir
+        self.floppy = os.path.join(KVM_TEST_DIR, self.floppy)
+        if not os.path.isdir(os.path.dirname(self.floppy)):
+            os.makedirs(os.path.dirname(self.floppy))
+
+        self.image_path = KVM_TEST_DIR
         self.kernel_path = os.path.join(self.image_path, self.kernel)
         self.initrd_path = os.path.join(self.image_path, self.initrd)
 
 
-    def create_boot_floppy(self):
+    def _setattr(self, key):
         """
-        Prepares a boot floppy by creating a floppy image file, mounting it and
-        copying an answer file (kickstarts for RH based distros, answer files
-        for windows) to it. After that the image is umounted.
+        Populate class attributes with contents of environment variables.
+
+        Example: KVM_TEST_medium will populate self.medium.
+
+        @param key: Name of the class attribute we desire to have.
         """
-        print "Creating boot floppy"
+        env_name = 'KVM_TEST_%s' % key
+        value = os.environ.get(env_name, '')
+        setattr(self, key, value)
 
-        if os.path.exists(self.floppy_img):
-            os.remove(self.floppy_img)
 
-        c_cmd = '%s create -f raw %s 1440k' % (self.qemu_img_bin,
-                                               self.floppy_img)
-        if os.system(c_cmd):
-            raise SetupError('Could not create floppy image.')
-
-        f_cmd = 'mkfs.msdos -s 1 %s' % self.floppy_img
-        if os.system(f_cmd):
-            raise SetupError('Error formatting floppy image.')
-
-        try:
-            m_cmd = 'mount -o loop %s %s' % (self.floppy_img, self.floppy_mount)
-            if os.system(m_cmd):
-                raise SetupError('Could not mount floppy image.')
-
-            if self.unattended_file.endswith('.sif'):
-                dest_fname = 'winnt.sif'
-                setup_file = 'winnt.bat'
-                setup_file_path = os.path.join(self.unattended_dir, setup_file)
-                setup_file_dest = os.path.join(self.floppy_mount, setup_file)
-                shutil.copyfile(setup_file_path, setup_file_dest)
-            elif self.unattended_file.endswith('.ks'):
-                # Red Hat kickstart install
-                dest_fname = 'ks.cfg'
-            elif self.unattended_file.endswith('.xml'):
-                if  self.tftp_root is '':
-                    # Windows unattended install
-                    dest_fname = "autounattend.xml"
-                else:
-                    # SUSE autoyast install
-                    dest_fname = "autoinst.xml"
-
-            dest = os.path.join(self.floppy_mount, dest_fname)
-
-            # Replace KVM_TEST_CDKEY (in the unattended file) with the cdkey
-            # provided for this test and replace the KVM_TEST_MEDIUM with
-            # the tree url or nfs address provided for this test.
-            unattended_contents = open(self.unattended_file).read()
-            dummy_cdkey_re = r'\bKVM_TEST_CDKEY\b'
-            real_cdkey = os.environ.get('KVM_TEST_cdkey')
-            if re.search(dummy_cdkey_re, unattended_contents):
-                if real_cdkey:
-                    unattended_contents = re.sub(dummy_cdkey_re, real_cdkey,
-                                                 unattended_contents)
-                else:
-                    print ("WARNING: 'cdkey' required but not specified for "
-                           "this unattended installation")
-
-            dummy_re = r'\bKVM_TEST_MEDIUM\b'
-            if self.medium == "cdrom":
-                content = "cdrom"
-            elif self.medium == "url":
-                content = "url --url %s" % self.url
-            elif self.medium == "nfs":
-                content = "nfs --server=%s --dir=%s" % (self.nfs_server, self.nfs_dir)
+    def render_answer_file(self):
+        # Replace KVM_TEST_CDKEY (in the unattended file) with the cdkey
+        # provided for this test and replace the KVM_TEST_MEDIUM with
+        # the tree url or nfs address provided for this test.
+        unattended_contents = open(self.unattended_file).read()
+        dummy_cdkey_re = r'\bKVM_TEST_CDKEY\b'
+        real_cdkey = os.environ.get('KVM_TEST_cdkey')
+        if re.search(dummy_cdkey_re, unattended_contents):
+            if real_cdkey:
+                unattended_contents = re.sub(dummy_cdkey_re, real_cdkey,
+                                             unattended_contents)
             else:
-                raise SetupError("Unexpected installation medium %s" % self.url)
+                print ("WARNING: 'cdkey' required but not specified for "
+                       "this unattended installation")
 
-            unattended_contents = re.sub(dummy_re, content, unattended_contents)
+        dummy_medium_re = r'\bKVM_TEST_MEDIUM\b'
+        if self.medium == "cdrom":
+            content = "cdrom"
+        elif self.medium == "url":
+            content = "url --url %s" % self.url
+        elif self.medium == "nfs":
+            content = "nfs --server=%s --dir=%s" % (self.nfs_server,
+                                                    self.nfs_dir)
+        else:
+            raise SetupError("Unexpected installation medium %s" % self.url)
 
-            print
-            print "Unattended install %s contents:" % dest_fname
-            print unattended_contents
-            # Write the unattended file contents to 'dest'
-            open(dest, 'w').write(unattended_contents)
+        unattended_contents = re.sub(dummy_medium_re, content,
+                                     unattended_contents)
 
-            if self.finish_program:
-                dest_fname = os.path.basename(self.finish_program)
-                dest = os.path.join(self.floppy_mount, dest_fname)
-                shutil.copyfile(self.finish_program, dest)
+        def replace_virtio_key(contents, dummy_re, env):
+            """
+            Replace a virtio dummy string with contents.
 
-        finally:
-            u_cmd = 'umount %s' % self.floppy_mount
-            if os.system(u_cmd):
-                raise SetupError('Could not unmount floppy at %s.' %
-                                 self.floppy_mount)
-            self.cleanup(self.floppy_mount)
+            If install_virtio is not set, replace it with a dummy string.
 
-        os.chmod(self.floppy_img, 0755)
+            @param contents: Contents of the unattended file
+            @param dummy_re: Regular expression used to search on the.
+                    unattended file contents.
+            @param env: Name of the environment variable.
+            """
+            dummy_path = "C:"
+            driver = os.environ.get(env, '')
 
-        print "Boot floppy created successfuly"
+            if re.search(dummy_re, contents):
+                if self.install_virtio == "yes":
+                    if driver.endswith("msi"):
+                        driver = 'msiexec /passive /package ' + driver
+                    else:
+                        try:
+                            # Let's escape windows style paths properly
+                            drive, path = driver.split(":")
+                            driver = drive + ":" + re.escape(path)
+                        except:
+                            pass
+                    contents = re.sub(dummy_re, driver, contents)
+                else:
+                    contents = re.sub(dummy_re, dummy_path, contents)
+            return contents
+
+        vdict = {r'\bKVM_TEST_STORAGE_DRIVER_PATH\b':
+                 'KVM_TEST_virtio_storage_path',
+                 r'\bKVM_TEST_NETWORK_DRIVER_PATH\b':
+                 'KVM_TEST_virtio_network_path',
+                 r'\bKVM_TEST_VIRTIO_NETWORK_INSTALLER\b':
+                 'KVM_TEST_virtio_network_installer_path'}
+
+        for vkey in vdict:
+            unattended_contents = replace_virtio_key(unattended_contents,
+                                                     vkey, vdict[vkey])
+
+        print "Unattended install contents:"
+        print unattended_contents
+        return unattended_contents
+
+
+    def setup_boot_disk(self):
+        answer_contents = self.render_answer_file()
+
+        if self.unattended_file.endswith('.sif'):
+            dest_fname = 'winnt.sif'
+            setup_file = 'winnt.bat'
+            boot_disk = FloppyDisk(self.floppy)
+            boot_disk.setup_answer_file(dest_fname, answer_contents)
+            setup_file_path = os.path.join(self.unattended_dir, setup_file)
+            boot_disk.copy_to(setup_file_path)
+            if self.install_virtio == "yes":
+                boot_disk.setup_virtio_win2003(self.virtio_floppy,
+                                               self.virtio_oemsetup_id)
+            boot_disk.copy_to(self.finish_program)
+
+        elif self.unattended_file.endswith('.ks'):
+            # Red Hat kickstart install
+            dest_fname = 'ks.cfg'
+            if self.cdrom_unattended:
+                boot_disk = CdromDisk(self.cdrom_unattended)
+            elif self.floppy:
+                boot_disk = FloppyDisk(self.floppy)
+            else:
+                raise SetupError("Neither cdrom_unattended nor floppy set "
+                                 "on the config file, please verify")
+            boot_disk.setup_answer_file(dest_fname, answer_contents)
+
+        elif self.unattended_file.endswith('.xml'):
+            if self.tftp:
+                # SUSE autoyast install
+                dest_fname = "autoinst.xml"
+                if self.cdrom_unattended:
+                    boot_disk = CdromDisk(self.cdrom_unattended)
+                elif self.floppy:
+                    boot_disk = FloppyDisk(self.floppy)
+                else:
+                    raise SetupError("Neither cdrom_unattended nor floppy set "
+                                     "on the config file, please verify")
+                boot_disk.setup_answer_file(dest_fname, answer_contents)
+
+            else:
+                # Windows unattended install
+                dest_fname = "autounattend.xml"
+                boot_disk = FloppyDisk(self.floppy)
+                boot_disk.setup_answer_file(dest_fname, answer_contents)
+                if self.install_virtio == "yes":
+                    boot_disk.setup_virtio_win2008(self.virtio_floppy)
+                boot_disk.copy_to(self.finish_program)
+
+        else:
+            raise SetupError('Unknown answer file %s' %
+                             self.unattended_file)
+
+        boot_disk.close()
 
 
     def setup_pxe_boot(self):
@@ -173,7 +442,7 @@
         initrd.img files from the CD to a directory that qemu will serve trough
         TFTP to the VM.
         """
-        print "Setting up PXE boot using TFTP root %s" % self.tftp_root
+        print "Setting up PXE boot using TFTP root %s" % self.tftp
 
         pxe_file = None
         pxe_paths = ['/usr/lib/syslinux/pxelinux.0',
@@ -188,17 +457,15 @@
                              'sure pxelinux or equivalent package for your '
                              'distro is installed.')
 
-        pxe_dest = os.path.join(self.tftp_root, 'pxelinux.0')
+        pxe_dest = os.path.join(self.tftp, 'pxelinux.0')
         shutil.copyfile(pxe_file, pxe_dest)
 
         try:
-            m_cmd = 'mount -t iso9660 -v -o loop,ro %s %s' % (self.cdrom_iso,
-                                                              self.cdrom_mount)
-            if os.system(m_cmd):
-                raise SetupError('Could not mount CD image %s.' %
-                                 self.cdrom_iso)
+            m_cmd = ('mount -t iso9660 -v -o loop,ro %s %s' %
+                     (self.cdrom_cd1, self.cdrom_cd1_mount))
+            run(m_cmd, info='Could not mount CD image %s.' % self.cdrom_cd1)
 
-            pxe_dir = os.path.join(self.cdrom_mount, self.pxe_dir)
+            pxe_dir = os.path.join(self.cdrom_cd1_mount, self.pxe_dir)
             pxe_image = os.path.join(pxe_dir, self.pxe_image)
             pxe_initrd = os.path.join(pxe_dir, self.pxe_initrd)
 
@@ -213,19 +480,15 @@
                                  'or a initrd.img file. Cannot find a PXE '
                                  'image to proceed.' % self.pxe_dir)
 
-            tftp_image = os.path.join(self.tftp_root, 'vmlinuz')
-            tftp_initrd = os.path.join(self.tftp_root, 'initrd.img')
+            tftp_image = os.path.join(self.tftp, 'vmlinuz')
+            tftp_initrd = os.path.join(self.tftp, 'initrd.img')
             shutil.copyfile(pxe_image, tftp_image)
             shutil.copyfile(pxe_initrd, tftp_initrd)
 
         finally:
-            u_cmd = 'umount %s' % self.cdrom_mount
-            if os.system(u_cmd):
-                raise SetupError('Could not unmount CD at %s.' %
-                                 self.cdrom_mount)
-            self.cleanup(self.cdrom_mount)
+            cleanup(self.cdrom_cd1_mount)
 
-        pxe_config_dir = os.path.join(self.tftp_root, 'pxelinux.cfg')
+        pxe_config_dir = os.path.join(self.tftp, 'pxelinux.cfg')
         if not os.path.isdir(pxe_config_dir):
             os.makedirs(pxe_config_dir)
         pxe_config_path = os.path.join(pxe_config_dir, 'default')
@@ -245,7 +508,7 @@
 
     def setup_url(self):
         """
-        Download the vmlinuz and initrd.img from URL
+        Download the vmlinuz and initrd.img from URL.
         """
         print "Downloading the vmlinuz and initrd.img"
         os.chdir(self.image_path)
@@ -258,12 +521,11 @@
         if os.path.exists(self.initrd):
             os.unlink(self.initrd)
 
-        if os.system(kernel_fetch_cmd) != 0:
-            raise SetupError("Could not fetch vmlinuz from %s" % self.url)
-        if os.system(initrd_fetch_cmd) != 0:
-            raise SetupError("Could not fetch initrd.img from %s" % self.url)
+        run(kernel_fetch_cmd, info="Could not fetch vmlinuz from %s" % self.url)
+        run(initrd_fetch_cmd, info=("Could not fetch initrd.img from %s" %
+                                    self.url))
+        print "Download of vmlinuz and initrd.img finished"
 
-        print "Downloading finish"
 
     def setup_nfs(self):
         """
@@ -271,71 +533,44 @@
         """
         print "Copying the vmlinuz and initrd.img from nfs"
 
-        m_cmd = "mount %s:%s %s -o ro" % (self.nfs_server, self.nfs_dir, self.nfs_mount)
-        if os.system(m_cmd):
-            raise SetupError('Could not mount nfs server.')
-
-        kernel_fetch_cmd = "cp %s/isolinux/%s %s" % (self.nfs_mount,
-                                                     self.kernel,
-                                                     self.image_path)
-        initrd_fetch_cmd = "cp %s/isolinux/%s %s" % (self.nfs_mount,
-                                                     self.initrd,
-                                                     self.image_path)
+        m_cmd = ("mount %s:%s %s -o ro" %
+                 (self.nfs_server, self.nfs_dir, self.nfs_mount))
+        run(m_cmd, info='Could not mount nfs server')
 
         try:
-            if os.system(kernel_fetch_cmd):
-                raise SetupError("Could not copy the vmlinuz from %s" %
-                                 self.nfs_mount)
-            if os.system(initrd_fetch_cmd):
-                raise SetupError("Could not copy the initrd.img from %s" %
-                                 self.nfs_mount)
+            kernel_fetch_cmd = ("cp %s/isolinux/%s %s" %
+                                (self.nfs_mount, self.kernel, self.image_path))
+            run(kernel_fetch_cmd, info=("Could not copy the vmlinuz from %s" %
+                                        self.nfs_mount))
+            initrd_fetch_cmd = ("cp %s/isolinux/%s %s" %
+                                (self.nfs_mount, self.initrd, self.image_path))
+            run(initrd_fetch_cmd, info=("Could not copy the initrd.img from "
+                                        "%s" % self.nfs_mount))
         finally:
-            u_cmd = "umount %s" % self.nfs_mount
-            if os.system(u_cmd):
-                raise SetupError("Could not unmont nfs at %s" % self.nfs_mount)
-            self.cleanup(self.nfs_mount)
-
-    def cleanup(self, mount):
-        """
-        Clean up a previously used mountpoint.
-
-        @param mount: Mountpoint to be cleaned up.
-        """
-        if os.path.isdir(mount):
-            if os.path.ismount(mount):
-                print "Path %s is still mounted, please verify" % mount
-            else:
-                print "Removing mount point %s" % mount
-                os.rmdir(mount)
+            cleanup(self.nfs_mount)
 
 
     def setup(self):
+        """
+        Configure the environment for unattended install.
+
+        Uses an appropriate strategy according to each install model.
+        """
         print "Starting unattended install setup"
+        print
 
         print "Variables set:"
-        print "    medium: " + str(self.medium)
-        print "    qemu_img_bin: " + str(self.qemu_img_bin)
-        print "    cdrom iso: " + str(self.cdrom_iso)
-        print "    unattended_file: " + str(self.unattended_file)
-        print "    kernel_args: " + str(self.kernel_args)
-        print "    tftp_root: " + str(self.tftp_root)
-        print "    floppy_mount: " + str(self.floppy_mount)
-        print "    floppy_img: " + str(self.floppy_img)
-        print "    finish_program: " + str(self.finish_program)
-        print "    pxe_dir: " + str(self.pxe_dir)
-        print "    pxe_image: " + str(self.pxe_image)
-        print "    pxe_initrd: " + str(self.pxe_initrd)
-        print "    url: " + str(self.url)
-        print "    kernel: " + str(self.kernel)
-        print "    initrd: " + str(self.initrd)
-        print "    nfs_server: " + str(self.nfs_server)
-        print "    nfs_dir: " + str(self.nfs_dir)
-        print "    nfs_mount: " + str(self.nfs_mount)
+        for member in inspect.getmembers(self):
+            name, value = member
+            attribute = getattr(self, name)
+            if not (name.startswith("__") or callable(attribute) or not value):
+                print "    %s: %s" % (name, value)
+        print
 
-        if self.unattended_file and self.floppy_img is not None:
-            self.create_boot_floppy()
+        if self.unattended_file and (self.floppy or self.cdrom_unattended):
+            self.setup_boot_disk()
         if self.medium == "cdrom":
-            if self.tftp_root:
+            if self.tftp:
                 self.setup_pxe_boot()
         elif self.medium == "url":
             self.setup_url()
@@ -343,7 +578,7 @@
             self.setup_nfs()
         else:
             raise SetupError("Unexpected installation method %s" %
-                                   self.medium)
+                             self.medium)
         print "Unattended install setup finished successfuly"
 
 
diff --git a/client/tests/kvm/scripts/virtio_guest.py b/client/tests/kvm/scripts/virtio_guest.py
new file mode 100644
index 0000000..4862ef2
--- /dev/null
+++ b/client/tests/kvm/scripts/virtio_guest.py
@@ -0,0 +1,513 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+Auxiliary script used to send data between ports on guests.
+
+@copyright: 2008-2009 Red Hat Inc.
+@author: Jiri Zupka (jzupka@redhat.com)
+@author: Lukas Doktor (ldoktor@redhat.com)
+"""
+#from _pydev_SimpleXMLRPCServer import fcntl
+
+"""
+TODO:
+virt.init([consoles])   # sysfs, udev, OK
+virt.open(name)
+virt.close(name)
+virt.poll(name, eventmask, timeout) # poll.register(), poll.poll(),
+return event
+virt.send(name, length) # host disconnected
+virt.recv(name, length) # host disconnected
+virt.blocking(name, true)   # true = blocking, false = nonblocking
+virt.loopback(in_names, out_names, type="None")  # use select/poll
+"""
+
+import threading
+from threading import Thread
+import os, time, select, re, random, sys, array, fcntl, array, subprocess
+
+DEBUGPATH = "/sys/kernel/debug"
+SYSFSPATH = "/sys/class/virtio-ports/"
+
+
+class virtio_guest():
+
+    LOOP_NONE = 0
+    LOOP_POLL = 1
+    LOOP_SELECT = 2
+
+    def __init__(self):
+        self.files = {}
+        self.exit_thread = threading.Event()
+        self.threads = []
+        self.ports = {}
+
+
+    def _readfile(self, name):
+        """
+        Read file and return content as string
+
+        @param name: Name of file
+        @return: Content of file as string
+        """
+        out = ""
+        try:
+            f = open(name, "r")
+            out = f.read()
+            f.close()
+        except:
+            print "FAIL: Cannot open file %s" % (name)
+
+        return out
+
+
+    def _get_port_status(self):
+        """
+        Get info about ports from kernel debugfs.
+
+        @return: Ports dictionary of port properties
+        """
+        ports = {}
+        not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
+        if (not os.path.ismount(DEBUGPATH)):
+            os.system('mount -t debugfs none %s' % (DEBUGPATH))
+        try:
+            if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
+                print not_present_msg
+        except:
+            print not_present_msg
+        else:
+            viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
+            for name in viop_names:
+                f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
+                port = {}
+                for line in iter(f):
+                    m = re.match("(\S+): (\S+)", line)
+                    port[m.group(1)] = m.group(2)
+
+                if (port['is_console'] == "yes"):
+                    port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
+                    # Console works like a serialport
+                else:
+                    port["path"] = "/dev/%s" % name
+
+                if (not os.path.exists(port['path'])):
+                    print "FAIL: %s not exist" % port['path']
+
+                sysfspath = SYSFSPATH + name
+                if (not os.path.isdir(sysfspath)):
+                    print "FAIL: %s not exist" % (sysfspath)
+
+                info_name = sysfspath + "/name"
+                port_name = self._readfile(info_name).strip()
+                if (port_name != port["name"]):
+                    print ("FAIL: Port info not match \n%s - %s\n%s - %s" %
+                           (info_name , port_name,
+                            "%s/virtio-ports/%s" % (DEBUGPATH, name),
+                            port["name"]))
+
+                ports[port['name']] = port
+                f.close()
+
+        return ports
+
+
+    def init(self, in_files):
+        """
+        Init and check port properties.
+        """
+        self.ports = self._get_port_status()
+
+        for item in in_files:
+            if (item[1] != self.ports[item[0]]["is_console"]):
+                print self.ports
+                print "FAIL: Host console is not like console on guest side\n"
+        print "PASS: Init and check virtioconsole files in system."
+
+
+    class switch(Thread):
+        """
+        Thread that sends data between ports.
+        """
+        def __init__ (self, in_files, out_files, event,
+                      cachesize=1024, method=0):
+            """
+            @param in_files: Array of input files.
+            @param out_files: Array of output files.
+            @param method: Method of read/write access.
+            @param cachesize: Block to receive and send.
+            """
+            Thread.__init__(self)
+
+            self.in_files = in_files
+            self.out_files = out_files
+            self.exit_thread = event
+            self.method = method
+
+            self.cachesize = cachesize
+
+
+        def _none_mode(self):
+            """
+            Read and write to device in blocking mode
+            """
+            data = ""
+            while not self.exit_thread.isSet():
+                data = ""
+                for desc in self.in_files:
+                    data += os.read(desc, self.cachesize)
+                if data != "":
+                    for desc in self.out_files:
+                        os.write(desc, data)
+
+
+        def _poll_mode(self):
+            """
+            Read and write to device in polling mode.
+            """
+
+            pi = select.poll()
+            po = select.poll()
+
+            for fd in self.in_files:
+                pi.register(fd, select.POLLIN)
+
+            for fd in self.out_files:
+                po.register(fd, select.POLLOUT)
+
+            while not self.exit_thread.isSet():
+                data = ""
+                t_out = self.out_files
+
+                readyf = pi.poll(1.0)
+                for i in readyf:
+                    data += os.read(i[0], self.cachesize)
+
+                if data != "":
+                    while ((len(t_out) != len(readyf)) and not
+                           self.exit_thread.isSet()):
+                        readyf = po.poll(1.0)
+                    for desc in t_out:
+                        os.write(desc, data)
+
+
+        def _select_mode(self):
+            """
+            Read and write to device in selecting mode.
+            """
+            while not self.exit_thread.isSet():
+                ret = select.select(self.in_files, [], [], 1.0)
+                data = ""
+                if ret[0] != []:
+                    for desc in ret[0]:
+                        data += os.read(desc, self.cachesize)
+                if data != "":
+                    ret = select.select([], self.out_files, [], 1.0)
+                    while ((len(self.out_files) != len(ret[1])) and not
+                           self.exit_thread.isSet()):
+                        ret = select.select([], self.out_files, [], 1.0)
+                    for desc in ret[1]:
+                        os.write(desc, data)
+
+
+        def run(self):
+            if (self.method == virtio_guest.LOOP_POLL):
+                self._poll_mode()
+            elif (self.method == virtio_guest.LOOP_SELECT):
+                self._select_mode()
+            else:
+                self._none_mode()
+
+
+    class sender(Thread):
+        """
+        Creates a thread which sends random blocks of data to dst port.
+        """
+        def __init__(self, port, event, length):
+            """
+            @param port: Destination port
+            @param length: Length of the random data block
+            """
+            Thread.__init__(self)
+            self.port = port
+            self.exit_thread = event
+            self.data = array.array('L')
+            for i in range(max(length / self.data.itemsize, 1)):
+                self.data.append(random.randrange(sys.maxint))
+
+        def run(self):
+            while not self.exit_thread.isSet():
+                os.write(self.port, self.data)
+
+
+    def _open(self, in_files):
+        """
+        Open devices and return array of descriptors
+
+        @param in_files: Files array
+        @return: Array of descriptor
+        """
+        f = []
+
+        for item in in_files:
+            name = self.ports[item]["path"]
+            if (name in self.files):
+                f.append(self.files[name])
+            else:
+                try:
+                    self.files[name] = os.open(name, os.O_RDWR)
+                    if (self.ports[item]["is_console"] == "yes"):
+                        print os.system("stty -F %s raw -echo" % (name))
+                        print os.system("stty -F %s -a" % (name))
+                    f.append(self.files[name])
+                except Exception as inst:
+                    print "FAIL: Failed to open file %s" % (name)
+                    raise inst
+        return f
+
+
+    def poll(self, port, expected, timeout=500):
+        """
+        Pool event from device and print event like text.
+
+        @param file: Device.
+        """
+        in_f = self._open([port])
+
+        p = select.poll()
+        p.register(in_f[0])
+
+        mask = p.poll(timeout)
+
+        str = ""
+        if (mask[0][1] & select.POLLIN):
+            str += "IN "
+        if (mask[0][1] & select.POLLPRI):
+            str += "PRI IN "
+        if (mask[0][1] & select.POLLOUT):
+            str += "OUT "
+        if (mask[0][1] & select.POLLERR):
+            str += "ERR "
+        if (mask[0][1] & select.POLLHUP):
+            str += "HUP "
+        if (mask[0][1] & select.POLLMSG):
+            str += "MSG "
+
+        if (mask[0][1] & expected) == expected:
+            print "PASS: Events: " + str
+        else:
+            print "FAIL: Events: " + str
+
+
+    def blocking(self, port, mode=False):
+        """
+        Set port function mode blocking/nonblocking
+
+        @param port: port to set mode
+        @param mode: False to set nonblock mode, True for block mode
+        """
+        path = self.ports[port]["path"]
+        fd = self.files[path]
+
+        try:
+            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+            if not mode:
+                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+            else:
+                fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
+
+        except Exception as inst:
+            print "FAIL: Setting (non)blocking mode: " + str(inst)
+            return
+
+        print ("PASS: set blocking mode to %s mode" %
+               ("blocking" if mode else "nonblocking"))
+
+
+    def close(self, file):
+        """
+        Close open port.
+
+        @param file: File to close.
+        """
+        descriptor = None
+        path = self.ports[file]["path"]
+        if path != None:
+            if path in self.files.keys():
+                descriptor = self.files[path]
+                del self.files[path]
+        try:
+            os.close(descriptor)
+        except Exception as inst:
+            print "FAIL: Closing the file: " + str(inst)
+            return
+        print "PASS: Close"
+
+
+    def open(self, in_files):
+        """
+        Direct open devices.
+
+        @param in_files: Array of files.
+        @return: Array of descriptors.
+        """
+        name = self.ports[in_files]["path"]
+        try:
+            self.files[name] = os.open(name, os.O_RDWR)
+            print "PASS: Open all filles correctly."
+        except Exception as inst:
+            print "%s\nFAIL: Failed open file %s" % (str(inst), name)
+
+
+    def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
+        """
+        Start a switch thread.
+
+        (There is a problem with multiple opens of a single file).
+
+        @param in_files: Array of input files.
+        @param out_files: Array of output files.
+        @param cachesize: Cachesize.
+        """
+        self.ports = self._get_port_status()
+
+        in_f = self._open(in_files)
+        out_f = self._open(out_files)
+
+        s = self.switch(in_f, out_f, self.exit_thread, cachesize, mode)
+        s.start()
+        self.threads.append(s)
+        print "PASS: Start switch"
+
+
+    def exit_threads(self):
+        """
+        Function end all running data switch.
+        """
+        self.exit_thread.set()
+        for th in self.threads:
+            print "join"
+            th.join()
+        self.exit_thread.clear()
+
+        del self.threads[:]
+        for desc in self.files.itervalues():
+            os.close(desc)
+        self.files.clear()
+        print "PASS: All threads finished."
+
+
+    def die(self):
+        """
+        Quit consoleswitch.
+        """
+        self.exit_threads()
+        exit()
+
+
+    def send_loop_init(self, port, length):
+        """
+        Prepares the sender thread. Requires clean thread structure.
+        """
+        self.ports = self._get_port_status()
+        in_f = self._open([port])
+
+        self.threads.append(self.sender(in_f[0], self.exit_thread, length))
+        print "PASS: Sender prepare"
+
+
+    def send_loop(self):
+        """
+        Start sender data transfer. Requires senderprepare run first.
+        """
+        self.threads[0].start()
+        print "PASS: Sender start"
+
+
+    def send(self, port, length=1, mode=True):
+        """
+        Send a data of some length
+
+        @param port: Port to write data
+        @param length: Length of data
+        @param mode: True = loop mode, False = one shoot mode
+        """
+        in_f = self._open([port])
+
+        data = ""
+        while len(data) < length:
+            data += "%c" % random.randrange(255)
+        try:
+            writes = os.write(in_f[0], data)
+        except Exception as inst:
+            print inst
+        if not writes:
+            writes = 0
+        if mode:
+            while (writes < length):
+                try:
+                    writes += os.write(in_f[0], data)
+                except Exception as inst:
+                    print inst
+        if writes >= length:
+            print "PASS: Send data length %d" % writes
+        else:
+            print ("FAIL: Partial send: desired %d, transfered %d" %
+                   (length, writes))
+
+
+    def recv(self, port, length=1, buffer=1024, mode=True):
+        """
+        Recv a data of some length
+
+        @param port: Port to write data
+        @param length: Length of data
+        @param mode: True = loop mode, False = one shoot mode
+        """
+        in_f = self._open([port])
+
+        recvs = ""
+        try:
+            recvs = os.read(in_f[0], buffer)
+        except Exception as inst:
+            print inst
+        if mode:
+            while (len(recvs) < length):
+                try:
+                    recvs += os.read(in_f[0], buffer)
+                except Exception as inst:
+                    print inst
+        if len(recvs) >= length:
+            print "PASS: Recv data length %d" % len(recvs)
+        else:
+            print ("FAIL: Partial recv: desired %d, transfered %d" %
+                   (length, len(recvs)))
+
+
+def compile():
+    """
+    Compile virtio_guest.py to speed up.
+    """
+    import py_compile
+    py_compile.compile(sys.path[0] + "/virtio_guest.py")
+    print "PASS: compile"
+    exit(0)
+
+
+def main():
+    """
+    Main (infinite) loop of virtio_guest.
+    """
+    if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
+        compile()
+
+    virt = virtio_guest()
+    print "PASS: Start"
+
+    while True:
+        str = raw_input()
+        exec str
+
+
+if __name__ == "__main__":
+    main()
diff --git a/client/tests/kvm/tests.cfg.sample b/client/tests/kvm/tests.cfg.sample
index e01406e..ce3e307 100644
--- a/client/tests/kvm/tests.cfg.sample
+++ b/client/tests/kvm/tests.cfg.sample
@@ -58,21 +58,29 @@
         only Fedora.13.64
         only unattended_install.cdrom boot shutdown
         # qemu needs -enable-kvm on the cmdline
-        extra_params = ' -enable-kvm'
+        extra_params += ' -enable-kvm'
 
     # Runs qemu-kvm, f13 64 bit guest OS, install, boot, shutdown
     - @qemu_kvm_f13_quick:
         # We want qemu-kvm for this run
         qemu_binary = /usr/bin/qemu-kvm
         only qcow2
-        only rtl8139
-        only ide
+        only virtio_net
+        only virtio_blk
         only smp2
         only no_pci_assignable
         only smallpages
         only Fedora.13.64
         only unattended_install.cdrom boot shutdown
 
+# You may provide information about the DTM server for WHQL tests here:
+#whql:
+#    server_address = 10.20.30.40
+#    server_shell_port = 10022
+#    server_file_transfer_port = 10023
+# Note that the DTM server must run rss.exe (available under deps/),
+# preferably with administrator privileges.
+
 # Uncomment the following lines to enable abort-on-error mode:
 #abort_on_error = yes
 #kill_vm.* ?= no
diff --git a/client/tests/kvm/tests/build.py b/client/tests/kvm/tests/build.py
index 5a8f3b0..f39371a 100644
--- a/client/tests/kvm/tests/build.py
+++ b/client/tests/kvm/tests/build.py
@@ -495,18 +495,22 @@
         kernel_repo = params.get("git_repo")
         user_repo = params.get("user_git_repo")
         kmod_repo = params.get("kmod_repo")
+        test_repo = params.get("test_git_repo")
 
         kernel_branch = params.get("kernel_branch", "master")
         user_branch = params.get("user_branch", "master")
         kmod_branch = params.get("kmod_branch", "master")
+        test_branch = params.get("test_branch", "master")
 
         kernel_lbranch = params.get("kernel_lbranch", "master")
         user_lbranch = params.get("user_lbranch", "master")
         kmod_lbranch = params.get("kmod_lbranch", "master")
+        test_lbranch = params.get("test_lbranch", "master")
 
         kernel_commit = params.get("kernel_commit", None)
         user_commit = params.get("user_commit", None)
         kmod_commit = params.get("kmod_commit", None)
+        test_commit = params.get("test_commit", None)
 
         kernel_patches = eval(params.get("kernel_patches", "[]"))
         user_patches = eval(params.get("user_patches", "[]"))
@@ -529,8 +533,16 @@
                                                    os.path.basename(patch)))
                 utils.system('patch -p1 %s' % os.path.basename(patch))
 
-        unittest_cfg = os.path.join(userspace_srcdir, 'kvm', 'test', 'x86',
-                                    'unittests.cfg')
+        if test_repo:
+            test_srcdir = os.path.join(self.srcdir, "kvm-unit-tests")
+            kvm_utils.get_git_branch(test_repo, test_branch, test_srcdir,
+                                     test_commit, test_lbranch)
+            unittest_cfg = os.path.join(test_srcdir, 'x86',
+                                        'unittests.cfg')
+            self.test_srcdir = test_srcdir
+        else:
+            unittest_cfg = os.path.join(userspace_srcdir, 'kvm', 'test', 'x86',
+                                        'unittests.cfg')
 
         self.unittest_cfg = None
         if os.path.isfile(unittest_cfg):
diff --git a/client/tests/kvm/tests/ksm_overcommit.py b/client/tests/kvm/tests/ksm_overcommit.py
index 2b49a65..dd4a30d 100644
--- a/client/tests/kvm/tests/ksm_overcommit.py
+++ b/client/tests/kvm/tests/ksm_overcommit.py
@@ -372,6 +372,11 @@
         utils.run("echo 50 > /sys/kernel/mm/ksm/sleep_millisecs")
         utils.run("echo 5000 > /sys/kernel/mm/ksm/pages_to_scan")
         utils.run("echo 1 > /sys/kernel/mm/ksm/run")
+
+        if (os.path.exists("/sys/kernel/mm/transparent_hugepage/enabled")):
+            utils.run("echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled ")
+        if (os.path.exists("/sys/kernel/mm/redhat_transparent_hugepage/enabled")):
+            utils.run("echo 'never' > /sys/kernel/mm/redhat_transparent_hugepage/enabled ")
         new_ksm = True
     else:
         try:
diff --git a/client/tests/kvm/tests/pci_hotplug.py b/client/tests/kvm/tests/pci_hotplug.py
index 2c459d7..55cf666 100644
--- a/client/tests/kvm/tests/pci_hotplug.py
+++ b/client/tests/kvm/tests/pci_hotplug.py
@@ -1,20 +1,22 @@
-import logging, os
+import logging, os, commands, re
 from autotest_lib.client.common_lib import error
 import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_vm
 
 
 def run_pci_hotplug(test, params, env):
     """
-    Test pci devices' hotplug
-    1) PCI add a deivce (NIC / block)
-    2) Compare output of hypervisor command `info pci`
-    3) Compare output of guest command `reference_cmd`
-    4) Verify whether pci_model is shown in `pci_find_cmd`
-    5) Check whether the newly added pci device works fine
-    6) PCI delete the device, verify whether could remove the pci device
+    Test hotplug of PCI devices.
 
-    @param test:   kvm test object
-    @param params: Dictionary with the test parameters
+    (Elements between [] are configurable test parameters)
+    1) PCI add a deivce (NIC / block)
+    2) Compare output of monitor command 'info pci'.
+    3) Compare output of guest command [reference_cmd].
+    4) Verify whether pci_model is shown in [pci_find_cmd].
+    5) Check whether the newly added PCI device works fine.
+    6) PCI delete the device, verify whether could remove the PCI device.
+
+    @param test:   KVM test object.
+    @param params: Dictionary with the test parameters.
     @param env:    Dictionary with test environment.
     """
     vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
@@ -35,26 +37,79 @@
 
     tested_model = params.get("pci_model")
     test_type = params.get("pci_type")
+    image_format = params.get("image_format_stg")
 
-    if test_type == "nic":
-        pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model
-    elif test_type == "block":
-        image_params = kvm_utils.get_sub_dict(params, "stg")
-        image_filename = kvm_vm.get_image_filename(image_params, test.bindir)
-        pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
-                       (image_filename, tested_model))
+    # Probe qemu to verify what is the supported syntax for PCI hotplug
+    cmd_output = vm.monitor.cmd("?")
+    if len(re.findall("\ndevice_add", cmd_output)) > 0:
+        cmd_type = "device_add"
+    elif len(re.findall("\npci_add", cmd_output)) > 0:
+        cmd_type = "pci_add"
+    else:
+        raise error.TestError("Unknow version of qemu")
 
-    # Execute pci_add (should be replaced by a proper monitor method call)
-    add_output = vm.monitor.cmd(pci_add_cmd)
-    if not "OK domain" in add_output:
-        raise error.TestFail("Add device failed. Hypervisor command is: %s. "
-                             "Output: %r" % (pci_add_cmd, add_output))
-    after_add = vm.monitor.info("pci")
+    if cmd_type == "pci_add":
+        if test_type == "nic":
+            pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model
+        elif test_type == "block":
+            image_params = kvm_utils.get_sub_dict(params, "stg")
+            image_filename = kvm_vm.get_image_filename(image_params,
+                                                       test.bindir)
+            pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
+                           (image_filename, tested_model))
+        # Execute pci_add (should be replaced by a proper monitor method call)
+        add_output = vm.monitor.cmd(pci_add_cmd)
+        if not "OK domain" in add_output:
+            raise error.TestFail("Add PCI device failed. "
+                                 "Monitor command is: %s, Output: %r" %
+                                 (pci_add_cmd, add_output))
+        after_add = vm.monitor.info("pci")
+
+    elif cmd_type == "device_add":
+        driver_id = test_type + "-" + kvm_utils.generate_random_id()
+        id = test_type + "-" + kvm_utils.generate_random_id()
+        if test_type == "nic":
+            if tested_model == "virtio":
+                tested_model = "virtio-net-pci"
+            pci_add_cmd = "device_add id=%s,driver=%s" % (id, tested_model)
+
+        elif test_type == "block":
+            image_params = kvm_utils.get_sub_dict(params, "stg")
+            image_filename = kvm_vm.get_image_filename(image_params,
+                                                       test.bindir)
+            if tested_model == "virtio":
+                tested_model = "virtio-blk-pci"
+
+            if tested_model == "scsi":
+                tested_model = "scsi-disk"
+
+            driver_add_cmd = (" __com.redhat_drive_add "
+                              "file=%s,format=%s,id=%s" %
+                              (image_filename, image_format, driver_id))
+            pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
+                           (id, tested_model, driver_id))
+            driver_output = vm.monitor.cmd(driver_add_cmd)
+
+        # Check if the device is support in qemu
+        devices_support = vm.monitor.cmd("%s ?" % cmd_type)
+        if len(re.findall(tested_model, devices_support)) > 0:
+            add_output = vm.monitor.cmd(pci_add_cmd)
+        else:
+            raise error.TestError("%s doesn't support device: %s" %
+                                  (cmd_type, tested_model))
+        after_add = vm.monitor.info("pci")
+
+        if not id in after_add:
+            raise error.TestFail("Add device failed. Monitor command is: %s"
+                                 ". Output: %r" % (pci_add_cmd, add_output))
 
     # Define a helper function to delete the device
     def pci_del(ignore_failure=False):
-        slot_id = "0" + add_output.split(",")[2].split()[1]
-        cmd = "pci_del pci_addr=%s" % slot_id
+        if cmd_type == "pci_add":
+            slot_id = "0" + add_output.split(",")[2].split()[1]
+            cmd = "pci_del pci_addr=%s" % slot_id
+        elif cmd_type == "device_add":
+            cmd = "device_del %s" % id
         # This should be replaced by a proper monitor method call
         vm.monitor.cmd(cmd)
 
@@ -65,14 +120,14 @@
         if (not kvm_utils.wait_for(device_removed, 10, 0, 1)
             and not ignore_failure):
             raise error.TestFail("Failed to hot remove PCI device: %s. "
-                                 "Hypervisor command: %s" % (tested_model,
-                                                             cmd))
+                                 "Monitor command: %s" %
+                                 (tested_model, cmd))
 
     try:
         # Compare the output of 'info pci'
         if after_add == info_pci_ref:
             raise error.TestFail("No new PCI device shown after executing "
-                                 "hypervisor command: 'info pci'")
+                                 "monitor command: 'info pci'")
 
         # Define a helper function to compare the output
         def new_shown():
diff --git a/client/tests/kvm/tests/unittest.py b/client/tests/kvm/tests/unittest.py
index 69c4b43..54e5f73 100644
--- a/client/tests/kvm/tests/unittest.py
+++ b/client/tests/kvm/tests/unittest.py
@@ -73,6 +73,7 @@
         smp = None
         if parser.has_option(t, 'smp'):
             smp = int(parser.get(t, 'smp'))
+            params['smp'] = smp
 
         extra_params = None
         if parser.has_option(t, 'extra_params'):
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
new file mode 100644
index 0000000..008ec63
--- /dev/null
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -0,0 +1,951 @@
+"""
+virtio_console test
+
+@copyright: Red Hat 2010
+"""
+import array, logging, os, random, re, select, shutil, socket, sys, tempfile
+import threading, time
+from collections import deque
+from threading import Thread
+
+import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+from autotest_lib.client.common_lib import error
+
+
+def run_virtio_console(test, params, env):
+    """
+    KVM virtio_console test
+
+    1) Starts VMs with the specified number of virtio console devices
+    2) Start smoke test
+    3) Start loopback test
+    4) Start performance test
+
+    This test uses an auxiliary script, console_switch.py, that is copied to
+    guests. This script has functions to send and write data to virtio console
+    ports. Details of each test can be found on the docstrings for the test_*
+    functions.
+
+    @param test: kvm test object
+    @param params: Dictionary with the test parameters
+    @param env: Dictionary with test environment
+    """
+    class th_send(Thread):
+        """
+        Random data sender thread.
+        """
+        def __init__(self, port, data, event):
+            """
+            @param port: Destination port.
+            @param data: The data intend to be send in a loop.
+            @param event: Exit event.
+            """
+            Thread.__init__(self)
+            self.port = port
+            # FIXME: socket.send(data>>127998) without read blocks thread
+            if len(data) > 102400:
+                data = data[0:102400]
+                logging.error("Data is too long, using only first %d bytes",
+                              len(data))
+            self.data = data
+            self.exitevent = event
+            self.idx = 0
+
+
+        def run(self):
+            logging.debug("th_send %s: run", self.getName())
+            while not self.exitevent.isSet():
+                self.idx += self.port.send(self.data)
+            logging.debug("th_send %s: exit(%d)", self.getName(),
+                          self.idx)
+
+
+    class th_send_check(Thread):
+        """
+        Random data sender thread.
+        """
+        def __init__(self, port, event, queues, blocklen=1024):
+            """
+            @param port: Destination port
+            @param event: Exit event
+            @param queues: Queues for the control data (FIFOs)
+            @param blocklen: Block length
+            """
+            Thread.__init__(self)
+            self.port = port
+            self.queues = queues
+            # FIXME: socket.send(data>>127998) without read blocks thread
+            if blocklen > 102400:
+                blocklen = 102400
+                logging.error("Data is too long, using blocklen = %d",
+                              blocklen)
+            self.blocklen = blocklen
+            self.exitevent = event
+            self.idx = 0
+
+
+        def run(self):
+            logging.debug("th_send_check %s: run", self.getName())
+            too_much_data = False
+            while not self.exitevent.isSet():
+                # FIXME: workaround the problem with qemu-kvm stall when too
+                # much data is sent without receiving
+                for queue in self.queues:
+                    while not self.exitevent.isSet() and len(queue) > 1048576:
+                        too_much_data = True
+                        time.sleep(0.1)
+                ret = select.select([], [self.port], [], 1.0)
+                if ret[1]:
+                    # Generate blocklen of random data add them to the FIFO
+                    # and send them over virtio_console
+                    buf = ""
+                    for i in range(self.blocklen):
+                        ch = "%c" % random.randrange(255)
+                        buf += ch
+                        for queue in self.queues:
+                            queue.append(ch)
+                    target = self.idx + self.blocklen
+                    while not self.exitevent.isSet() and self.idx < target:
+                        idx = self.port.send(buf)
+                        buf = buf[idx:]
+                        self.idx += idx
+            logging.debug("th_send_check %s: exit(%d)", self.getName(),
+                          self.idx)
+            if too_much_data:
+                logging.error("th_send_check: workaround the 'too_much_data'"
+                              "bug")
+
+
+    class th_recv(Thread):
+        """
+        Recieves data and throws it away.
+        """
+        def __init__(self, port, event, blocklen=1024):
+            """
+            @param port: Data source port.
+            @param event: Exit event.
+            @param blocklen: Block length.
+            """
+            Thread.__init__(self)
+            self.port = port
+            self._port_timeout = self.port.gettimeout()
+            self.port.settimeout(0.1)
+            self.exitevent = event
+            self.blocklen = blocklen
+            self.idx = 0
+        def run(self):
+            logging.debug("th_recv %s: run", self.getName())
+            while not self.exitevent.isSet():
+                # TODO: Workaround, it didn't work with select :-/
+                try:
+                    self.idx += len(self.port.recv(self.blocklen))
+                except socket.timeout:
+                    pass
+            self.port.settimeout(self._port_timeout)
+            logging.debug("th_recv %s: exit(%d)", self.getName(), self.idx)
+
+
+    class th_recv_check(Thread):
+        """
+        Random data receiver/checker thread.
+        """
+        def __init__(self, port, buffer, event, blocklen=1024):
+            """
+            @param port: Source port.
+            @param buffer: Control data buffer (FIFO).
+            @param length: Amount of data we want to receive.
+            @param blocklen: Block length.
+            """
+            Thread.__init__(self)
+            self.port = port
+            self.buffer = buffer
+            self.exitevent = event
+            self.blocklen = blocklen
+            self.idx = 0
+
+
+        def run(self):
+            logging.debug("th_recv_check %s: run", self.getName())
+            while not self.exitevent.isSet():
+                ret = select.select([self.port], [], [], 1.0)
+                if ret and (not self.exitevent.isSet()):
+                    buf = self.port.recv(self.blocklen)
+                    if buf:
+                        # Compare the recvd data with the control data
+                        for ch in buf:
+                            ch_ = self.buffer.popleft()
+                            if not ch == ch_:
+                                self.exitevent.set()
+                                logging.error("Failed to recv %dth character",
+                                              self.idx)
+                                logging.error("%s != %s", repr(ch), repr(ch_))
+                                logging.error("Recv = %s", repr(buf))
+                                # sender might change the buffer :-(
+                                time.sleep(1)
+                                ch_ = ""
+                                for buf in self.buffer:
+                                    ch_ += buf
+                                logging.error("Queue = %s", repr(ch_))
+                                raise error.TestFail("th_recv_check: incorrect "
+                                                     "data")
+                        self.idx += len(buf)
+            logging.debug("th_recv_check %s: exit(%d)", self.getName(),
+                          self.idx)
+
+
+    class cpu_load():
+        """
+        Get average cpu load between start and get_load.
+        """
+        def __init__ (self):
+            self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+            self.startTime = 0
+            self.endTime = 0
+
+
+        def _get_cpu_load(self):
+            # Let's see if we can calc system load.
+            try:
+                f = open("/proc/stat", "r")
+                tmp = f.readlines(200)
+                f.close()
+            except:
+                logging.critical("Error reading /proc/stat")
+                error.TestFail("average_cpu_load: Error reading /proc/stat")
+
+            # 200 bytes should be enough because the information we need
+            # is typically stored in the first line
+            # Info about individual processors (not yet supported) is in
+            # the second (third, ...?) line
+            for line in tmp:
+                if line[0:4] == "cpu ":
+                    reg = re.compile('[0-9]+')
+                    load_values = reg.findall(line)
+                    # extract values from /proc/stat
+                    load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+                    for i in range(8):
+                        load[i] = int(load_values[i]) - self.old_load[i]
+
+                    for i in range(8):
+                        self.old_load[i] = int(load_values[i])
+                    return load
+
+
+        def start (self):
+            """
+            Start CPU usage measurement
+            """
+            self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+            self.startTime = time.time()
+            self._get_cpu_load()
+
+
+        def get_load(self):
+            """
+            Get and reset CPU usage
+
+            @return: return group cpu (user[%], system[%], sum[%], testTime[s])
+            """
+            self.endTime = time.time()
+            testTime = self.endTime - self.startTime
+            load = self._get_cpu_load()
+
+            user = load[0] / testTime
+            system = load[2] / testTime
+            sum = user + system
+
+            return (user, system, sum, testTime)
+
+
+    class pid_load():
+        """
+        Get average process cpu load between start and get_load
+        """
+        def __init__ (self, pid, name):
+            self.old_load = [0, 0]
+            self.startTime = 0
+            self.endTime = 0
+            self.pid = pid
+            self.name = name
+
+
+        def _get_cpu_load(self, pid):
+            # Let's see if we can calc system load.
+            try:
+                f = open("/proc/%d/stat" % (pid), "r")
+                line = f.readline()
+                f.close()
+            except:
+                logging.critical("Error reading /proc/%d/stat", pid)
+                error.TestFail("average_process_cpu_load: Error reading "
+                               "/proc/stat")
+            else:
+                reg = re.compile('[0-9]+')
+                load_values = reg.findall(line)
+                del load_values[0:11]
+                # extract values from /proc/stat
+                load = [0, 0]
+                for i in range(2):
+                    load[i] = int(load_values[i]) - self.old_load[i]
+
+                for i in range(2):
+                    self.old_load[i] = int(load_values[i])
+                return load
+
+
+        def start (self):
+            """
+            Start CPU usage measurement
+            """
+            self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+            self.startTime = time.time()
+            self._get_cpu_load(self.pid)
+
+
+        def get_load(self):
+            """
+            Get and reset CPU usage.
+
+            @return: Group cpu
+                    (pid, user[%], system[%], sum[%], testTime[s])
+            """
+            self.endTime = time.time()
+            testTime = self.endTime - self.startTime
+            load = self._get_cpu_load(self.pid)
+
+            user = load[0] / testTime
+            system = load[1] / testTime
+            sum = user + system
+
+            return (self.name, self.pid, user, system, sum, testTime)
+
+
+    def print_load(process, system):
+        """
+        Print load in tabular mode.
+
+        @param process: List of process statistic tuples.
+        @param system: Tuple of system cpu usage.
+        """
+
+        logging.info("%-10s %6s %5s %5s %5s %11s",
+                     "NAME", "PID", "USER", "SYS", "SUM", "TIME")
+        for pr in process:
+            logging.info("%-10s %6d %4.0f%% %4.0f%% %4.0f%% %10.3fs" % pr)
+        logging.info("TOTAL:     ------ %4.0f%% %4.0f%% %4.0f%% %10.3fs" %
+                     system)
+
+
+    def process_stats(stats, scale=1.0):
+        """
+        Process and print the statistic.
+
+        @param stats: List of measured data.
+        """
+        if not stats:
+            return None
+        for i in range((len(stats) - 1), 0, -1):
+            stats[i] = stats[i] - stats[i - 1]
+            stats[i] /= scale
+        stats[0] /= scale
+        stats = sorted(stats)
+        return stats
+
+
+    def init_guest(vm, timeout=2):
+        """
+        Execute virtio_guest.py on guest, wait until it is initialized.
+
+        @param vm: Informations about the guest.
+        @param timeout: Timeout that will be used to verify if the script
+                started properly.
+        """
+        logging.debug("compile virtio_guest.py on guest %s", vm[0].name)
+        vm[1].sendline("python -OO /tmp/virtio_guest.py -c &&"
+                       "echo -n 'PASS: Compile virtio_guest finished' ||"
+                       "echo -n 'FAIL: Compile virtio_guest failed'")
+        (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
+                                                           timeout)
+        if match == 1 or match is None:
+            raise error.TestFail("Command console_switch.py on guest %s failed."
+                                 "\nreturn code: %s\n output:\n%s" %
+                                 (vm[0].name, match, data))
+        logging.debug("Starting virtio_guest.py on guest %s", vm[0].name)
+        vm[1].sendline("python /tmp/virtio_guest.pyo &&"
+                       "echo -n 'PASS: virtio_guest finished' ||"
+                       "echo -n 'FAIL: virtio_guest failed'")
+        (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
+                                                           timeout)
+        if match == 1 or match is None:
+            raise error.TestFail("Command console_switch.py on guest %s failed."
+                                 "\nreturn code: %s\n output:\n%s" %
+                                 (vm[0].name, match, data))
+        # Let the system rest
+        time.sleep(2)
+
+
+    def _on_guest(command, vm, timeout=2):
+        """
+        Execute given command inside the script's main loop, indicating the vm
+        the command was executed on.
+
+        @param command: Command that will be executed.
+        @param vm: Informations about the guest.
+        @param timeout: Timeout used to verify expected output.
+
+        @return: Tuple (match index, data)
+        """
+        logging.debug("Executing '%s' on virtio_guest.py loop, vm: %s," +
+                      "timeout: %s", command, vm[0].name, timeout)
+        vm[1].sendline(command)
+        (match, data) = vm[1].read_until_last_line_matches(["PASS:", 
+                                                    "FAIL:[Failed to execute]"],
+                                                    timeout)
+        return (match, data)
+
+
+    def on_guest(command, vm, timeout=2):
+        """
+        Wrapper around the _on_guest command which executes the command on
+        guest. Unlike _on_guest command when the command fails it raises the
+        test error.
+
+        @param command: Command that will be executed.
+        @param vm: Informations about the guest.
+        @param timeout: Timeout used to verify expected output.
+
+        @return: Tuple (match index, data)
+        """
+        match, data = _on_guest(command, vm, timeout)
+        if match == 1 or match is None:
+            raise error.TestFail("Failed to execute '%s' on virtio_guest.py, "
+                                 "vm: %s, output:\n%s" %
+                                 (command, vm[0].name, data))
+
+        return (match, data)
+
+
+    def socket_readall(sock, read_timeout, mesagesize):
+        """
+        Read everything from the socket.
+
+        @param sock: Socket.
+        @param read_timeout: Read timeout.
+        @param mesagesize: Size of message.
+        """
+        sock_decriptor = sock.fileno()
+        sock.settimeout(read_timeout)
+        message = ""
+        try:
+            while (len(message) < mesagesize):
+                message += sock.recv(mesagesize)
+        except Exception as inst:
+            if (inst.args[0] == "timed out"):
+                logging.debug("Reading timeout")
+            else:
+                logging.debug(inst)
+        sock.setblocking(1)
+        return message
+
+
+    def _guest_exit_threads(vm, send_pts, recv_pts):
+        """
+        Safely executes on_guest("virt.exit_threads()") using workaround of
+        the stuck thread in loopback in mode=virt.LOOP_NONE .
+
+        @param vm: Informations about the guest.
+        @param send_pts: list of possible send sockets we need to work around.
+        @param recv_pts: list of possible recv sockets we need to read-out.
+        """
+        # in LOOP_NONE mode it might stuck in read/write
+        match, tmp = _on_guest("virt.exit_threads()", vm, 10)
+        if match == None:
+            logging.debug("Workaround the stuck thread on guest")
+            # Thread is stucked in read/write
+            for send_pt in send_pts:
+                send_pt[0].sendall(".")
+        elif match != 0:
+            # Something else
+            raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s"
+                                 % (match, tmp))
+
+        # Read-out all remaining data
+        for recv_pt in recv_pts:
+            while select.select([recv_pt[0]], [], [], 0.1)[0]:
+                recv_pt[0].recv(1024)
+
+        # This will cause fail in case anything went wrong.
+        on_guest("print 'PASS: nothing'", vm, 10)
+
+
+    def _vm_create(no_console=3, no_serialport=3):
+        """
+        Creates the VM and connects the specified number of consoles and serial
+        ports.
+
+        @param no_console: Number of desired virtconsoles.
+        @param no_serialport: Number of desired virtserialports.
+        @return: Tuple with (guest information, consoles information)
+                guest informations = [vm, session, tmp_dir]
+                consoles informations = [consoles[], serialports[]]
+        """
+        consoles = []
+        serialports = []
+        tmp_dir = tempfile.mkdtemp(prefix="virtio-console-", dir="/tmp/")
+        if not params.get('extra_params'):
+            params['extra_params'] = ''
+        params['extra_params'] += " -device virtio-serial"
+
+        for i in  range(0, no_console):
+            params['extra_params'] += (" -chardev socket,path=%s/%d,id=vc%d,"
+                                       "server,nowait" % (tmp_dir, i, i))
+            params['extra_params'] += (" -device virtconsole,chardev=vc%d,"
+                                      "name=console-%d,id=c%d" % (i, i, i))
+
+        for i in  range(no_console, no_console + no_serialport):
+            params['extra_params'] += (" -chardev socket,path=%s/%d,id=vs%d,"
+                                       "server,nowait" % (tmp_dir, i, i))
+            params['extra_params'] += (" -device virtserialport,chardev=vs%d,"
+                                       "name=serialport-%d,id=p%d" % (i, i, i))
+
+
+        logging.debug("Booting first guest %s", params.get("main_vm"))
+        kvm_preprocessing.preprocess_vm(test, params, env,
+                                        params.get("main_vm"))
+
+
+        vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
+
+        session = kvm_test_utils.wait_for_login(vm, 0,
+                                         float(params.get("boot_timeout", 240)),
+                                         0, 2)
+
+        # connect the sockets
+        for i in range(0, no_console):
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect("%s/%d" % (tmp_dir, i))
+            consoles.append([sock, "console-%d" % i, "yes"])
+        for i in range(no_console, no_console + no_serialport):
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect("%s/%d" % (tmp_dir, i))
+            serialports.append([sock, "serialport-%d" % i, "no"])
+
+        return [vm, session, tmp_dir], [consoles, serialports]
+
+
+    def test_smoke(vm, consoles, params):
+        """
+        Virtio console smoke test.
+
+        Tests the basic functionalities (poll, read/write with and without
+        connected host, etc.
+
+        @param vm: target virtual machine [vm, session, tmp_dir]
+        @param consoles: a field of virtio ports with the minimum of 2 items
+        @param params: test parameters '$console_type:$data;...'
+        """
+        logging.info("Smoke test: Tests the basic capabilities of "
+                     "virtio_consoles.")
+        # PREPARE
+        for param in params.split(';'):
+            if not param:
+                continue
+            logging.info("test_smoke: params: %s", param)
+            param = param.split(':')
+            if len(param) > 1:
+                data = param[1]
+            else:
+                data = "Smoke test data"
+            param = (param[0] == 'serialport')
+            send_pt = consoles[param][0]
+            recv_pt = consoles[param][1]
+
+            # TEST
+            # Poll (OUT)
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+                     2)
+
+            # Poll (IN, OUT)
+            send_pt[0].sendall("test")
+            for test in [select.POLLIN, select.POLLOUT]:
+                on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+            # Poll (IN HUP)
+            # I store the socket informations and close the socket
+            sock = send_pt[0]
+            send_pt[0] = sock.getpeername()
+            sock.shutdown(2)
+            sock.close()
+            del sock
+            for test in [select.POLLIN, select.POLLHUP]:
+                on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+            # Poll (HUP)
+            on_guest("virt.recv('%s', 4, 1024, False)" % (send_pt[1]), vm, 2)
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLHUP), vm,
+                     2)
+
+            # Reconnect the socket
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect(send_pt[0])
+            send_pt[0] = sock
+            # Redefine socket in consoles
+            consoles[param][0] = send_pt
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+                     2)
+
+            # Read/write without host connected
+            # I store the socket informations and close the socket
+            sock = send_pt[0]
+            send_pt[0] = sock.getpeername()
+            sock.shutdown(2)
+            sock.close()
+            del sock
+            # Read should pass
+            on_guest("virt.recv('%s', 0, 1024, False)" % send_pt[1], vm, 2)
+            # Write should timed-out
+            match, tmp = _on_guest("virt.send('%s', 10, False)"
+                                    % send_pt[1], vm, 2)
+            if match != None:
+                raise error.TestFail("Read on guest while host disconnected "
+                                     "didn't timed out.\nOutput:\n%s"
+                                     % tmp)
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect(send_pt[0])
+            send_pt[0] = sock
+
+            # Redefine socket in consoles
+            consoles[param][0] = send_pt
+            if (send_pt[0].recv(1024) < 10):
+                raise error.TestFail("Didn't received data from guest")
+            # Now the _on_guest("virt.send('%s'... command should be finished
+            on_guest("print 'PASS: nothing'", vm, 2)
+
+            # Non-blocking mode
+            on_guest("virt.blocking('%s', False)" % send_pt[1], vm, 2)
+            # Recv should return FAIL with 0 received data
+            match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)" %
+                                   send_pt[1], vm, 2)
+            if match == 0:
+                raise error.TestFail("Received data even when non were sent\n"
+                                     "Data:\n%s" % tmp)
+            elif match == None:
+                raise error.TestFail("Timed out, probably in blocking mode\n"
+                                     "Data:\n%s" % tmp)
+            elif match != 1:
+                raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s" %
+                                     (match, tmp))
+            send_pt[0].sendall("1234567890")
+            on_guest("virt.recv('%s', 10, 1024, False)" % send_pt[1], vm, 2)
+
+            # Blocking mode
+            on_guest("virt.blocking('%s', True)" % send_pt[1], vm, 2)
+            # Recv should timed out
+            match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)" %
+                                   send_pt[1], vm, 2)
+            if match == 0:
+                raise error.TestFail("Received data even when non were sent\n"
+                                     "Data:\n%s" % tmp)
+            elif match != None:
+                raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s" %
+                                     (match, tmp))
+            send_pt[0].sendall("1234567890")
+            # Now guest received the data end escaped from the recv()
+            on_guest("print 'PASS: nothing'", vm, 2)
+
+            # Basic loopback test
+            on_guest("virt.loopback(['%s'], ['%s'], 1024, virt.LOOP_NONE)" %
+                     (send_pt[1], recv_pt[1]), vm, 2)
+            send_pt[0].sendall(data)
+            tmp = ""
+            i = 0
+            while i <= 10:
+                i += 1
+                ret = select.select([recv_pt[0]], [], [], 1.0)
+                if ret:
+                    tmp += recv_pt[0].recv(1024)
+                if len(tmp) >= len(data):
+                    break
+            if tmp != data:
+                raise error.TestFail("Incorrect data: '%s' != '%s'",
+                                     data, tmp)
+            _guest_exit_threads(vm, [send_pt], [recv_pt])
+
+        return consoles
+
+
+    def test_loopback(vm, consoles, params):
+        """
+        Virtio console loopback test.
+
+        Creates loopback on the vm machine between send_pt and recv_pts
+        ports and sends length amount of data through this connection.
+        It validates the correctness of the data sent.
+
+        @param vm: target virtual machine [vm, session, tmp_dir]
+        @param consoles: a field of virtio ports with the minimum of 2 items
+        @param params: test parameters, multiple recievers allowed.
+            '$source_console_type@buffer_length:
+             $destination_console_type1@$buffer_length:...:
+             $loopback_buffer_length;...'
+        """
+        logging.info("Loopback test: Creates a loopback between sender port "
+                     "and receiving port, send data through this connection, "
+                     "verify data correctness.")
+        # PREPARE
+        for param in params.split(';'):
+            if not param:
+                continue
+            logging.info("test_loopback: params: %s", param)
+            param = param.split(':')
+            idx_serialport = 0
+            idx_console = 0
+            buf_len = []
+            if (param[0].startswith('console')):
+                send_pt = consoles[0][idx_console]
+                idx_console += 1
+            else:
+                send_pt = consoles[1][idx_serialport]
+                idx_serialport += 1
+            if (len(param[0].split('@')) == 2):
+                buf_len.append(int(param[0].split('@')[1]))
+            else:
+                buf_len.append(1024)
+            recv_pts = []
+            for parm in param[1:]:
+                if (parm.isdigit()):
+                    buf_len.append(int(parm))
+                    break   # buf_len is the last portion of param
+                if (parm.startswith('console')):
+                    recv_pts.append(consoles[0][idx_console])
+                    idx_console += 1
+                else:
+                    recv_pts.append(consoles[1][idx_serialport])
+                    idx_serialport += 1
+                if (len(parm[0].split('@')) == 2):
+                    buf_len.append(int(parm[0].split('@')[1]))
+                else:
+                    buf_len.append(1024)
+            # There must be sum(idx_*) consoles + last item as loopback buf_len
+            if len(buf_len) == (idx_console + idx_serialport):
+                buf_len.append(1024)
+
+            if len(recv_pts) == 0:
+                raise error.TestFail("test_loopback: incorrect recv consoles"
+                                     "definition")
+
+            threads = []
+            queues = []
+            for i in range(0, len(recv_pts)):
+                queues.append(deque())
+
+            tmp = "'%s'" % recv_pts[0][1]
+            for recv_pt in recv_pts[1:]:
+                tmp += ", '%s'" % (recv_pt[1])
+            on_guest("virt.loopback(['%s'], [%s], %d, virt.LOOP_POLL)"
+                     % (send_pt[1], tmp, buf_len[-1]), vm, 2)
+
+            exit_event = threading.Event()
+
+            # TEST
+            thread = th_send_check(send_pt[0], exit_event, queues, buf_len[0])
+            thread.start()
+            threads.append(thread)
+
+            for i in range(len(recv_pts)):
+                thread = th_recv_check(recv_pts[i][0], queues[i], exit_event,
+                                       buf_len[i + 1])
+                thread.start()
+                threads.append(thread)
+
+            time.sleep(60)
+            exit_event.set()
+            threads[0].join()
+            tmp = "%d data sent; " % threads[0].idx
+            for thread in threads[1:]:
+                thread.join()
+                tmp += "%d, " % thread.idx
+            logging.info("test_loopback: %s data received and verified",
+                         tmp[:-2])
+
+            # Read-out all remaining data
+            for recv_pt in recv_pts:
+                while select.select([recv_pt[0]], [], [], 0.1)[0]:
+                    recv_pt[0].recv(1024)
+
+            _guest_exit_threads(vm, [send_pt], recv_pts)
+
+            del exit_event
+            del threads[:]
+
+
+    def test_perf(vm, consoles, params):
+        """
+        Tests performance of the virtio_console tunel. First it sends the data
+        from host to guest and than back. It provides informations about
+        computer utilisation and statistic informations about the troughput.
+
+        @param vm: target virtual machine [vm, session, tmp_dir]
+        @param consoles: a field of virtio ports with the minimum of 2 items
+        @param params: test parameters:
+                '$console_type@$buffer_length:$test_duration;...'
+        """
+        logging.info("Performance test: Measure performance for the "
+                     "virtio console tunnel")
+        for param in params.split(';'):
+            if not param:
+                continue
+            logging.info("test_perf: params: %s", param)
+            param = param.split(':')
+            duration = 60.0
+            if len(param) > 1:
+                try:
+                    duration = float(param[1])
+                except:
+                    pass
+            param = param[0].split('@')
+            if len(param) > 1 and param[1].isdigit():
+                buf_len = int(param[1])
+            else:
+                buf_len = 1024
+            param = (param[0] == 'serialport')
+            port = consoles[param][0]
+
+            data = ""
+            for i in range(buf_len):
+                data += "%c" % random.randrange(255)
+
+            exit_event = threading.Event()
+            slice = float(duration)/100
+
+            # HOST -> GUEST
+            on_guest('virt.loopback(["%s"], [], %d, virt.LOOP_NONE)' %
+                     (port[1], buf_len), vm, 2)
+            thread = th_send(port[0], data, exit_event)
+            stats = array.array('f', [])
+            loads = []
+            loads.append(cpu_load())
+            loads.append(pid_load(os.getpid(), 'autotest'))
+            loads.append(pid_load(vm[0].get_pid(), 'VM'))
+
+            for load in loads:
+                load.start()
+            _time = time.time()
+            thread.start()
+            for i in range(100):
+                stats.append(thread.idx)
+                time.sleep(slice)
+            _time = time.time() - _time - duration
+            print_load([loads[1].get_load(), loads[2].get_load()],
+                       loads[0].get_load())
+            exit_event.set()
+            thread.join()
+
+            # Let the guest read-out all the remaining data
+            while not _on_guest("virt.poll('%s', %s)" %
+                                (port[1], select.POLLIN), vm, 2)[0]:
+                time.sleep(1)
+
+            _guest_exit_threads(vm, [port], [])
+
+            if (_time > slice):
+                logging.error(
+                "Test ran %fs longer which is more than one slice", _time)
+            else:
+                logging.debug("Test ran %fs longer", _time)
+            stats = process_stats(stats[1:], slice*1048576)
+            logging.debug("Stats = %s", stats)
+            logging.info("Host -> Guest [MB/s] (min/med/max) = %.3f/%.3f/%.3f",
+                         stats[0], stats[len(stats)/2], stats[-1])
+
+            del thread
+
+            # GUEST -> HOST
+            exit_event.clear()
+            stats = array.array('f', [])
+            on_guest("virt.send_loop_init('%s', %d)" % (port[1], buf_len),
+                     vm, 30)
+            thread = th_recv(port[0], exit_event, buf_len)
+            thread.start()
+            for load in loads:
+                load.start()
+            on_guest("virt.send_loop()", vm, 2)
+            _time = time.time()
+            for i in range(100):
+                stats.append(thread.idx)
+                time.sleep(slice)
+            _time = time.time() - _time - duration
+            print_load([loads[1].get_load(), loads[2].get_load()],
+                       loads[0].get_load())
+            on_guest("virt.exit_threads()", vm, 2)
+            exit_event.set()
+            thread.join()
+            if (_time > slice): # Deviation is higher than 1 slice
+                logging.error(
+                "Test ran %fs longer which is more than one slice", _time)
+            else:
+                logging.debug("Test ran %fs longer" % _time)
+            stats = process_stats(stats[1:], slice*1048576)
+            logging.debug("Stats = %s", stats)
+            logging.info("Guest -> Host [MB/s] (min/med/max) = %.3f/%.3f/%.3f",
+                         stats[0], stats[len(stats)/2], stats[-1])
+
+            del thread
+
+            del exit_event
+            del loads[:]
+
+
+    # INITIALIZE
+    test_smoke_params = params.get('virtio_console_smoke', '')
+    test_loopback_params = params.get('virtio_console_loopback', '')
+    test_perf_params = params.get('virtio_console_perf', '')
+
+    no_serialports = 0
+    no_consoles = 0
+    # consoles required for Smoke test
+    if (test_smoke_params.count('serialport')):
+        no_serialports = max(2, no_serialports)
+    if (test_smoke_params.count('console')):
+        no_consoles = max(2, no_consoles)
+    # consoles required for Loopback test
+    for param in test_loopback_params.split(';'):
+        no_serialports = max(no_serialports, param.count('serialport'))
+        no_consoles = max(no_consoles, param.count('console'))
+    # consoles required for Performance test
+    if (test_perf_params.count('serialport')):
+        no_serialports = max(1, no_serialports)
+    if (test_perf_params.count('console')):
+        no_consoles = max(1, no_consoles)
+
+    if (no_serialports + no_consoles) == 0:
+        raise error.TestFail("No tests defined, probably incorrect "
+                             "configuration in tests_base.cfg")
+
+    vm, consoles = _vm_create(no_consoles, no_serialports)
+
+    # Copy allocator.py into guests
+    pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
+    vksmd_src = os.path.join(pwd, "scripts/virtio_guest.py")
+    dst_dir = "/tmp"
+    if not vm[0].copy_files_to(vksmd_src, dst_dir):
+        raise error.TestFail("copy_files_to failed %s" % vm[0].name)
+
+    # ACTUAL TESTING
+    # Defines all available consoles; tests udev and sysfs
+    conss = []
+    for mode in consoles:
+        for cons in mode:
+            conss.append(cons[1:3])
+    init_guest(vm, 10)
+    on_guest("virt.init(%s)" % (conss), vm, 10)
+
+    consoles = test_smoke(vm, consoles, test_smoke_params)
+    test_loopback(vm, consoles, test_loopback_params)
+    test_perf(vm, consoles, test_perf_params)
+
+    # CLEANUP
+    vm[1].close()
+    vm[0].destroy(gracefully=False)
+    shutil.rmtree(vm[2])
+
diff --git a/client/tests/kvm/tests/whql_client_install.py b/client/tests/kvm/tests/whql_client_install.py
new file mode 100644
index 0000000..d866df7
--- /dev/null
+++ b/client/tests/kvm/tests/whql_client_install.py
@@ -0,0 +1,116 @@
+import logging, time, os, re
+from autotest_lib.client.common_lib import error
+import kvm_subprocess, kvm_test_utils, kvm_utils, rss_file_transfer
+
+
+def run_whql_client_install(test, params, env):
+    """
+    WHQL DTM client installation:
+    1) Log into the guest (the client machine) and into a DTM server machine
+    2) Stop the DTM client service (wttsvc) on the client machine
+    3) Delete the client machine from the server's data store
+    4) Rename the client machine (give it a randomly generated name)
+    5) Move the client machine into the server's workgroup
+    6) Reboot the client machine
+    7) Install the DTM client software
+
+    @param test: kvm test object
+    @param params: Dictionary with the test parameters
+    @param env: Dictionary with test environment.
+    """
+    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
+    session = kvm_test_utils.wait_for_login(vm, 0, 240)
+
+    # Collect test params
+    server_address = params.get("server_address")
+    server_shell_port = int(params.get("server_shell_port"))
+    server_file_transfer_port = int(params.get("server_file_transfer_port"))
+    server_studio_path = params.get("server_studio_path", "%programfiles%\\ "
+                                    "Microsoft Driver Test Manager\\Studio")
+    server_username = params.get("server_username")
+    server_password = params.get("server_password")
+    dsso_delete_machine_binary = params.get("dsso_delete_machine_binary",
+                                            "deps/whql_delete_machine_15.exe")
+    dsso_delete_machine_binary = kvm_utils.get_path(test.bindir,
+                                                    dsso_delete_machine_binary)
+    install_timeout = float(params.get("install_timeout", 600))
+    install_cmd = params.get("install_cmd")
+    wtt_services = params.get("wtt_services")
+
+    # Stop WTT service(s) on client
+    for svc in wtt_services.split():
+        kvm_test_utils.stop_windows_service(session, svc)
+
+    # Copy dsso_delete_machine_binary to server
+    rss_file_transfer.upload(server_address, server_file_transfer_port,
+                             dsso_delete_machine_binary, server_studio_path,
+                             timeout=60)
+
+    # Open a shell session with server
+    server_session = kvm_utils.remote_login("nc", server_address,
+                                            server_shell_port, "", "",
+                                            session.prompt, session.linesep)
+
+    # Get server and client information
+    cmd = "echo %computername%"
+    server_name = server_session.get_command_output(cmd).strip()
+    client_name = session.get_command_output(cmd).strip()
+    cmd = "wmic computersystem get domain"
+    server_workgroup = server_session.get_command_output(cmd).strip()
+    server_workgroup = server_workgroup.splitlines()[-1]
+    regkey = r"HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
+    cmd = "reg query %s /v Domain" % regkey
+    server_dns_suffix = server_session.get_command_output(cmd).split()[-1]
+
+    # Delete the client machine from the server's data store (if it's there)
+    server_session.get_command_output("cd %s" % server_studio_path)
+    cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary),
+                        server_name, client_name)
+    server_session.get_command_output(cmd, print_func=logging.info)
+    server_session.close()
+
+    # Rename the client machine
+    client_name = "autotest_%s" % kvm_utils.generate_random_string(4)
+    logging.info("Renaming client machine to '%s'" % client_name)
+    cmd = ('wmic computersystem where name="%%computername%%" rename name="%s"'
+           % client_name)
+    if session.get_command_status(cmd, timeout=600) != 0:
+        raise error.TestError("Could not rename the client machine")
+
+    # Join the server's workgroup
+    logging.info("Joining workgroup '%s'" % server_workgroup)
+    cmd = ('wmic computersystem where name="%%computername%%" call '
+           'joindomainorworkgroup name="%s"' % server_workgroup)
+    if session.get_command_status(cmd, timeout=600) != 0:
+        raise error.TestError("Could not change the client's workgroup")
+
+    # Set the client machine's DNS suffix
+    logging.info("Setting DNS suffix to '%s'" % server_dns_suffix)
+    cmd = "reg add %s /v Domain /d %s /f" % (regkey, server_dns_suffix)
+    if session.get_command_status(cmd, timeout=300) != 0:
+        raise error.TestError("Could not set the client's DNS suffix")
+
+    # Reboot
+    session = kvm_test_utils.reboot(vm, session)
+
+    # Access shared resources on the server machine
+    logging.info("Attempting to access remote share on server")
+    cmd = r"net use \\%s /user:%s %s" % (server_name, server_username,
+                                         server_password)
+    end_time = time.time() + 120
+    while time.time() < end_time:
+        s = session.get_command_status(cmd)
+        if s == 0:
+            break
+        time.sleep(5)
+    else:
+        raise error.TestError("Could not access server share from client "
+                              "machine")
+
+    # Install
+    logging.info("Installing DTM client (timeout=%ds)", install_timeout)
+    install_cmd = r"cmd /c \\%s\%s" % (server_name, install_cmd.lstrip("\\"))
+    if session.get_command_status(install_cmd, timeout=install_timeout) != 0:
+        raise error.TestError("Client installation failed")
+
+    session.close()
diff --git a/client/tests/kvm/tests/whql_submission.py b/client/tests/kvm/tests/whql_submission.py
new file mode 100644
index 0000000..1fe27c9
--- /dev/null
+++ b/client/tests/kvm/tests/whql_submission.py
@@ -0,0 +1,188 @@
+import logging, time, os, re
+from autotest_lib.client.common_lib import error
+import kvm_subprocess, kvm_test_utils, kvm_utils, rss_file_transfer
+
+
+def run_whql_submission(test, params, env):
+    """
+    WHQL submission test:
+    1) Log into the guest (the client machine) and into a DTM server machine
+    2) Copy the automation program binary (dsso_test_binary) to the server machine
+    3) Run the automation program
+    4) Pass the program all relevant parameters (e.g. device_data)
+    5) Wait for the program to terminate
+    6) Parse and report job results
+    (logs and HTML reports are placed in test.bindir)
+
+    @param test: kvm test object
+    @param params: Dictionary with the test parameters
+    @param env: Dictionary with test environment.
+    """
+    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
+    session = kvm_test_utils.wait_for_login(vm, 0, 240)
+
+    # Collect parameters
+    server_address = params.get("server_address")
+    server_shell_port = int(params.get("server_shell_port"))
+    server_file_transfer_port = int(params.get("server_file_transfer_port"))
+    server_studio_path = params.get("server_studio_path", "%programfiles%\\ "
+                                    "Microsoft Driver Test Manager\\Studio")
+    dsso_test_binary = params.get("dsso_test_binary",
+                                  "deps/whql_submission_15.exe")
+    dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary)
+    test_device = params.get("test_device")
+    job_filter = params.get("job_filter", ".*")
+    test_timeout = float(params.get("test_timeout", 600))
+    wtt_services = params.get("wtt_services")
+
+    # Restart WTT service(s) on the client
+    logging.info("Restarting WTT services on client")
+    for svc in wtt_services.split():
+        kvm_test_utils.stop_windows_service(session, svc)
+    for svc in wtt_services.split():
+        kvm_test_utils.start_windows_service(session, svc)
+
+    # Copy dsso_test_binary to the server
+    rss_file_transfer.upload(server_address, server_file_transfer_port,
+                             dsso_test_binary, server_studio_path, timeout=60)
+
+    # Open a shell session with the server
+    server_session = kvm_utils.remote_login("nc", server_address,
+                                            server_shell_port, "", "",
+                                            session.prompt, session.linesep)
+
+    # Get the computer names of the server and client
+    cmd = "echo %computername%"
+    server_name = server_session.get_command_output(cmd).strip()
+    client_name = session.get_command_output(cmd).strip()
+    session.close()
+
+    # Run the automation program on the server
+    server_session.get_command_output("cd %s" % server_studio_path)
+    cmd = "%s %s %s %s %s %s" % (os.path.basename(dsso_test_binary),
+                                 server_name,
+                                 client_name,
+                                 "%s_pool" % client_name,
+                                 "%s_submission" % client_name,
+                                 test_timeout)
+    server_session.sendline(cmd)
+
+    # Helper function: wait for a given prompt and raise an exception if an
+    # error occurs
+    def find_prompt(prompt):
+        m, o = server_session.read_until_last_line_matches(
+            [prompt, server_session.prompt], print_func=logging.info,
+            timeout=600)
+        if m != 0:
+            errors = re.findall("^Error:.*$", o, re.I | re.M)
+            if errors:
+                raise error.TestError(errors[0])
+            else:
+                raise error.TestError("Error running automation program: could "
+                                      "not find '%s' prompt" % prompt)
+
+    # Tell the automation program which device to test
+    find_prompt("Device to test:")
+    server_session.sendline(test_device)
+
+    # Tell the automation program which jobs to run
+    find_prompt("Jobs to run:")
+    server_session.sendline(job_filter)
+
+    # Give the automation program all the device data supplied by the user
+    find_prompt("DeviceData name:")
+    for dd in kvm_utils.get_sub_dict_names(params, "device_data"):
+        dd_params = kvm_utils.get_sub_dict(params, dd)
+        if dd_params.get("dd_name") and dd_params.get("dd_data"):
+            server_session.sendline(dd_params.get("dd_name"))
+            server_session.sendline(dd_params.get("dd_data"))
+    server_session.sendline()
+
+    # Give the automation program all the descriptor information supplied by
+    # the user
+    find_prompt("Descriptor path:")
+    for desc in kvm_utils.get_sub_dict_names(params, "descriptors"):
+        desc_params = kvm_utils.get_sub_dict(params, desc)
+        if desc_params.get("desc_path"):
+            server_session.sendline(desc_params.get("desc_path"))
+    server_session.sendline()
+
+    # Wait for the automation program to terminate
+    m, o = server_session.read_up_to_prompt(print_func=logging.info,
+                                            timeout=test_timeout + 300)
+    # (test_timeout + 300 is used here because the automation program is
+    # supposed to terminate cleanly on its own when test_timeout expires)
+    server_session.close()
+
+    # Look for test results in the automation program's output
+    result_summaries = re.findall(r"---- \[.*?\] ----", o, re.DOTALL)
+    if not result_summaries:
+        raise error.TestError("The automation program did not return any "
+                              "results")
+    results = result_summaries[-1].strip("-")
+    results = eval("".join(results.splitlines()))
+
+    # Download logs and HTML reports from the server
+    for i, r in enumerate(results):
+        if "report" in r:
+            try:
+                rss_file_transfer.download(server_address,
+                                           server_file_transfer_port,
+                                           r["report"], test.debugdir)
+            except rss_file_transfer.FileTransferNotFoundError:
+                pass
+        if "logs" in r:
+            try:
+                rss_file_transfer.download(server_address,
+                                           server_file_transfer_port,
+                                           r["logs"], test.debugdir)
+            except rss_file_transfer.FileTransferNotFoundError:
+                pass
+            else:
+                try:
+                    # Create symlinks to test log dirs to make it easier
+                    # to access them (their original names are not human
+                    # readable)
+                    link_name = "logs_%s" % r["report"].split("\\")[-1]
+                    link_name = link_name.replace(" ", "_")
+                    link_name = link_name.replace("/", "_")
+                    os.symlink(r["logs"].split("\\")[-1],
+                               os.path.join(test.debugdir, link_name))
+                except (KeyError, OSError):
+                    pass
+
+    # Print result summary
+    logging.info("")
+    logging.info("Result summary:")
+    name_length = max(len(r.get("job", "")) for r in results)
+    fmt = "%%-6s %%-%ds %%-15s %%-8s %%-8s %%-8s %%-15s" % name_length
+    logging.info(fmt % ("ID", "Job", "Status", "Pass", "Fail", "NotRun",
+                        "NotApplicable"))
+    logging.info(fmt % ("--", "---", "------", "----", "----", "------",
+                        "-------------"))
+    for r in results:
+        logging.info(fmt % (r.get("id"), r.get("job"), r.get("status"),
+                            r.get("pass"), r.get("fail"), r.get("notrun"),
+                            r.get("notapplicable")))
+    logging.info("(see logs and HTML reports in %s)" % test.debugdir)
+
+    # Kill the VM and fail if the automation program did not terminate on time
+    if not m:
+        vm.destroy()
+        raise error.TestFail("The automation program did not terminate "
+                             "on time")
+
+    # Fail if there are failed or incomplete jobs (kill the VM if there are
+    # incomplete jobs)
+    failed_jobs = [r.get("job") for r in results
+                   if r.get("status", "").lower() == "investigate"]
+    running_jobs = [r.get("job") for r in results
+                    if r.get("status", "").lower() == "inprogress"]
+    errors = []
+    if failed_jobs:
+        errors += ["Jobs failed: %s." % failed_jobs]
+    if running_jobs:
+        vm.destroy()
+        errors += ["Jobs did not complete on time: %s." % running_jobs]
+    if errors:
+        raise error.TestFail(" ".join(errors))
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index cb727c4..167e86d 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -90,7 +90,6 @@
         pre_command += " scripts/unattended.py;"
         extra_params += " -boot d"
         guest_port_unattended_install = 12323
-        floppy = "images/floppy.img"
         kernel = vmlinuz
         initrd = initrd.img
         nic_mode = tap
@@ -205,34 +204,66 @@
 
     - timedrift:    install setup unattended_install.cdrom
         variants:
-            - with_load:
-                type = timedrift
-                # Pin the VM and host load to CPU #0
-                cpu_mask = 0x1
-                # Set the load and rest durations
-                load_duration = 20
-                rest_duration = 20
-                # Fail if the drift after load is higher than 50%
-                drift_threshold = 50
-                # Fail if the drift after the rest period is higher than 10%
-                drift_threshold_after_rest = 10
-                # For now, make sure this test is executed alone
-                used_cpus = 100
-            - with_migration:
-                type = timedrift_with_migration
-                migration_iterations = 3
-                drift_threshold = 10
-                drift_threshold_single = 3
-            - with_reboot:
-                type = timedrift_with_reboot
-                reboot_iterations = 1
-                drift_threshold = 10
-                drift_threshold_single = 3
-            - with_stop:
-                type = timedrift_with_stop
-                stop_interations = 1
-                drift_threshold = 10
-                drift_threshold_single = 3
+            - ntp:
+                variants:
+                    - with_load:
+                        type = timedrift
+                        # Pin the VM and host load to CPU #0
+                        cpu_mask = 0x1
+                        # Set the load and rest durations
+                        load_duration = 20
+                        rest_duration = 20
+                        # Fail if the drift after load is higher than 50%
+                        drift_threshold = 50
+                        # Fail if the drift after the rest period is higher than 10%
+                        drift_threshold_after_rest = 10
+                        # For now, make sure this test is executed alone
+                        used_cpus = 100
+                    - with_migration:
+                        type = timedrift_with_migration
+                        migration_iterations = 3
+                        drift_threshold = 10
+                        drift_threshold_single = 3
+                    - with_reboot:
+                        type = timedrift_with_reboot
+                        reboot_iterations = 1
+                        drift_threshold = 10
+                        drift_threshold_single = 3
+                    - with_stop:
+                        type = timedrift_with_stop
+                        stop_interations = 1
+                        drift_threshold = 10
+                        drift_threshold_single = 3
+            - date:
+                variants:
+                    - with_load:
+                        type = timedrift
+                        # Pin the VM and host load to CPU #0
+                        cpu_mask = 0x1
+                        # Set the load and rest durations
+                        load_duration = 20
+                        rest_duration = 20
+                        # Fail if the drift after load is higher than 50%
+                        drift_threshold = 50
+                        # Fail if the drift after the rest period is higher than 10%
+                        drift_threshold_after_rest = 10
+                        # For now, make sure this test is executed alone
+                        used_cpus = 100
+                    - with_migration:
+                        type = timedrift_with_migration
+                        migration_iterations = 3
+                        drift_threshold = 10
+                        drift_threshold_single = 3
+                    - with_reboot:
+                        type = timedrift_with_reboot
+                        reboot_iterations = 1
+                        drift_threshold = 10
+                        drift_threshold_single = 3
+                    - with_stop:
+                        type = timedrift_with_stop
+                        stop_interations = 1
+                        drift_threshold = 10
+                        drift_threshold_single = 3
 
     - balloon_check:  install setup unattended_install.cdrom
         type = balloon_check
@@ -286,6 +317,90 @@
         iozone_cmd = "D:\IOzone\iozone.exe -a"
         iozone_timeout = 3600
 
+    - @whql:         install setup unattended_install.cdrom
+        nic_mode = tap
+        # Replace this with the address of an installed DTM server
+        server_address = 10.20.30.40
+        # The server should run rss.exe like a regular Windows VM, preferably
+        # with administrator privileges (or at least with permission to write
+        # to the DTM studio directory)
+        server_shell_port = 10022
+        server_file_transfer_port = 10023
+        server_studio_path = %programfiles%\Microsoft Driver Test Manager\Studio
+        wtt_services = wttsvc
+        variants:
+            - whql_client_install:
+                type = whql_client_install
+                dsso_delete_machine_binary = deps/whql_delete_machine_15.exe
+                # The username and password are required for accessing the DTM client
+                # installer binary shared by the server
+                server_username = administrator
+                server_password = 1q2w3eP
+                # This path refers to a shared directory on the server
+                # (the final cmd will be something like \\servername\DTMInstall\...)
+                install_cmd = \DTMInstall\Client\Setup.exe /passive
+                install_timeout = 3600
+            - whql_submission:    whql_client_install
+                type = whql_submission
+                extra_params += " -snapshot"
+                dsso_test_binary = deps/whql_submission_15.exe
+                test_timeout = 3600
+                device_data = cat0 cat1 cat2 cat3 logoarch logoos whqlos whqlqual prog desc filter virt
+                descriptors = desc1 desc2 desc3
+                # DeviceData names
+                dd_name_cat0     = Category
+                dd_name_cat1     = Category
+                dd_name_cat2     = Category
+                dd_name_cat3     = Category
+                dd_name_logoarch = LogoProcessorArchitecture
+                dd_name_logoos   = LogoOperatingSystem
+                dd_name_whqlos   = WhqlOs
+                dd_name_whqlqual = WhqlQualification
+                dd_name_prog     = LogoProgramId
+                dd_name_desc     = LogoProgramDescription
+                dd_name_filter   = WDKFilterAttribute
+                dd_name_virt     = ParaVirtualizationDriver
+                # Common DeviceData data
+                dd_data_filter   = FilterIfNoInf
+                dd_data_virt     = True
+                variants:
+                    - keyboard:
+                        # test_device is a regular expression that should match a device's
+                        # name as it appears in device manager.  The first device that matches
+                        # is used.
+                        test_device = keyboard
+                        # Set timeout to 10 hours
+                        test_timeout = 36000
+                        dd_data_cat0 = Input\Keyboard
+                        dd_data_cat1 = Device Fundamentals
+                        dd_data_cat2 = System Fundamentals\Dynamic Partitioning
+                        dd_data_prog = InputKbd
+                        dd_data_desc = Input > Keyboard
+                    - hdd:
+                        test_device = qemu harddisk
+                        device_data += " ex0 ex1 ex2 ex3"
+                        dd_data_cat0 = Storage\Device Class\Disk\Disk
+                        dd_data_cat1 = Storage\Device Class\Disk\Fixed
+                        dd_data_cat2 = Storage\Device Class\Disk\Bus\ATA
+                        dd_data_cat3 = Device Fundamentals
+                        dd_data_prog = StorHDD
+                        dd_data_desc = Storage > Hard Disk Drive (HDD)
+                        dd_name_ex0 = Storage_bus_type
+                        dd_data_ex0 = ATA/ATAPI
+                        dd_name_ex1 = Hybrid_HDD_Support
+                        dd_data_ex1 = 0
+                        dd_name_ex2 = Non_Rotating_Media
+                        dd_data_ex2 = 0
+                        dd_name_ex3 = Secure_Storage
+                        dd_data_ex3 = 0
+                        variants:
+                            - full:
+                                # Yes, 100 hours, this is not a mistake
+                                test_timeout = 360000
+                            - syscache_test:
+                                job_filter = syscache test
+                                test_timeout = 7200
+
     - guest_s4:     install setup unattended_install.cdrom
         type = guest_s4
         check_s4_support_cmd = grep -q disk /sys/power/state
@@ -378,9 +493,24 @@
                 ksm_mode = "serial"
             - ksm_parallel:
                 ksm_mode = "parallel"
+
     - iofuzz:
         type = iofuzz
 
+    - virtio_console:
+        vms = ''
+        type = virtio_console
+        # smoke params - $console_type:data_string
+        # FIXME: test_smoke doesn't work with console yet (virtio_console bug)
+        # "serialport;console:Custom data"
+        virtio_console_smoke = "serialport"
+        # loopback params - '$source_console_type@buffer_length:$destination_console_type1@buffer_length:...:$loopback_buffer_length;...'
+        virtio_console_loopback = "serialport:serialport;serialport@1024:serialport@32:console@1024:console@8:16"
+        # perf params - $console_type@buffer_length:$test_duration
+        # FIXME: test_perf doesn't work with console yet (virtio_console bug)
+        # virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+        virtio_console_perf = "serialport;serialport@1000000:120"
+
     # This unit test module is for older branches of KVM that use the
     # kvmctl test harness (such as the code shipped with RHEL 5.x)
     - unit_test_kvmctl:
@@ -490,7 +620,7 @@
         nic_model = rtl8139
     - e1000:
         nic_model = e1000
-    - virtio:
+    - virtio_net:
         nic_model = virtio
 
 
@@ -498,7 +628,7 @@
 variants:
     # Linux section
     - @Linux:
-        no autoit iozone_windows
+        no autoit iozone_windows whql
         shutdown_command = shutdown -h now
         reboot_command = shutdown -r now
         status_test_command = echo $?
@@ -511,6 +641,12 @@
         mem_chk_cmd = dmidecode -t 17 | awk -F: '/Size/ {print $2}'
         mem_chk_cur_cmd = grep MemTotal /proc/meminfo
         cpu_chk_cmd = grep -c processor /proc/cpuinfo
+        unattended_install.cdrom:
+            # If you want to use floppy to hold kickstarts,
+            # comment the 3 lines below
+            cdroms += " unattended"
+            drive_index_unattended = 1
+            drive_index_cd1 = 2
         timedrift:
             extra_params += " -no-kvm-pit-reinjection"
             time_command = date +'TIME: %a %m/%d/%Y %H:%M:%S.%N'
@@ -521,6 +657,14 @@
             guest_load_stop_command = "killall -9 dd"
             host_load_command = "bzip2 -c --best /dev/urandom > /dev/null"
             host_load_instances = 8
+            ntp:
+                time_command = "ntpdate -d -q ns1.nay.redhat.com"
+                time_filter_re = "originate timestamp:.*, (.\w+\s+\d+\s+\d+\s+\d+:\d+:\d+)\.(.\d+)"
+                time_format = "%b %d %Y %H:%M:%S"
+            date:
+                time_command = date +'TIME: %a %m/%d/%Y %H:%M:%S.%N'
+                time_filter_re = "(?:TIME: \w\w\w )(.{19})(?:\.\d\d)"
+                time_format = "%m/%d/%Y %H:%M:%S"
 
         variants:
             - Fedora:
@@ -533,7 +677,10 @@
                     tftp = "images/tftpboot"
                     bootp = "/pxelinux.0"
                     extra_params += " -boot cn"
-                    kernel_args = "ks=floppy nicdelay=60 console=ttyS0,115200 console=tty0"
+                    # You have to use ks=floppy if you want to use floppies to
+                    # hold your kickstart file
+                    #kernel_args = "ks=floppy nicdelay=60 console=ttyS0,115200 console=tty0"
+                    kernel_args = "ks=cdrom nicdelay=60 console=ttyS0,115200 console=tty0"
 
                 variants:
                     - 8.32:
@@ -547,7 +694,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-8.ks
                             tftp = images/f8-32/tftpboot
-                            floppy = images/f8-32/floppy.img
+                            #floppy = images/f8-32/ks.vfd
+                            cdrom_unattended = images/f8-32/ks.iso
 
                     - 8.64:
                         no setup
@@ -560,7 +708,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-8.ks
                             tftp = images/f8-64/tftpboot
-                            floppy = images/f8-64/floppy.img
+                            #floppy = images/f8-64/ks.vfd
+                            cdrom_unattended = images/f8-64/ks.iso
 
                     - 9.32:
                         image_name = f9-32
@@ -572,7 +721,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-9.ks
                             tftp = images/f9-32/tftpboot
-                            floppy = images/f9-32/floppy.img
+                            #floppy = images/f9-32/ks.vfd
+                            cdrom_unattended = images/f9-32/ks.iso
 
                     - 9.64:
                         image_name = f9-64
@@ -584,7 +734,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-9.ks
                             tftp = images/f9-64/tftpboot
-                            floppy = images/f9-64/floppy.img
+                            #floppy = images/f9-64/ks.vfd
+                            cdrom_unattended = images/f9-64/ks.iso
 
                     - 10.32:
                         image_name = f10-32
@@ -594,7 +745,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-10.ks
                             tftp = images/f10-32/tftpboot
-                            floppy = images/f10-32/floppy.img
+                            #floppy = images/f10-32/ks.vfd
+                            cdrom_unattended = images/f10-32/ks.iso
 
                     - 10.64:
                         image_name = f10-64
@@ -604,7 +756,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-10.ks
                             tftp = images/f10-64/tftpboot
-                            floppy = images/f10-64/floppy.img
+                            #floppy = images/f10-64/ks.vfd
+                            cdrom_unattended = images/f10-64/ks.iso
 
                     - 11.32:
                         image_name = f11-32
@@ -616,7 +769,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-11.ks
                             tftp = images/f11-32/tftpboot
-                            floppy = images/f11-32/floppy.img
+                            #floppy = images/f11-32/ks.vfd
+                            cdrom_unattended = images/f11-32/ks.iso
 
                     - 11.64:
                         image_name = f11-64
@@ -626,7 +780,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-11.ks
                             tftp = images/f11-64/tftpboot
-                            floppy = images/f11-64/floppy.img
+                            #floppy = images/f11-64/ks.vfd
+                            cdrom_unattended = images/f11-64/ks.iso
 
                     - 12.32:
                         image_name = f12-32
@@ -636,7 +791,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-12.ks
                             tftp = images/f12-32/tftpboot
-                            floppy = images/f12-32/floppy.img
+                            #floppy = images/f12-32/ks.vfd
+                            cdrom_unattended = images/f12-32/ks.iso
 
                     - 12.64:
                         image_name = f12-64
@@ -646,27 +802,30 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/Fedora-12.ks
                             tftp = images/f12-64/tftpboot
-                            floppy = images/f12-64/floppy.img
+                            #floppy = images/f12-64/ks.vfd
+                            cdrom_unattended = images/f12-64/ks.iso
 
                     - 13.32:
                         image_name = f13-32
                         cdrom_cd1 = linux/Fedora-13-i386-DVD.iso
                         md5sum = 212fec517c2629b4b5eaf3662ac13136
                         md5sum_1m = 4e1578a6ed5a6e7cd03b8fb074030746
-                        unattended_install:
+                        unattended_install.cdrom:
                             unattended_file = unattended/Fedora-13.ks
                             tftp = images/f13-32/tftpboot
-                            floppy = images/f13-32/floppy.img
+                            #floppy = images/f13-32/ks.vfd
+                            cdrom_unattended = images/f13-32/ks.iso
 
                     - 13.64:
                         image_name = f13-64
                         cdrom_cd1 = linux/Fedora-13-x86_64-DVD.iso
                         md5sum = 6fbae6379cf27f36e1f2c7827ba7dc35
                         md5sum_1m = 68821b9de4d3b5975d6634334e7f47a6
-                        unattended_install:
+                        unattended_install.cdrom:
                             unattended_file = unattended/Fedora-13.ks
                             tftp = images/f13-64/tftpboot
-                            floppy = images/f13-64/floppy.img
+                            #floppy = images/f13-64/ks.vfd
+                            cdrom_unattended = images/f13-64/ks.iso
 
 
             - DSL-4.2.5:
@@ -695,7 +854,10 @@
                     tftp = "images/tftpboot"
                     bootp = "/pxelinux.0"
                     extra_params += " -boot cn"
-                    kernel_args = "autoyast=floppy console=ttyS0,115200 console=tty0"
+                    # You have to use autoyast=floppy if you want to use floppies to
+                    # hold your autoyast file
+                    #kernel_args = "autoyast=floppy console=ttyS0,115200 console=tty0"
+                    kernel_args = "autoyast=cdrom console=ttyS0,115200 console=tty0"
                     post_install_delay = 10
 
                 variants:
@@ -720,7 +882,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-0-64/tftpboot
-                            floppy = images/opensuse-11-0-64/floppy.img
+                            #floppy = images/opensuse-11-0-64/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-0-64/autoyast.iso
                             pxe_dir = boot/x86_64/loader
 
                     - 11.1.32:
@@ -733,7 +896,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-1-32/tftpboot
-                            floppy = images/opensuse-11-1-32/floppy.img
+                            #floppy = images/opensuse-11-1-32/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-1-32/autoyast.iso
                             pxe_dir = boot/i386/loader
 
                     - 11.1.64:
@@ -746,7 +910,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-1-64/tftpboot
-                            floppy = images/opensuse-11-1-64/floppy.img
+                            #floppy = images/opensuse-11-1-64/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-1-64/autoyast.iso
                             pxe_dir = boot/x86_64/loader
 
                     - 11.2.32:
@@ -757,7 +922,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-2-32/tftpboot
-                            floppy = images/opensuse-11-2-32/floppy.img
+                            #floppy = images/opensuse-11-2-32/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-2-32/autoyast.iso
                             pxe_dir = boot/i386/loader
 
                     - 11.2.64:
@@ -768,7 +934,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-2-64/tftpboot
-                            floppy = images/opensuse11-2-64/floppy.img
+                            #floppy = images/opensuse11-2-64/autoyast.vfd
+                            cdrom_unattended = images/opensuse11-2-64/autoyast.iso
                             pxe_dir = boot/x86_64/loader
 
                     - 11.3.32:
@@ -779,7 +946,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-3-32/tftpboot
-                            floppy = images/opensuse-11-3-32/floppy.img
+                            #floppy = images/opensuse-11-3-32/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-3-32/autoyast.iso
                             pxe_dir = boot/i386/loader
 
                     - 11.3.64:
@@ -790,7 +958,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/OpenSUSE-11.xml
                             tftp = images/opensuse-11-3-64/tftpboot
-                            floppy = images/opensuse-11-3-64/floppy.img
+                            #floppy = images/opensuse-11-3-64/autoyast.vfd
+                            cdrom_unattended = images/opensuse-11-3-64/autoyast.iso
                             pxe_dir = boot/x86_64/loader
 
             - SLES:
@@ -800,7 +969,10 @@
                     pxe_initrd = "initrd"
                     bootp = "/pxelinux.0"
                     extra_params += " -boot cn"
-                    kernel_args = "autoyast=floppy console=ttyS0,115200 console=tty0"
+                    # You have to use autoyast=floppy if you want to use floppies to
+                    # hold your autoyast file
+                    #kernel_args = "autoyast=floppy console=ttyS0,115200 console=tty0"
+                    kernel_args = "autoyast=cdrom console=ttyS0,115200 console=tty0"
                     post_install_delay = 10
 
                 variants:
@@ -811,9 +983,10 @@
                         md5sum_1m = 1f19d4eff5bcead2a3e5b8b4212b6796
                         unattended_install.cdrom:
                             unattended_file = unattended/SLES-11.xml
-                            tftp = "images/sles-11-0-32/tftpboot"
-                            floppy = "images/sles-11-0-32/floppy.img"
-                            pxe_dir = "boot/i386/loader"
+                            tftp = images/sles-11-0-32/tftpboot
+                            #floppy = images/sles-11-0-32/autoyast.vfd
+                            cdrom_unattended = images/sles-11-0-32/autoyast.iso
+                            pxe_dir = boot/i386/loader
 
                     - 11.0.64:
                         image_name = sles11-64
@@ -822,9 +995,10 @@
                         md5sum_1m = 00000951cab7c32e332362fc424c1054
                         unattended_install.cdrom:
                             unattended_file = unattended/SLES-11.xml
-                            tftp = "images/sles-11-0-64/tftpboot"
-                            floppy = "images/sles-11-0-64/floppy.img"
-                            pxe_dir = "boot/x86_64/loader"
+                            tftp = images/sles-11-0-64/tftpboot
+                            #floppy = images/sles-11-0-64/autoyast.vfd
+                            cdrom_unattended = images/sles-11-0-64/autoyast.iso
+                            pxe_dir = boot/x86_64/loader
 
                     - 11.1.32:
                         image_name = sles11sp1-32
@@ -833,9 +1007,10 @@
                         md5sum_1m = a626a3d50813410e3ac42794e05773bb
                         unattended_install:
                             unattended_file = unattended/SLES-11.xml
-                            tftp = "images/sles-11-1-32/tftpboot"
-                            floppy = "images/sles-11-1-32/floppy.img"
-                            pxe_dir = "boot/i386/loader"
+                            tftp = images/sles-11-1-32/tftpboot
+                            #floppy = images/sles-11-1-32/autoyast.vfd
+                            cdrom_unattended = images/sles-11-1-32/autoyast.iso
+                            pxe_dir = boot/i386/loader
 
                     - 11.1.64:
                         image_name = sles11sp1-64
@@ -844,9 +1019,10 @@
                         md5sum_1m = f7f67b5da46923a9f01da8a2b6909654
                         unattended_install:
                             unattended_file = unattended/SLES-11.xml
-                            tftp = "images/sles-11-1-64/tftpboot"
-                            floppy = "images/sles-11-1-64/floppy.img"
-                            pxe_dir = "boot/x86_64/loader"
+                            tftp = images/sles-11-1-64/tftpboot
+                            #floppy = images/sles-11-1-64/autoyast.vfd
+                            cdrom_unattended = images/sles-11-1-64/autoyast.iso
+                            pxe_dir = boot/x86_64/loader
 
             - @Ubuntu:
                 shell_prompt = "^root@.*[\#\$]\s*$"
@@ -893,7 +1069,10 @@
                     tftp = "images/tftpboot"
                     bootp = "/pxelinux.0"
                     extra_params += " -boot cn"
-                    kernel_args = "ks=floppy nicdelay=60 console=ttyS0,115200 console=tty0"
+                    # You have to use ks=floppy if you want to use floppies to
+                    # hold your kickstart file
+                    #kernel_args = "ks=floppy nicdelay=60 console=ttyS0,115200 console=tty0"
+                    kernel_args = "ks=cdrom nicdelay=60 console=ttyS0,115200 console=tty0"
 
                 variants:
                     - 3.9.i386:
@@ -908,7 +1087,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-3-series.ks
                             tftp = images/rhel39-32/tftpboot
-                            floppy = images/rhel39-32/floppy.img
+                            #floppy = images/rhel39-32/ks.vfd
+                            cdrom_unattended = images/rhel39-32/ks.iso
 
                     - 3.9.x86_64:
                         no setup autotest linux_s3 guest_s4 shutdown
@@ -922,7 +1102,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-3-series.ks
                             tftp = images/rhel39-64/tftpboot
-                            floppy = images/rhel39-64/floppy.img
+                            #floppy = images/rhel39-64/ks.vfd
+                            cdrom_unattended = images/rhel39-64/ks.iso
 
                     - 4.7.i386:
                         no setup autotest
@@ -935,7 +1116,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-4-series.ks
                             tftp = images/rhel47-32/tftpboot
-                            floppy = images/rhel47-32/floppy.img
+                            #floppy = images/rhel47-32/ks.vfd
+                            cdrom_unattended = images/rhel47-32/ks.iso
 
                     - 4.7.x86_64:
                         no setup autotest
@@ -948,7 +1130,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-4-series.ks
                             tftp = images/rhel47-64/tftpboot
-                            floppy = images/rhel47-64/floppy.img
+                            #floppy = images/rhel47-64/ks.vfd
+                            cdrom_unattended = images/rhel47-64/ks.iso
 
                     - 4.8.i386:
                         no setup autotest
@@ -959,7 +1142,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-4-series.ks
                             tftp = images/rhel48-32/tftpboot
-                            floppy = images/rhel48-32/floppy.img
+                            #floppy = images/rhel48-32/ks.vfd
+                            cdrom_unattended = images/rhel48-32/ks.iso
 
                     - 4.8.x86_64:
                         no setup autotest
@@ -970,7 +1154,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-4-series.ks
                             tftp = images/rhel48-64/tftpboot
-                            floppy = images/rhel48-64/floppy.img
+                            #floppy = images/rhel48-64/ks.vfd
+                            cdrom_unattended = images/rhel48-64/ks.iso
 
                     - 5.3.i386:
                         no setup
@@ -983,7 +1168,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel53-32/tftpboot
-                            floppy = images/rhel53-32/floppy.img
+                            #floppy = images/rhel53-32/ks.vfd
+                            cdrom_unattended = images/rhel53-32/ks.iso
 
                     - 5.3.x86_64:
                         no setup
@@ -996,7 +1182,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel53-64/tftpboot
-                            floppy = images/rhel53-64/floppy.img
+                            #floppy = images/rhel53-64/ks.vfd
+                            cdrom_unattended = images/rhel53-64/ks.iso
 
                     - 5.4.i386:
                         no setup
@@ -1007,7 +1194,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel54-32/tftpboot
-                            floppy = images/rhel54-32/floppy.img
+                            #floppy = images/rhel54-32/ks.vfd
+                            cdrom_unattended = images/rhel54-32/ks.iso
 
                     - 5.4.x86_64:
                         no setup
@@ -1018,7 +1206,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel54-64/tftpboot
-                            floppy = images/rhel54-64/floppy.img
+                            #floppy = images/rhel54-64/ks.vfd
+                            cdrom_unattended = images/rhel54-64/ks.iso
 
                     - 5.5.i386:
                         no setup
@@ -1029,7 +1218,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel55-32/tftpboot
-                            floppy = images/rhel55-32/floppy.img
+                            #floppy = images/rhel55-32/ks.vfd
+                            cdrom_unattended = images/rhel55-32/ks.iso
 
                     - 5.5.x86_64:
                         no setup
@@ -1040,7 +1230,8 @@
                         unattended_install.cdrom:
                             unattended_file = unattended/RHEL-5-series.ks
                             tftp = images/rhel55-64/tftpboot
-                            floppy = images/rhel55-64/floppy.img
+                            #floppy = images/rhel55-64/ks.vfd
+                            cdrom_unattended = images/rhel55-64/ks.iso
 
 
     # Windows section
@@ -1071,9 +1262,16 @@
         unattended_install.cdrom:
             timeout = 7200
             finish_program = deps/finish.exe
-            cdroms += " winutilscd"
-            cdrom_winutilscd = windows/winutils.iso
-            drive_index_winutilscd = 2
+            cdroms += " winutils"
+            cdrom_winutils = windows/winutils.iso
+            drive_index_winutils = 2
+            # Turn install_virtio = yes if you want to install the
+            # Windows virtio drivers. It might be a lot of setup though :)
+            #install_virtio = no
+            #cdroms += " virtio"
+            #cdrom_virtio = windows/virtio-win.iso
+            #drive_index_virtio = 3
+            #virtio_floppy = /usr/share/virtio-win/virtio-drivers.vfd
         migrate:
             migration_test_command = ver && vol
             migration_bg_command = start ping -t localhost
@@ -1098,6 +1296,15 @@
             # Alternative host load:
             #host_load_command = "dd if=/dev/urandom of=/dev/null"
             host_load_instances = 8
+            ntp:
+                time_command = "w32tm /stripchart /samples:1 /computer:ns1.nay.redhat.com"
+                time_filter_re = "\d+/\d+/\d+\s\d+:\d+:\d+ [AP]M"
+                time_format = "%m/%d/%Y %H:%M:%S"
+            date:
+                time_command = "echo TIME: %date% %time%"
+                time_filter_re = "(?<=TIME: \w\w\w ).{19}(?=\.\d\d)"
+                time_format = "%m/%d/%Y %H:%M:%S"
+
         guest_s4:
             check_s4_support_cmd = powercfg /hibernate on
             test_s4_cmd = start ping -t localhost
@@ -1123,7 +1330,7 @@
 
         variants:
             - Win2000:
-                no reboot
+                no reboot whql
                 image_name = win2000-32
                 kill_vm_gracefully = no
                 install:
@@ -1139,7 +1346,7 @@
                     md5sum = dda6039f3a9173f0f6bfae40f5efdfea
                     md5sum_1m = dd28fba196d366d56fe774bd93df5527
                     unattended_file = unattended/win2000-32.sif
-                    floppy = images/win2000-32/floppy.img
+                    floppy = images/win2000-32/answer.vfd
 
             - WinXP:
                 image_name = winXP
@@ -1159,7 +1366,20 @@
                             md5sum = 743450644b1d9fe97b3cf379e22dceb0
                             md5sum_1m = b473bf75af2d1269fec8958cf0202bfd
                             unattended_file = unattended/winxp32.sif
-                            floppy = images/winXP-32/floppy.img
+                            floppy = images/winXP-32/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_oemsetup_id = WXP32
+                            virtio_network_path = 'F:\NetKVM\xp\x86'
+                            #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
+                        whql_submission:
+                            desc_path_desc1 = $\WDK\Logo Type\Device Logo\Windows XP
+                            desc_path_desc2 = $\WDK\Logo Type\Systems Logo\Windows XP
+                            dd_data_logoarch = X86
+                            dd_data_logoos = Windows XP
+                            dd_data_whqlos = Windows XP
+                            dd_data_whqlqual = Basic
 
                     - 64:
                         image_name += -64
@@ -1176,7 +1396,20 @@
                             md5sum = 8d3f007ec9c2060cec8a50ee7d7dc512
                             md5sum_1m = e812363ff427effc512b7801ee70e513
                             unattended_file = unattended/winxp64.sif
-                            floppy = images/winXP-64/floppy.img
+                            floppy = images/winXP-64/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_oemsetup_id = WNET64
+                            virtio_network_path = 'F:\NetKVM\xp\amd64'
+                            #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
+                        whql_submission:
+                            desc_path_desc1 = $\WDK\Logo Type\Device Logo\Windows XP
+                            desc_path_desc2 = $\WDK\Logo Type\Systems Logo\Windows XP
+                            dd_data_logoarch = AMD64
+                            dd_data_logoos = Windows XP 64-Bit Edition Version 2003
+                            dd_data_whqlos = Windows XP x64
+                            dd_data_whqlqual = Basic
 
             - Win2003:
                 image_name = win2003
@@ -1198,7 +1431,19 @@
                             md5sum = 03e921e9b4214773c21a39f5c3f42ef7
                             md5sum_1m = 37c2fdec15ac4ec16aa10fdfdb338aa3
                             unattended_file = unattended/win2003-32.sif
-                            floppy = images/win2003-32/floppy.img
+                            floppy = images/win2003-32/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_oemsetup_id = WNET32
+                            virtio_network_path = 'F:\NetKVM\2k3\x86'
+                            #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
+                        whql_submission:
+                            desc_path_desc1 = $\WDK\Logo Type\Device Logo\Windows Server 2003
+                            dd_data_logoarch = X86
+                            dd_data_logoos = Windows Server 2003
+                            dd_data_whqlos = Windows Server 2003
+                            dd_data_whqlqual = Basic
 
                     - 64:
                         image_name += -64
@@ -1215,145 +1460,240 @@
                             md5sum = 5703f87c9fd77d28c05ffadd3354dbbd
                             md5sum_1m = 439393c384116aa09e08a0ad047dcea8
                             unattended_file = unattended/win2003-64.sif
-                            floppy = images/win2003-64/floppy.img
+                            floppy = images/win2003-64/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_oemsetup_id = WNET64
+                            virtio_network_path = 'F:\NetKVM\2k3\amd64'
+                            #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
+
+                        whql_submission:
+                            desc_path_desc1 = $\WDK\Logo Type\Device Logo\Windows Server 2003
+                            dd_data_logoarch = AMD64
+                            dd_data_logoos = Windows Server 2003
+                            dd_data_whqlos = Windows Server 2003 x64
+                            dd_data_whqlqual = Basic
 
             - WinVista:
                 image_name = winvista
                 image_size = 20G
+                whql_submission:
+                    desc_path_desc1 = $\WDK\Logo Type\Device Logo\Vista Client\Device Premium
+                    desc_path_desc2 = $\WDK\Logo Type\Device Logo\Vista Client\Device Standard
+                    desc_path_desc3 = $\WDK\Logo Type\Device Logo\Vista Client
 
                 variants:
-                    - 32sp1:
-                        image_name += sp1-32
-                        install:
-                            cdrom_cd1 = windows/WindowsVista-32.iso
-                            md5sum = 1008f323d5170c8e614e52ccb85c0491
-                            md5sum_1m = c724e9695da483bc0fd59e426eaefc72
-                            steps = Win-Vista-32.steps
-                        setup:
-                            steps = WinVista-32-rss.steps
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/WindowsVista-32.iso
-                            md5sum = 1008f323d5170c8e614e52ccb85c0491
-                            md5sum_1m = c724e9695da483bc0fd59e426eaefc72
-                            unattended_file = unattended/winvista-32-autounattend.xml
-                            floppy = images/winvista-sp1-32/floppy.img
+                    - 32:
+                        whql_submission:
+                            dd_data_logoarch = X86
+                            dd_data_logoos = Windows Vista
+                            dd_data_whqlos = Windows Vista Client
+                            dd_data_whqlqual = Premium
+                        variants:
+                            - sp1:
+                                image_name += -sp1-32
+                                install:
+                                    cdrom_cd1 = windows/WindowsVista-32.iso
+                                    md5sum = 1008f323d5170c8e614e52ccb85c0491
+                                    md5sum_1m = c724e9695da483bc0fd59e426eaefc72
+                                    steps = Win-Vista-32.steps
+                                setup:
+                                    steps = WinVista-32-rss.steps
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/WindowsVista-32.iso
+                                    md5sum = 1008f323d5170c8e614e52ccb85c0491
+                                    md5sum_1m = c724e9695da483bc0fd59e426eaefc72
+                                    unattended_file = unattended/winvista-32-autounattend.xml
+                                    floppy = images/winvista-sp1-32/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\w7\x86'
+                                    virtio_network_path = 'F:\NetKVM\w7\x86'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
 
-                    - 64sp1:
-                        image_name += sp1-64
-                        install:
-                            cdrom_cd1 = windows/WindowsVista-64.iso
-                            md5sum = 11e2010d857fffc47813295e6be6d58d
-                            md5sum_1m = 0947bcd5390546139e25f25217d6f165
-                            steps = Win-Vista-64.steps
-                        setup:
-                            steps = WinVista-64-rss.steps
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/WindowsVista-64.iso
-                            md5sum = 11e2010d857fffc47813295e6be6d58d
-                            md5sum_1m = 0947bcd5390546139e25f25217d6f165
-                            unattended_file = unattended/winvista-64-autounattend.xml
-                            floppy = images/winvista-sp1-64/floppy.img
+                            - sp2:
+                                image_name += -sp2-32
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/en_windows_vista_with_sp2_x86_dvd_342266.iso
+                                    md5sum = 19ca90a425667812977bab6f4ce24175
+                                    md5sum_1m = 89c15020e0e6125be19acf7a2e5dc614
+                                    sha1sum = 25ad9a776503e6a583bec07879dbcc5dfd20cd6e
+                                    sha1sum_1m = a2afa4cffdc1c362dbf9e62942337f4f875a22cf
+                                    unattended_file = unattended/winvista-32-autounattend.xml
+                                    floppy = images/winvista-sp2-32/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\w7\x86'
+                                    virtio_network_path = 'F:\NetKVM\w7\x86'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
 
-                    - 32sp2:
-                        image_name += sp2-32
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/en_windows_vista_with_sp2_x86_dvd_342266.iso
-                            md5sum = 19ca90a425667812977bab6f4ce24175
-                            md5sum_1m = 89c15020e0e6125be19acf7a2e5dc614
-                            sha1sum = 25ad9a776503e6a583bec07879dbcc5dfd20cd6e
-                            sha1sum_1m = a2afa4cffdc1c362dbf9e62942337f4f875a22cf
-                            unattended_file = unattended/winvista-32-autounattend.xml
-                            floppy = images/winvista-sp2-32/floppy.img
-
-                    - 64sp2:
-                        image_name += sp2-64
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/en_windows_vista_sp2_x64_dvd_342267.iso
-                            md5sum = a1c024d7abaf34bac3368e88efbc2574
-                            md5sum_1m = 3d84911a80f3df71d1026f7adedc2181
-                            sha1sum = aaee3c04533899f9f8c4ae0c4250ef5fafbe29a3
-                            sha1sum_1m = 1fd21bd3ce2a4de8856c7b8fe6fdf80260f6d1c7
-                            unattended_file = unattended/winvista-64-autounattend.xml
-                            floppy = images/winvista-sp2-64/floppy.img
+                    - 64:
+                        whql_submission:
+                            dd_data_logoarch = AMD64
+                            dd_data_logoos = Windows Vista
+                            dd_data_whqlos = Windows Vista Client x64
+                            dd_data_whqlqual = Premium
+                        variants:
+                            - sp1:
+                                image_name += -sp1-64
+                                install:
+                                    cdrom_cd1 = windows/WindowsVista-64.iso
+                                    md5sum = 11e2010d857fffc47813295e6be6d58d
+                                    md5sum_1m = 0947bcd5390546139e25f25217d6f165
+                                    steps = Win-Vista-64.steps
+                                setup:
+                                    steps = WinVista-64-rss.steps
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/WindowsVista-64.iso
+                                    md5sum = 11e2010d857fffc47813295e6be6d58d
+                                    md5sum_1m = 0947bcd5390546139e25f25217d6f165
+                                    unattended_file = unattended/winvista-64-autounattend.xml
+                                    floppy = images/winvista-sp1-64/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\w7\amd64'
+                                    virtio_network_path = 'F:\NetKVM\w7\amd64'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
+                            - sp2:
+                                image_name += -sp2-64
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/en_windows_vista_sp2_x64_dvd_342267.iso
+                                    md5sum = a1c024d7abaf34bac3368e88efbc2574
+                                    md5sum_1m = 3d84911a80f3df71d1026f7adedc2181
+                                    sha1sum = aaee3c04533899f9f8c4ae0c4250ef5fafbe29a3
+                                    sha1sum_1m = 1fd21bd3ce2a4de8856c7b8fe6fdf80260f6d1c7
+                                    unattended_file = unattended/winvista-64-autounattend.xml
+                                    floppy = images/winvista-sp2-64/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\w7\amd64'
+                                    virtio_network_path = 'F:\NetKVM\w7\amd64'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
 
             - Win2008:
+                no whql
                 image_name = win2008
                 image_size = 20G
 
                 variants:
-                    - 32sp1:
-                        image_name += sp1-32
-                        install:
-                            cdrom_cd1 = windows/Windows2008-x86.iso
-                            #en_windows_server_2008_datacenter_enterprise_standard_x86_dvd_X14-26710.iso
-                            md5sum=0bfca49f0164de0a8eba236ced47007d
-                            md5sum_1m=07d7f5006393f74dc76e6e2e943e2440
-                            sha1sum = 6ca018ff96f1e9b2b310a36546b6fded99a421e6
-                            steps = Win2008-32.steps
-                        setup:
-                            steps = Win2008-32-rss.steps
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/Windows2008-x86.iso
-                            md5sum=0bfca49f0164de0a8eba236ced47007d
-                            md5sum_1m=07d7f5006393f74dc76e6e2e943e2440
-                            unattended_file = unattended/win2008-32-autounattend.xml
-                            floppy = images/win2008-sp1-32/floppy.img
+                    - 32:
+                        variants:
+                            - sp1:
+                                image_name += -sp1-32
+                                install:
+                                    cdrom_cd1 = windows/Windows2008-x86.iso
+                                    #en_windows_server_2008_datacenter_enterprise_standard_x86_dvd_X14-26710.iso
+                                    md5sum=0bfca49f0164de0a8eba236ced47007d
+                                    md5sum_1m=07d7f5006393f74dc76e6e2e943e2440
+                                    sha1sum = 6ca018ff96f1e9b2b310a36546b6fded99a421e6
+                                    steps = Win2008-32.steps
+                                setup:
+                                    steps = Win2008-32-rss.steps
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/Windows2008-x86.iso
+                                    md5sum=0bfca49f0164de0a8eba236ced47007d
+                                    md5sum_1m=07d7f5006393f74dc76e6e2e943e2440
+                                    unattended_file = unattended/win2008-32-autounattend.xml
+                                    floppy = images/win2008-sp1-32/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\2k8\x86'
+                                    virtio_network_path = 'F:\NetKVM\2k8\x86'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
 
-                    - 64sp1:
-                        image_name += sp1-64
-                        install:
-                            steps = Win2008-64.steps
-                            cdrom_cd1 = windows/Windows2008-x64.iso
-                            #en_windows_server_2008_datacenter_enterprise_standard_x64_dvd_X14-26714.iso
-                            md5sum=27c58cdb3d620f28c36333a5552f271c
-                            md5sum_1m=efdcc11d485a1ef9afa739cb8e0ca766
-                            sha1sum = bd000374709f67e9358814db6ec8f0ddaaa16f70
-                            passwd = 1q2w3eP
-                        setup:
-                            steps = Win2008-64-rss.steps
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/Windows2008-x64.iso
-                            md5sum=27c58cdb3d620f28c36333a5552f271c
-                            md5sum_1m=efdcc11d485a1ef9afa739cb8e0ca766
-                            unattended_file = unattended/win2008-64-autounattend.xml
-                            floppy = images/win2008-sp1-64/floppy.img
+                            - sp2:
+                                image_name += -sp2-32
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/en_windows_server_2008_datacenter_enterprise_standard_sp2_x86_dvd_342333.iso
+                                    md5sum = b9201aeb6eef04a3c573d036a8780bdf
+                                    md5sum_1m = b7a9d42e55ea1e85105a3a6ad4da8e04
+                                    sha1sum = 49d0d6917c1256fe81048d414fa473bbc76a8724
+                                    sha1sum_1m = 9662ff7ed715faa00407e4befc484ea52a92a9fb
+                                    unattended_file = unattended/win2008-32-autounattend.xml
+                                    floppy = images/win2008-sp2-32/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\2k8\x86'
+                                    virtio_network_path = 'F:\NetKVM\2k8\x86'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
 
-                    - 32sp2:
-                        image_name += sp2-32
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/en_windows_server_2008_datacenter_enterprise_standard_sp2_x86_dvd_342333.iso
-                            md5sum = b9201aeb6eef04a3c573d036a8780bdf
-                            md5sum_1m = b7a9d42e55ea1e85105a3a6ad4da8e04
-                            sha1sum = 49d0d6917c1256fe81048d414fa473bbc76a8724
-                            sha1sum_1m = 9662ff7ed715faa00407e4befc484ea52a92a9fb
-                            unattended_file = unattended/win2008-32-autounattend.xml
-                            floppy = images/win2008-sp2-32/floppy.img
+                    - 64:
+                        variants:
+                            -sp1:
+                                image_name += -sp1-64
+                                install:
+                                    steps = Win2008-64.steps
+                                    cdrom_cd1 = windows/Windows2008-x64.iso
+                                    #en_windows_server_2008_datacenter_enterprise_standard_x64_dvd_X14-26714.iso
+                                    md5sum=27c58cdb3d620f28c36333a5552f271c
+                                    md5sum_1m=efdcc11d485a1ef9afa739cb8e0ca766
+                                    sha1sum = bd000374709f67e9358814db6ec8f0ddaaa16f70
+                                    passwd = 1q2w3eP
+                                setup:
+                                    steps = Win2008-64-rss.steps
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/Windows2008-x64.iso
+                                    md5sum=27c58cdb3d620f28c36333a5552f271c
+                                    md5sum_1m=efdcc11d485a1ef9afa739cb8e0ca766
+                                    unattended_file = unattended/win2008-64-autounattend.xml
+                                    floppy = images/win2008-sp1-64/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\2k8\amd64'
+                                    virtio_network_path = 'F:\NetKVM\2k8\amd64'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
 
-                    - 64sp2:
-                        image_name += sp2-64
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/en_windows_server_2008_datacenter_enterprise_standard_sp2_x64_dvd_342336.iso
-                            md5sum = e94943ef484035b3288d8db69599a6b5
-                            md5sum_1m = ee55506823d0efffb5532ddd88a8e47b
-                            sha1sum = 34c7d726c57b0f8b19ba3b40d1b4044c15fc2029
-                            sha1sum_1m = 8fe08b03e3531906855a60a78020ac9577dff5ba
-                            unattended_file = unattended/win2008-64-autounattend.xml
-                            floppy = images/win2008-sp2-64/floppy.img
+                            - sp2:
+                                image_name += -sp2-64
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/en_windows_server_2008_datacenter_enterprise_standard_sp2_x64_dvd_342336.iso
+                                    md5sum = e94943ef484035b3288d8db69599a6b5
+                                    md5sum_1m = ee55506823d0efffb5532ddd88a8e47b
+                                    sha1sum = 34c7d726c57b0f8b19ba3b40d1b4044c15fc2029
+                                    sha1sum_1m = 8fe08b03e3531906855a60a78020ac9577dff5ba
+                                    unattended_file = unattended/win2008-64-autounattend.xml
+                                    floppy = images/win2008-sp2-64/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\2k8\amd64'
+                                    virtio_network_path = 'F:\NetKVM\2k8\amd64'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
 
-                    - r2:
-                        image_name += -r2
-                        unattended_install.cdrom:
-                            cdrom_cd1 = windows/en_windows_server_2008_r2_standard_enterprise_datacenter_and_web_x64_dvd_x15-59754.iso
-                            md5sum = 0207ef392c60efdda92071b0559ca0f9
-                            md5sum_1m = a5a22ce25008bd7109f6d830d627e3ed
-                            sha1sum = ad855ea913aaec3f1d0e1833c1aef7a0de326b0a
-                            sha1sum_1m = 9194a3aabae25b36e5f73cad001314b2c8d07d14
-                            unattended_file = unattended/win2008-r2-autounattend.xml
-                            floppy = images/win2008-r2-64/floppy.img
+                            - r2:
+                                image_name += -r2-64
+                                unattended_install.cdrom:
+                                    cdrom_cd1 = windows/en_windows_server_2008_r2_standard_enterprise_datacenter_and_web_x64_dvd_x15-59754.iso
+                                    md5sum = 0207ef392c60efdda92071b0559ca0f9
+                                    md5sum_1m = a5a22ce25008bd7109f6d830d627e3ed
+                                    sha1sum = ad855ea913aaec3f1d0e1833c1aef7a0de326b0a
+                                    sha1sum_1m = 9194a3aabae25b36e5f73cad001314b2c8d07d14
+                                    unattended_file = unattended/win2008-r2-autounattend.xml
+                                    floppy = images/win2008-r2-64/answer.vfd
+                                    # Uncomment virtio_network_installer_path line if
+                                    # you have an msi installer, also make sure the
+                                    # paths are properly set in your virtio driver iso.
+                                    virtio_storage_path = 'F:\viostor\2k8\amd64'
+                                    virtio_network_path = 'F:\NetKVM\2k8\amd64'
+                                    #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
 
             - Win7:
                 image_name = win7
                 image_size = 20G
+                whql_submission:
+                    desc_path_desc1 = $\WDK\Logo Type\Device Logo\Windows 7 Client\Logo
+                    desc_path_desc2 = $\WDK\Logo Type\Device Logo\Windows 7 Client
+                    device_data += " adq"
+                    dd_name_adq = AdditionalQualificationGroup
+                    dd_data_adq = Windows 7
 
                 variants:
                     - 32:
@@ -1365,7 +1705,18 @@
                             sha1sum = 5395dc4b38f7bdb1e005ff414deedfdb16dbf610
                             sha1sum_1m = 9f9c3780aebeb28a9bf22188eed6bc15475dc9c5
                             unattended_file = unattended/win7-32-autounattend.xml
-                            floppy = images/win7-32/floppy.img
+                            floppy = images/win7-32/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_storage_path = 'F:\viostor\w7\x86'
+                            virtio_network_path = 'F:\NetKVM\w7\x86'
+                            #virtio_network_installer_path = 'F:\RHEV-Network32.msi'
+                        whql_submission:
+                            dd_data_logoarch = X86
+                            dd_data_logoos = Windows 7
+                            dd_data_whqlos = Windows 7 Client
+                            dd_data_whqlqual = Logo
 
                     - 64:
                         image_name += -64
@@ -1384,7 +1735,18 @@
                             sha1sum = 326327cc2ff9f05379f5058c41be6bc5e004baa7
                             sha1sum_1m = 4a3903bd5157de54f0702e5263e0a683c5775515
                             unattended_file = unattended/win7-64-autounattend.xml
-                            floppy = images/win7-64/floppy.img
+                            floppy = images/win7-64/answer.vfd
+                            # Uncomment virtio_network_installer_path line if
+                            # you have an msi installer, also make sure the
+                            # paths are properly set in your virtio driver iso.
+                            virtio_storage_path = 'F:\viostor\w7\amd64'
+                            virtio_network_path = 'F:\NetKVM\w7\amd64'
+                            #virtio_network_installer_path = 'F:\RHEV-Network64.msi'
+                        whql_submission:
+                            dd_data_logoarch = AMD64
+                            dd_data_logoos = Windows 7
+                            dd_data_whqlos = Windows 7 Client x64
+                            dd_data_whqlqual = Logo
 
 
     # Unix/BSD section
@@ -1463,8 +1825,9 @@
         image_boot=yes
 
 
-virtio|virtio_blk|e1000|balloon_check:
-    only Fedora.11 Fedora.12 Win2008 WinVista Win7 OpenSUSE.11 SLES.11 Ubuntu-8.10-server
+virtio_net|virtio_blk|e1000|balloon_check:
+    only Fedora.11 Fedora.12 Fedora.13 RHEL.5 OpenSUSE.11 SLES.11 Ubuntu-8.10-server
+    # only WinXP Win2003 Win2008 WinVista Win7 Fedora.11 Fedora.12 Fedora.13 RHEL.5 OpenSUSE.11 SLES.11 Ubuntu-8.10-server
 
 
 variants:
diff --git a/client/tests/kvm/unattended/Fedora-10.ks b/client/tests/kvm/unattended/Fedora-10.ks
index 03163c3..26965af 100644
--- a/client/tests/kvm/unattended/Fedora-10.ks
+++ b/client/tests/kvm/unattended/Fedora-10.ks
@@ -11,7 +11,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 clearpart --all --initlabel
 autopart
diff --git a/client/tests/kvm/unattended/Fedora-11.ks b/client/tests/kvm/unattended/Fedora-11.ks
index 443e2c3..861546b 100644
--- a/client/tests/kvm/unattended/Fedora-11.ks
+++ b/client/tests/kvm/unattended/Fedora-11.ks
@@ -10,7 +10,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 
 clearpart --all --initlabel
diff --git a/client/tests/kvm/unattended/Fedora-12.ks b/client/tests/kvm/unattended/Fedora-12.ks
index 443e2c3..861546b 100644
--- a/client/tests/kvm/unattended/Fedora-12.ks
+++ b/client/tests/kvm/unattended/Fedora-12.ks
@@ -10,7 +10,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 
 clearpart --all --initlabel
diff --git a/client/tests/kvm/unattended/Fedora-13.ks b/client/tests/kvm/unattended/Fedora-13.ks
index ef978e8..0949e40 100644
--- a/client/tests/kvm/unattended/Fedora-13.ks
+++ b/client/tests/kvm/unattended/Fedora-13.ks
@@ -10,7 +10,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 
 clearpart --all --initlabel
diff --git a/client/tests/kvm/unattended/Fedora-8.ks b/client/tests/kvm/unattended/Fedora-8.ks
index 3e9d387..92ff727 100644
--- a/client/tests/kvm/unattended/Fedora-8.ks
+++ b/client/tests/kvm/unattended/Fedora-8.ks
@@ -11,7 +11,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 clearpart --all --initlabel
 autopart
diff --git a/client/tests/kvm/unattended/Fedora-9.ks b/client/tests/kvm/unattended/Fedora-9.ks
index 3e9d387..92ff727 100644
--- a/client/tests/kvm/unattended/Fedora-9.ks
+++ b/client/tests/kvm/unattended/Fedora-9.ks
@@ -11,7 +11,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 clearpart --all --initlabel
 autopart
diff --git a/client/tests/kvm/unattended/OpenSUSE-11.xml b/client/tests/kvm/unattended/OpenSUSE-11.xml
index 64140bf..0ade836 100644
--- a/client/tests/kvm/unattended/OpenSUSE-11.xml
+++ b/client/tests/kvm/unattended/OpenSUSE-11.xml
@@ -50,7 +50,7 @@
         <module>edd</module>
       </initrd_module>
     </initrd_modules>
-    <append>console=ttyS0,115200 console=tty0</append>
+    <append>console=tty0 console=ttyS0,115200</append>
     <loader_type>grub</loader_type>
     <sections config:type="list"/>
   </bootloader>
diff --git a/client/tests/kvm/unattended/RHEL-3-series.ks b/client/tests/kvm/unattended/RHEL-3-series.ks
index 413890a..79d9605 100644
--- a/client/tests/kvm/unattended/RHEL-3-series.ks
+++ b/client/tests/kvm/unattended/RHEL-3-series.ks
@@ -10,7 +10,7 @@
 firewall --enabled --ssh
 timezone America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 clearpart --all --initlabel
 autopart
 reboot
diff --git a/client/tests/kvm/unattended/RHEL-4-series.ks b/client/tests/kvm/unattended/RHEL-4-series.ks
index 213914d..d791e0f 100644
--- a/client/tests/kvm/unattended/RHEL-4-series.ks
+++ b/client/tests/kvm/unattended/RHEL-4-series.ks
@@ -11,7 +11,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 clearpart --all --initlabel
 autopart
diff --git a/client/tests/kvm/unattended/RHEL-5-series.ks b/client/tests/kvm/unattended/RHEL-5-series.ks
index 3e9d387..92ff727 100644
--- a/client/tests/kvm/unattended/RHEL-5-series.ks
+++ b/client/tests/kvm/unattended/RHEL-5-series.ks
@@ -11,7 +11,7 @@
 selinux --enforcing
 timezone --utc America/New_York
 firstboot --disable
-bootloader --location=mbr --append="console=ttyS0,115200 console=tty0"
+bootloader --location=mbr --append="console=tty0 console=ttyS0,115200"
 zerombr
 clearpart --all --initlabel
 autopart
diff --git a/client/tests/kvm/unattended/SLES-11.xml b/client/tests/kvm/unattended/SLES-11.xml
index 61151d9..c694a31 100644
--- a/client/tests/kvm/unattended/SLES-11.xml
+++ b/client/tests/kvm/unattended/SLES-11.xml
@@ -49,7 +49,7 @@
         <module>edd</module>
       </initrd_module>
     </initrd_modules>
-    <append>console=ttyS0,115200 console=tty0</append>
+    <append>console=tty0 console=ttyS0,115200</append>
     <loader_type>grub</loader_type>
     <sections config:type="list"/>
   </bootloader>
diff --git a/client/tests/kvm/unattended/win2003-32.sif b/client/tests/kvm/unattended/win2003-32.sif
index f58b0b0..fab2cf5 100644
--- a/client/tests/kvm/unattended/win2003-32.sif
+++ b/client/tests/kvm/unattended/win2003-32.sif
@@ -10,6 +10,7 @@
     UnattendSwitch = Yes
     CrashDumpSetting = 1
     DriverSigningPolicy = ignore
+    OemPnPDriversPath="KVM_TEST_NETWORK_DRIVER_PATH"
     WaitForReboot = no
     Repartition = yes
 
@@ -56,9 +57,10 @@
     YResolution=768
 
 [GuiRunOnce]
-    Command0="cmd /c sc config TlntSvr start= auto"
-    Command1="cmd /c netsh firewall set opmode disable"
-    Command2="cmd /c net start telnet"
-    Command3="cmd /c E:\setuprss.bat"
-    Command4="cmd /c netsh interface ip set address local dhcp"
-    Command5="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
+    Command0="cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"
+    Command1="cmd /c sc config TlntSvr start= auto"
+    Command2="cmd /c netsh firewall set opmode disable"
+    Command3="cmd /c net start telnet"
+    Command4="cmd /c E:\setuprss.bat"
+    Command5="cmd /c netsh interface ip set address local dhcp"
+    Command6="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
diff --git a/client/tests/kvm/unattended/win2003-64.sif b/client/tests/kvm/unattended/win2003-64.sif
index f58b0b0..fab2cf5 100644
--- a/client/tests/kvm/unattended/win2003-64.sif
+++ b/client/tests/kvm/unattended/win2003-64.sif
@@ -10,6 +10,7 @@
     UnattendSwitch = Yes
     CrashDumpSetting = 1
     DriverSigningPolicy = ignore
+    OemPnPDriversPath="KVM_TEST_NETWORK_DRIVER_PATH"
     WaitForReboot = no
     Repartition = yes
 
@@ -56,9 +57,10 @@
     YResolution=768
 
 [GuiRunOnce]
-    Command0="cmd /c sc config TlntSvr start= auto"
-    Command1="cmd /c netsh firewall set opmode disable"
-    Command2="cmd /c net start telnet"
-    Command3="cmd /c E:\setuprss.bat"
-    Command4="cmd /c netsh interface ip set address local dhcp"
-    Command5="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
+    Command0="cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"
+    Command1="cmd /c sc config TlntSvr start= auto"
+    Command2="cmd /c netsh firewall set opmode disable"
+    Command3="cmd /c net start telnet"
+    Command4="cmd /c E:\setuprss.bat"
+    Command5="cmd /c netsh interface ip set address local dhcp"
+    Command6="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
diff --git a/client/tests/kvm/unattended/win2008-32-autounattend.xml b/client/tests/kvm/unattended/win2008-32-autounattend.xml
index 44a9fc4..89af07f 100644
--- a/client/tests/kvm/unattended/win2008-32-autounattend.xml
+++ b/client/tests/kvm/unattended/win2008-32-autounattend.xml
@@ -15,6 +15,20 @@
 			<UILanguageFallback>en-us</UILanguageFallback>
 			<UserLocale>en-us</UserLocale>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 		<component name="Microsoft-Windows-Setup"
 			processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"
 			language="neutral" versionScope="nonSxS"
@@ -115,32 +129,36 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>2</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>3</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>4</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>5</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>6</Order>
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
 				</SynchronousCommand>
 			</FirstLogonCommands>
 			<OOBE>
diff --git a/client/tests/kvm/unattended/win2008-64-autounattend.xml b/client/tests/kvm/unattended/win2008-64-autounattend.xml
index ea0a524..98f5589 100644
--- a/client/tests/kvm/unattended/win2008-64-autounattend.xml
+++ b/client/tests/kvm/unattended/win2008-64-autounattend.xml
@@ -70,6 +70,20 @@
 			<UserLocale>en-us</UserLocale>
 			<UILanguageFallback>en-us</UILanguageFallback>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 	</settings>
 	<settings pass="specialize">
 		<component name="Microsoft-Windows-Deployment"
@@ -124,32 +138,36 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>2</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>3</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>4</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>5</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>6</Order>
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
 				</SynchronousCommand>
 			</FirstLogonCommands>
 			<OOBE>
diff --git a/client/tests/kvm/unattended/win2008-r2-autounattend.xml b/client/tests/kvm/unattended/win2008-r2-autounattend.xml
index ea0a524..b624d10 100644
--- a/client/tests/kvm/unattended/win2008-r2-autounattend.xml
+++ b/client/tests/kvm/unattended/win2008-r2-autounattend.xml
@@ -100,6 +100,20 @@
 			<UILanguage>en-US</UILanguage>
 			<UserLocale>en-US</UserLocale>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 	</settings>
 	<settings pass="oobeSystem">
 		<component name="Microsoft-Windows-Shell-Setup"
@@ -124,32 +138,36 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>2</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>3</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>4</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>5</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>6</Order>
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
 				</SynchronousCommand>
 			</FirstLogonCommands>
 			<OOBE>
diff --git a/client/tests/kvm/unattended/win7-32-autounattend.xml b/client/tests/kvm/unattended/win7-32-autounattend.xml
index a577a91..a16cdd7 100644
--- a/client/tests/kvm/unattended/win7-32-autounattend.xml
+++ b/client/tests/kvm/unattended/win7-32-autounattend.xml
@@ -15,6 +15,20 @@
 			<UILanguageFallback>en-us</UILanguageFallback>
 			<UserLocale>en-us</UserLocale>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 		<component name="Microsoft-Windows-Setup"
 			processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"
 			language="neutral" versionScope="nonSxS"
@@ -122,33 +136,37 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
 					<Order>2</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
 					<Order>3</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
 					<Order>4</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
 					<Order>5</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine> 
+					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
 					<Order>6</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
 				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
+				</SynchronousCommand>
 			</FirstLogonCommands>
 		</component>
 	</settings>
diff --git a/client/tests/kvm/unattended/win7-64-autounattend.xml b/client/tests/kvm/unattended/win7-64-autounattend.xml
index fec8017..65873f6 100644
--- a/client/tests/kvm/unattended/win7-64-autounattend.xml
+++ b/client/tests/kvm/unattended/win7-64-autounattend.xml
@@ -15,6 +15,20 @@
 			<UILanguageFallback>en-us</UILanguageFallback>
 			<UserLocale>en-us</UserLocale>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 		<component name="Microsoft-Windows-Setup"
 			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
 			language="neutral" versionScope="nonSxS"
@@ -122,33 +136,37 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
 					<Order>2</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
 					<Order>3</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
 					<Order>4</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
 					<Order>5</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine> 
+					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
 					<Order>6</Order>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
-					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
 				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
+				</SynchronousCommand>
 			</FirstLogonCommands>
 		</component>
 	</settings>
diff --git a/client/tests/kvm/unattended/winvista-32-autounattend.xml b/client/tests/kvm/unattended/winvista-32-autounattend.xml
index 7835a64..d4e8c5c 100644
--- a/client/tests/kvm/unattended/winvista-32-autounattend.xml
+++ b/client/tests/kvm/unattended/winvista-32-autounattend.xml
@@ -15,6 +15,20 @@
 			<UILanguageFallback>en-us</UILanguageFallback>
 			<UserLocale>en-us</UserLocale>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 		<component name="Microsoft-Windows-Setup"
 			processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"
 			language="neutral" versionScope="nonSxS"
@@ -122,32 +136,36 @@
 			</AutoLogon>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>2</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>3</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>4</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>5</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>6</Order>
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
 				</SynchronousCommand>
 			</FirstLogonCommands>
 		</component>
diff --git a/client/tests/kvm/unattended/winvista-64-autounattend.xml b/client/tests/kvm/unattended/winvista-64-autounattend.xml
index ad68bf9..16d4850 100644
--- a/client/tests/kvm/unattended/winvista-64-autounattend.xml
+++ b/client/tests/kvm/unattended/winvista-64-autounattend.xml
@@ -62,6 +62,20 @@
 			<UserLocale>en-us</UserLocale>
 			<UILanguageFallback>en-us</UILanguageFallback>
 		</component>
+		<component name="Microsoft-Windows-PnpCustomizationsWinPE"
+			processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
+			language="neutral" versionScope="nonSxS"
+			xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
+			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<DriverPaths>
+				<PathAndCredentials wcm:keyValue="1" wcm:action="add">
+					<Path>KVM_TEST_STORAGE_DRIVER_PATH</Path>
+				</PathAndCredentials>
+				<PathAndCredentials wcm:keyValue="2" wcm:action="add">
+					<Path>KVM_TEST_NETWORK_DRIVER_PATH</Path>
+				</PathAndCredentials>
+			</DriverPaths>
+		</component>
 	</settings>
 	<settings pass="specialize">
 		<component name="Microsoft-Windows-Deployment"
@@ -123,32 +137,36 @@
 			</OOBE>
 			<FirstLogonCommands>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"</CommandLine>
 					<Order>1</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c start /w pkgmgr /iu:"TelnetServer"</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>2</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c sc config TlntSvr start= auto</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>3</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c netsh firewall set opmode disable</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>4</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c net start telnet</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>5</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c E:\setuprss.bat</CommandLine>
-				</SynchronousCommand>
-				<SynchronousCommand wcm:action="add">
 					<Order>6</Order>
-					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 				</SynchronousCommand>
 				<SynchronousCommand wcm:action="add">
+					<CommandLine>%WINDIR%\System32\cmd /c netsh interface ip set address "Local Area Connection" dhcp</CommandLine>
 					<Order>7</Order>
+				</SynchronousCommand>
+				<SynchronousCommand wcm:action="add">
 					<CommandLine>%WINDIR%\System32\cmd /c ping 10.0.2.2 -n 20 &#38;&#38; A:\finish.exe</CommandLine>
+					<Order>8</Order>
 				</SynchronousCommand>
 			</FirstLogonCommands>
 		</component>
diff --git a/client/tests/kvm/unattended/winxp32.sif b/client/tests/kvm/unattended/winxp32.sif
index 7562846..b9a2ab6 100644
--- a/client/tests/kvm/unattended/winxp32.sif
+++ b/client/tests/kvm/unattended/winxp32.sif
@@ -13,6 +13,7 @@
     UnattendSwitch=Yes
     CrashDumpSetting=1
     DriverSigningPolicy=ignore
+    OemPnPDriversPath="KVM_TEST_NETWORK_DRIVER_PATH"
     WaitForReboot=no
 
 [GuiUnattended]
@@ -68,6 +69,7 @@
     YResolution=768
 
 [GuiRunOnce]
-   Command0="cmd /c E:\setuprss.bat"
-   Command1="cmd /c netsh interface ip set address local dhcp"
-   Command2="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
+   Command0="cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"
+   Command1="cmd /c E:\setuprss.bat"
+   Command2="cmd /c netsh interface ip set address local dhcp"
+   Command3="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
diff --git a/client/tests/kvm/unattended/winxp64.sif b/client/tests/kvm/unattended/winxp64.sif
index 7562846..b9a2ab6 100644
--- a/client/tests/kvm/unattended/winxp64.sif
+++ b/client/tests/kvm/unattended/winxp64.sif
@@ -13,6 +13,7 @@
     UnattendSwitch=Yes
     CrashDumpSetting=1
     DriverSigningPolicy=ignore
+    OemPnPDriversPath="KVM_TEST_NETWORK_DRIVER_PATH"
     WaitForReboot=no
 
 [GuiUnattended]
@@ -68,6 +69,7 @@
     YResolution=768
 
 [GuiRunOnce]
-   Command0="cmd /c E:\setuprss.bat"
-   Command1="cmd /c netsh interface ip set address local dhcp"
-   Command2="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
+   Command0="cmd /c KVM_TEST_VIRTIO_NETWORK_INSTALLER"
+   Command1="cmd /c E:\setuprss.bat"
+   Command2="cmd /c netsh interface ip set address local dhcp"
+   Command3="cmd /c ping 10.0.2.2 -n 20 && A:\finish.exe"
diff --git a/client/tests/kvm/unittests.cfg.sample b/client/tests/kvm/unittests.cfg.sample
index 7ea0674..3d32cb2 100644
--- a/client/tests/kvm/unittests.cfg.sample
+++ b/client/tests/kvm/unittests.cfg.sample
@@ -58,6 +58,7 @@
                 user_git_repo = git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git
                 user_branch = next
                 user_lbranch = next
+                test_git_repo = git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git
 
     - unittest:
         type = unittest
diff --git a/client/tests/libhugetlbfs/libhugetlbfs.py b/client/tests/libhugetlbfs/libhugetlbfs.py
index 2fe6b45..373a5ba 100644
--- a/client/tests/libhugetlbfs/libhugetlbfs.py
+++ b/client/tests/libhugetlbfs/libhugetlbfs.py
@@ -44,9 +44,9 @@
         # make might fail if there are no proper headers for the 32 bit
         # version, in that case try only for the 64 bit version
         try:
-            utils.system('make')
+            utils.make()
         except:
-            utils.system('make OBJDIRS=obj64')
+            utils.make('OBJDIRS=obj64')
 
 
     def run_once(self):
@@ -54,9 +54,9 @@
         # make check might fail for 32 bit if the 32 bit compile earlier
         # had failed. See if it passes for 64 bit in that case.
         try:
-            utils.system('make check')
+            utils.make('check')
         except:
-            utils.system('make check OBJDIRS=obj64')
+            utils.make('check OBJDIRS=obj64')
 
 
     def cleanup(self):
diff --git a/client/tests/lmbench/lmbench.py b/client/tests/lmbench/lmbench.py
index 33a86b4..0883258 100644
--- a/client/tests/lmbench/lmbench.py
+++ b/client/tests/lmbench/lmbench.py
@@ -34,7 +34,7 @@
         utils.system(p2)
 
         # build lmbench
-        utils.system('make')
+        utils.make()
 
         # configure lmbench
         utils.system('yes "" | make config')
@@ -62,11 +62,11 @@
 
     def run_once(self):
         os.chdir(self.srcdir)
-        utils.system('make rerun')
+        utils.make('rerun')
 
 
     def postprocess(self):
         # Get the results:
         outputdir = self.srcdir + "/results"
         results = self.resultsdir + "/summary.txt"
-        utils.system("make -C " + outputdir + " summary > " + results)
+        utils.make("-C " + outputdir + " summary > " + results)
diff --git a/client/tests/ltp/ltp.py b/client/tests/ltp/ltp.py
index 0d0e763..fb2df01 100644
--- a/client/tests/ltp/ltp.py
+++ b/client/tests/ltp/ltp.py
@@ -40,9 +40,9 @@
             utils.system('patch -p1 < ../ltp_capability.patch')
 
         utils.system('cp ../scan.c pan/')   # saves having lex installed
-        utils.system('make autotools')
+        utils.make('autotools')
         utils.configure('--prefix=%s' % ltpbin_dir)
-        utils.system('make -j %d all' % utils.count_cpus())
+        utils.make('-j %d all' % utils.count_cpus())
         utils.system('yes n | make SKIP_IDCHECK=1 install')
 
 
diff --git a/client/tests/monotonic_time/monotonic_time.py b/client/tests/monotonic_time/monotonic_time.py
index 1814c2d..ce49110 100644
--- a/client/tests/monotonic_time/monotonic_time.py
+++ b/client/tests/monotonic_time/monotonic_time.py
@@ -9,7 +9,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def initialize(self):
diff --git a/client/tests/netperf2/netperf2.py b/client/tests/netperf2/netperf2.py
index b82aa5c..179757a 100644
--- a/client/tests/netperf2/netperf2.py
+++ b/client/tests/netperf2/netperf2.py
@@ -18,7 +18,7 @@
 
         utils.system('patch -p0 < ../wait_before_data.patch')
         utils.configure()
-        utils.system('make')
+        utils.make()
         utils.system('sync')
 
         self.job.setup_dep(['sysstat'])
diff --git a/client/tests/netpipe/netpipe.py b/client/tests/netpipe/netpipe.py
index 9937456..948065c 100644
--- a/client/tests/netpipe/netpipe.py
+++ b/client/tests/netpipe/netpipe.py
@@ -13,7 +13,7 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
         utils.system('patch -p1 < ../makefile.patch')
-        utils.system('make')
+        utils.make()
 
 
     def initialize(self):
diff --git a/client/tests/perfmon/perfmon.py b/client/tests/perfmon/perfmon.py
index ec1145f..207d68a 100644
--- a/client/tests/perfmon/perfmon.py
+++ b/client/tests/perfmon/perfmon.py
@@ -10,7 +10,7 @@
         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def initialize(self):
diff --git a/client/tests/pi_tests/pi_tests.py b/client/tests/pi_tests/pi_tests.py
index f6f9020..a68581a 100644
--- a/client/tests/pi_tests/pi_tests.py
+++ b/client/tests/pi_tests/pi_tests.py
@@ -15,7 +15,7 @@
         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def execute(self, args = '1 300'):
diff --git a/client/tests/posixtest/posixtest.py b/client/tests/posixtest/posixtest.py
index cf68e6d..c8e3e19 100644
--- a/client/tests/posixtest/posixtest.py
+++ b/client/tests/posixtest/posixtest.py
@@ -21,7 +21,7 @@
         # Applying a small patch that introduces some linux specific
         # linking options
         utils.system('patch -p1 < ../posix-linux.patch')
-        utils.system('make')
+        utils.make()
 
 
     def execute(self):
diff --git a/client/tests/qemu_iotests/qemu_iotests.py b/client/tests/qemu_iotests/qemu_iotests.py
index 33b24c3..1a036b9 100644
--- a/client/tests/qemu_iotests/qemu_iotests.py
+++ b/client/tests/qemu_iotests/qemu_iotests.py
@@ -34,7 +34,7 @@
         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
-        utils.system("make clean")
+        utils.make('clean')
 
 
     def run_once(self, options='', testlist=''):
diff --git a/client/tests/rtc/rtc.py b/client/tests/rtc/rtc.py
index 49b2a9d..5345db1 100644
--- a/client/tests/rtc/rtc.py
+++ b/client/tests/rtc/rtc.py
@@ -8,8 +8,8 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make clobber')
-        utils.system('make')
+        utils.make('clobber')
+        utils.make()
 
 
     def initialize(self):
diff --git a/client/tests/scrashme/scrashme.py b/client/tests/scrashme/scrashme.py
index 89b60b3..822d4d2 100644
--- a/client/tests/scrashme/scrashme.py
+++ b/client/tests/scrashme/scrashme.py
@@ -43,7 +43,7 @@
         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def run_once(self, args_list=''):
diff --git a/client/tests/signaltest/signaltest.py b/client/tests/signaltest/signaltest.py
index 39303a1..d8d047a 100644
--- a/client/tests/signaltest/signaltest.py
+++ b/client/tests/signaltest/signaltest.py
@@ -14,7 +14,7 @@
     # git://git.kernel.org/pub/scm/linux/kernel/git/tglx/rt-tests.git
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def execute(self, args = '-t 10 -l 100000'):
diff --git a/client/tests/sparse/sparse.py b/client/tests/sparse/sparse.py
index 2a9d68c..53a0679 100644
--- a/client/tests/sparse/sparse.py
+++ b/client/tests/sparse/sparse.py
@@ -15,7 +15,7 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
 
-        utils.system('make')
+        utils.make()
         utils.system('ln check sparse')
 
         self.top_dir = self.job.tmpdir+'/sparse'
diff --git a/client/tests/spew/spew.py b/client/tests/spew/spew.py
index 8da0d28..0c04bb0 100644
--- a/client/tests/spew/spew.py
+++ b/client/tests/spew/spew.py
@@ -15,8 +15,8 @@
         utils.extract_tarball_to_dir(self.tarball, self.srcdir)
 
         os.chdir(self.srcdir)
-        utils.system('./configure')
-        utils.system('make')
+        utils.configure()
+        utils.make()
 
 
     def run_once(self, testdir = None, filesize='100M', type='write',
diff --git a/client/tests/stress/stress.py b/client/tests/stress/stress.py
index c0447b2..9b254da 100644
--- a/client/tests/stress/stress.py
+++ b/client/tests/stress/stress.py
@@ -23,8 +23,8 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
 
-        utils.system('./configure')
-        utils.system('make')
+        utils.configure()
+        utils.make()
 
 
     def run_once(self, args = '', stress_length=60):
diff --git a/client/tests/synctest/synctest.py b/client/tests/synctest/synctest.py
index 2e5dd31..37d5143 100644
--- a/client/tests/synctest/synctest.py
+++ b/client/tests/synctest/synctest.py
@@ -13,7 +13,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def run_once(self, len, loop, testdir=None):
diff --git a/client/tests/sysbench/sysbench.py b/client/tests/sysbench/sysbench.py
index 1db0ba1..8a5400c 100644
--- a/client/tests/sysbench/sysbench.py
+++ b/client/tests/sysbench/sysbench.py
@@ -25,7 +25,7 @@
         utils.system(
             'PATH=%s/bin:$PATH ./configure --with-mysql=%s --with-pgsql'
             % (pgsql_dir, mysql_dir))
-        utils.system('make -j %d' % utils.count_cpus())
+        utils.make('-j %d' % utils.count_cpus())
 
 
     def run_once(self, db_type = 'pgsql', build = 1, \
diff --git a/client/tests/systemtap/systemtap.py b/client/tests/systemtap/systemtap.py
index f220045..08720c1 100644
--- a/client/tests/systemtap/systemtap.py
+++ b/client/tests/systemtap/systemtap.py
@@ -43,8 +43,8 @@
         testsuite = os.path.join(self.srcdir, 'testsuite')
         os.chdir(testsuite)
 
-        utils.system('./configure')
-        utils.system('make')
+        utils.configure()
+        utils.make()
 
         # Run a simple systemtap script to make sure systemtap and the
         # kernel debuginfo packages are correctly installed
diff --git a/client/tests/tbench/tbench.py b/client/tests/tbench/tbench.py
index 6e98807..510bc2f 100644
--- a/client/tests/tbench/tbench.py
+++ b/client/tests/tbench/tbench.py
@@ -15,8 +15,8 @@
         utils.extract_tarball_to_dir(tarball, self.srcdir)
         os.chdir(self.srcdir)
 
-        utils.system('./configure')
-        utils.system('make')
+        utils.configure()
+        utils.make()
 
 
     def run_once(self, nprocs = None, args = ''):
diff --git a/client/tests/tsc/tsc.py b/client/tests/tsc/tsc.py
index 2bac609..1c1058d 100644
--- a/client/tests/tsc/tsc.py
+++ b/client/tests/tsc/tsc.py
@@ -9,7 +9,7 @@
 
     def setup(self):
         os.chdir(self.srcdir)
-        utils.system('make')
+        utils.make()
 
 
     def initialize(self):
diff --git a/client/tests/unixbench/unixbench.py b/client/tests/unixbench/unixbench.py
index b3fe920..1db49ac 100644
--- a/client/tests/unixbench/unixbench.py
+++ b/client/tests/unixbench/unixbench.py
@@ -19,7 +19,7 @@
 
         utils.system('patch -p1 < ../unixbench.patch')
         utils.system('patch -p1 < ../Makefile.patch')
-        utils.system('make')
+        utils.make()
         utils.system('rm pgms/select')
 
 
diff --git a/client/tests/xmtest/xmtest.py b/client/tests/xmtest/xmtest.py
index d5f8040..eb873de 100644
--- a/client/tests/xmtest/xmtest.py
+++ b/client/tests/xmtest/xmtest.py
@@ -26,8 +26,8 @@
         os.chdir(self.srcdir)
 
         utils.system('./autogen')
-        utils.system('./configure')
-        utils.system('make existing')
+        utils.configure()
+        utils.make('existing')
 
 
     def execute(self, args = ''):