fate#313584: pass bios information to XEN HVM guest

Index: xen-4.2.2-testing/tools/python/xen/xm/create.py
===================================================================
--- xen-4.2.2-testing.orig/tools/python/xen/xm/create.py
+++ xen-4.2.2-testing/tools/python/xen/xm/create.py
@@ -491,6 +491,14 @@ gopts.var('nfs_root', val="PATH",
           fn=set_value, default=None,
           use="Set the path of the root NFS directory.")
 
+gopts.var('smbios_firmware', val='FILE',
+          fn=set_value, default=None,
+          use="Path to a file that contains extra SMBIOS firmware structures.")
+
+gopts.var('acpi_firmware', val='FILE',
+          fn=set_value, default=None,
+          use="Path to a file that contains extra ACPI firmware tables.")
+
 gopts.var('device_model', val='FILE',
           fn=set_value, default=None,
           use="Path to device model program.")
@@ -1097,6 +1105,7 @@ def configure_hvm(config_image, vals):
              'boot',
              'cpuid', 'cpuid_check',
              'device_model', 'display',
+             'smbios_firmware', 'acpi_firmware',
              'fda', 'fdb',
              'gfx_passthru', 'guest_os_type',
              'hap', 'hpet',
Index: xen-4.2.2-testing/tools/python/xen/xm/xenapi_create.py
===================================================================
--- xen-4.2.2-testing.orig/tools/python/xen/xm/xenapi_create.py
+++ xen-4.2.2-testing/tools/python/xen/xm/xenapi_create.py
@@ -1086,6 +1086,8 @@ class sxp2xml:
             'apic',
             'boot',
             'device_model',
+            'smbios_firmware',
+            'acpi_firmware',
             'loader',
             'fda',
             'fdb',
Index: xen-4.2.2-testing/tools/python/xen/xend/image.py
===================================================================
--- xen-4.2.2-testing.orig/tools/python/xen/xend/image.py
+++ xen-4.2.2-testing/tools/python/xen/xend/image.py
@@ -17,7 +17,7 @@
 #============================================================================
 
 
-import os, os.path, string
+import os, os.path, string, struct, stat
 import re
 import math
 import time
@@ -123,6 +123,8 @@ class ImageHandler:
 
         self.device_model = vmConfig['platform'].get('device_model')
 
+        self.smbios_firmware =(str(vmConfig['platform'].get('smbios_firmware')))
+        self.acpi_firmware =(str(vmConfig['platform'].get('acpi_firmware')))
         self.display = vmConfig['platform'].get('display')
         self.xauthority = vmConfig['platform'].get('xauthority')
         self.vncconsole = int(vmConfig['platform'].get('vncconsole', 0))
@@ -945,6 +947,38 @@ class HVMImageHandler(ImageHandler):
                              self.vm.getDomid() ])
         return args
 
+    def _readFirmwareFile(self, filename):
+        # Sanity check
+        if filename is None or filename.strip() == "":
+            size = struct.pack('i', int(0))
+            return size + ""
+
+        log.debug("Reading firmware file %s", filename)
+        # Open
+        try:
+            fd = os.open(filename, os.O_RDONLY)
+        except Exception, e:
+            raise VmError('Unable to open firmware file %s' % filename)
+
+        # Validate file size
+        statinfo = os.fstat(fd)
+        if statinfo.st_size == 0 or statinfo.st_size > sys.maxint:
+            os.close(fd)
+            raise VmError('Firmware file %s is an invalid size' % filename)
+        if not stat.S_ISREG(statinfo.st_mode):
+            os.close(fd)
+            raise VmError('Firmware file %s is an invalid file type' % filename)
+        size = struct.pack('i', statinfo.st_size)
+
+        # Read entire file
+        try:
+            buf = os.read(fd, statinfo.st_size)
+        except Exception, e:
+            os.close(fd)
+            raise VmError('Failed reading firmware file %s' % filename)
+        os.close(fd)
+        return size+buf
+
     def buildDomain(self):
         store_evtchn = self.vm.getStorePort()
 
@@ -960,6 +994,8 @@ class HVMImageHandler(ImageHandler):
         log.debug("vcpu_avail     = %li", self.vm.getVCpuAvail())
         log.debug("acpi           = %d", self.acpi)
         log.debug("apic           = %d", self.apic)
+        log.debug("smbios_firmware= %s", self.smbios_firmware)
+        log.debug("acpi_firmware  = %s", self.acpi_firmware)
 
         rc = xc.hvm_build(domid          = self.vm.getDomid(),
                           image          = self.loader,
@@ -968,7 +1004,9 @@ class HVMImageHandler(ImageHandler):
                           vcpus          = self.vm.getVCpuCount(),
                           vcpu_avail     = self.vm.getVCpuAvail(),
                           acpi           = self.acpi,
-                          apic           = self.apic)
+                          apic           = self.apic,
+                          smbios_firmware= self._readFirmwareFile(self.smbios_firmware),
+                          acpi_firmware  = self._readFirmwareFile(self.acpi_firmware))
         rc['notes'] = { 'SUSPEND_CANCEL': 1 }
 
         rc['store_mfn'] = xc.hvm_get_param(self.vm.getDomid(),
Index: xen-4.2.2-testing/tools/python/xen/xend/XendConfig.py
===================================================================
--- xen-4.2.2-testing.orig/tools/python/xen/xend/XendConfig.py
+++ xen-4.2.2-testing/tools/python/xen/xend/XendConfig.py
@@ -147,6 +147,8 @@ XENAPI_PLATFORM_CFG_TYPES = {
     'apic': int,
     'boot': str,
     'device_model': str,
+    'smbios_firmware': str,
+    'acpi_firmware': str,
     'loader': str,
     'display' : str,
     'fda': str,
@@ -515,6 +517,10 @@ class XendConfig(dict):
             self['platform']['nomigrate'] = 0
 
         if self.is_hvm():
+            if 'smbios_firmware' not in self['platform']:
+                self['platform']['smbios_firmware'] = ""
+            if 'acpi_firmware' not in self['platform']:
+                self['platform']['acpi_firmware'] = ""
             if 'timer_mode' not in self['platform']:
                 self['platform']['timer_mode'] = 1
             if 'viridian' not in self['platform']:
Index: xen-4.2.2-testing/tools/python/xen/lowlevel/xc/xc.c
===================================================================
--- xen-4.2.2-testing.orig/tools/python/xen/lowlevel/xc/xc.c
+++ xen-4.2.2-testing/tools/python/xen/lowlevel/xc/xc.c
@@ -954,18 +954,23 @@ static PyObject *pyxc_hvm_build(XcObject
     struct hvm_info_table *va_hvm;
     uint8_t *va_map, sum;
 #endif
-    int i;
-    char *image;
+    int i, datalen;
+    char *image, *smbios_str, *acpi_str;
     int memsize, target=-1, vcpus = 1, acpi = 0, apic = 1;
+    PyObject *acpi_firmware = NULL;
+    PyObject *smbios_firmware = NULL;
     PyObject *vcpu_avail_handle = NULL;
     uint8_t vcpu_avail[(HVM_MAX_VCPUS + 7)/8];
+    struct xc_hvm_build_args hvm_args = {};
 
     static char *kwd_list[] = { "domid",
                                 "memsize", "image", "target", "vcpus", 
-                                "vcpu_avail", "acpi", "apic", NULL };
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiOii", kwd_list,
+                                "vcpu_avail", "acpi", "apic",
+                                "smbios_firmware", "acpi_firmware", NULL };
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iiOiiOO", kwd_list,
                                       &dom, &memsize, &image, &target, &vcpus,
-                                      &vcpu_avail_handle, &acpi, &apic) )
+                                      &vcpu_avail_handle, &acpi,
+                                      &apic, &smbios_firmware, &acpi_firmware) )
         return NULL;
 
     memset(vcpu_avail, 0, sizeof(vcpu_avail));
@@ -996,8 +1001,38 @@ static PyObject *pyxc_hvm_build(XcObject
     if ( target == -1 )
         target = memsize;
 
-    if ( xc_hvm_build_target_mem(self->xc_handle, dom, memsize,
-                                 target, image) != 0 )
+    memset(&hvm_args, 0, sizeof(struct xc_hvm_build_args));
+    hvm_args.mem_size = (uint64_t)memsize << 20;
+    hvm_args.mem_target = (uint64_t)target << 20;
+    hvm_args.image_file_name = image;
+
+    if ( PyString_Check(smbios_firmware ) )
+    {
+        smbios_str = PyString_AsString(smbios_firmware);
+        if ( smbios_str )
+        {
+            datalen = *(int *)smbios_str;
+            if ( datalen ) {
+                hvm_args.smbios_module.data = &((uint8_t *)smbios_str)[4];
+                hvm_args.smbios_module.length = (uint32_t)datalen;
+            }
+        }
+    }
+
+    if ( PyString_Check(acpi_firmware ) )
+    {
+        acpi_str = PyString_AsString(acpi_firmware);
+        if (acpi_str)
+        {
+            datalen = *(int *)acpi_str;
+            if ( datalen ) {
+                hvm_args.acpi_module.data = &((uint8_t *)acpi_str)[4];
+                hvm_args.acpi_module.length = (uint32_t)datalen;
+            }
+        }
+    }
+
+    if ( xc_hvm_build(self->xc_handle, dom, &hvm_args) != 0 )
         return pyxc_error_to_exception(self->xc_handle);
 
 #if !defined(__ia64__)
Index: xen-4.2.2-testing/docs/man/xmdomain.cfg.pod.5
===================================================================
--- xen-4.2.2-testing.orig/docs/man/xmdomain.cfg.pod.5
+++ xen-4.2.2-testing/docs/man/xmdomain.cfg.pod.5
@@ -243,6 +243,25 @@ this the xen kernel must be compiled wit
 
 This defaults to 1, meaning running the domain as a UP.
 
+=item B<acpi_firmware>
+
+Specify a path to a file that contains extra ACPI firmware tables to pass in to
+a guest. The file can contain several tables in their binary AML form
+concatenated together. Each table self describes its length so no additional
+information is needed. These tables will be added to the ACPI table set in the
+guest. Note that existing tables cannot be overridden by this feature. For
+example this cannot be used to override tables like DSDT, FADT, etc.
+
+=item B<smbios_firmware>
+
+Specify a path to a file that contains extra SMBIOS firmware structures to pass
+in to a guest. The file can contain a set DMTF predefined structures which will
+override the internal defaults. Not all predefined structures can be overridden,
+only the following types: 0, 1, 2, 3, 11, 22, 39. The file can also contain any
+number of vendor defined SMBIOS structures (type 128 - 255). Since SMBIOS
+structures do not present their overall size, each entry in the file must be
+preceded by a 32b integer indicating the size of the next structure.
+
 =back
 
 =head1 DOMAIN SHUTDOWN OPTIONS
Index: xen-4.2.2-testing/tools/python/README.sxpcfg
===================================================================
--- xen-4.2.2-testing.orig/tools/python/README.sxpcfg
+++ xen-4.2.2-testing/tools/python/README.sxpcfg
@@ -51,6 +51,8 @@ image
   - vncunused
   (HVM)
   - device_model
+  - smbios_firmware
+  - acpi_firmware
   - display
   - xauthority
   - vncconsole
Index: xen-4.2.2-testing/tools/python/README.XendConfig
===================================================================
--- xen-4.2.2-testing.orig/tools/python/README.XendConfig
+++ xen-4.2.2-testing/tools/python/README.XendConfig
@@ -120,6 +120,8 @@ otherConfig
                                 image.vncdisplay
                                 image.vncunused
                                 image.hvm.device_model
+                                image.hvm.smbios_firmware
+                                image.hvm.apci_firmware
                                 image.hvm.display
                                 image.hvm.xauthority
                                 image.hvm.vncconsole
