libxl: HVM firmware passthrough support
authorRoss Philipson <ross.philipson@citrix.com>
Fri, 15 Feb 2013 13:32:16 +0000 (13:32 +0000)
committerRoss Philipson <ross.philipson@citrix.com>
Fri, 15 Feb 2013 13:32:16 +0000 (13:32 +0000)
This patch introduces support for two new parameters in libxl:

smbios_firmware=<path_to_smbios_structures_file>
acpi_firmware=<path_to_acpi_tables_file>

The changes are primarily in the domain building code where the firmware files
are read and passed to libxc for loading into the new guest. After the domain
building call to libxc, the addresses for the loaded blobs are returned and
written to xenstore.

LIBXL_HAVE_FIRMWARE_PASSTHROUGH is defined in libxl.h to allow users to
determine if the feature is present.

This patch also updates the xl.cfg man page with descriptions of the two new
parameters for firmware passthrough.

Signed-off-by: Ross Philipson <ross.philipson@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
docs/man/xl.cfg.pod.5
tools/libxl/libxl.h
tools/libxl/libxl_dom.c
tools/libxl/libxl_types.idl
tools/libxl/xl_cmdimpl.c

index caba1628f5d9392b45e0f59e7a9f892299fa220c..48e05c4a7cdbb2fa0e211107199c487458b911cd 100644 (file)
@@ -829,6 +829,25 @@ libxl: 'host,tm=0,sse3=0'
 More info about the CPUID instruction can be found in the processor manuals, and
 in Wikipedia: L<http://en.wikipedia.org/wiki/CPUID>
 
+=item B<acpi_firmware="STRING">
+
+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="STRING">
+
+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 
 
 =head3 Guest Virtual Time Controls
index 72e5efb6d1f18b99ef373e86011afe52dc0cf2ba..030aa86d52c79d011c7bf385bd8a92438a082124 100644 (file)
  * the same $(XEN_VERSION) (e.g. throughout a major release).
  */
 
+/*
+ * LIBXL_HAVE_FIRMWARE_PASSTHROUGH indicates the feature for
+ * passing in SMBIOS and ACPI firmware to HVM guests is present
+ * in the library.
+ */
+#define LIBXL_HAVE_FIRMWARE_PASSTHROUGH 1
+
 /*
  * libxl ABI compatibility
  *
index 33ae5583d88c92adf193a98eb0f201e6a9d31990..8fe4fc4d063aa3382e3f738cea14a81ac0ef7815 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <xc_dom.h>
 #include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/hvm_xs_strings.h>
 
 libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid)
 {
@@ -510,11 +511,61 @@ static int hvm_build_set_params(xc_interface *handle, uint32_t domid,
     return 0;
 }
 
-static const char *libxl__domain_firmware(libxl__gc *gc,
-                                          libxl_domain_build_info *info)
+static int hvm_build_set_xs_values(libxl__gc *gc,
+                                   uint32_t domid,
+                                   struct xc_hvm_build_args *args)
+{
+    char *path = NULL;
+    int ret = 0;
+
+    if (args->smbios_module.guest_addr_out) {
+        path = GCSPRINTF("/local/domain/%d/"HVM_XS_SMBIOS_PT_ADDRESS, domid);
+
+        ret = libxl__xs_write(gc, XBT_NULL, path, "0x%"PRIx64,
+                              args->smbios_module.guest_addr_out);
+        if (ret)
+            goto err;
+
+        path = GCSPRINTF("/local/domain/%d/"HVM_XS_SMBIOS_PT_LENGTH, domid);
+
+        ret = libxl__xs_write(gc, XBT_NULL, path, "0x%x",
+                              args->smbios_module.length);
+        if (ret)
+            goto err;
+    }
+
+    if (args->acpi_module.guest_addr_out) {
+        path = GCSPRINTF("/local/domain/%d/"HVM_XS_ACPI_PT_ADDRESS, domid);
+
+        ret = libxl__xs_write(gc, XBT_NULL, path, "0x%"PRIx64,
+                              args->acpi_module.guest_addr_out);
+        if (ret)
+            goto err;
+
+        path = GCSPRINTF("/local/domain/%d/"HVM_XS_ACPI_PT_LENGTH, domid);
+
+        ret = libxl__xs_write(gc, XBT_NULL, path, "0x%x",
+                              args->acpi_module.length);
+        if (ret)
+            goto err;
+    }
+
+    return 0;
+
+err:
+    LOG(ERROR, "failed to write firmware xenstore value, err: %d", ret);
+    return ret;
+}
+
+static int libxl__domain_firmware(libxl__gc *gc,
+                                  libxl_domain_build_info *info,
+                                  struct xc_hvm_build_args *args)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
     const char *firmware;
+    int e, rc = ERROR_FAIL;
+    int datalen = 0;
+    void *data;
 
     if (info->u.hvm.firmware)
         firmware = info->u.hvm.firmware;
@@ -528,13 +579,52 @@ static const char *libxl__domain_firmware(libxl__gc *gc,
             firmware = "hvmloader";
             break;
         default:
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "invalid device model version %d",
-                       info->device_model_version);
-            return NULL;
+            LOG(ERROR, "invalid device model version %d",
+                info->device_model_version);
+            return ERROR_FAIL;
             break;
         }
     }
-    return libxl__abs_path(gc, firmware, libxl__xenfirmwaredir_path());
+    args->image_file_name = libxl__abs_path(gc, firmware,
+                                            libxl__xenfirmwaredir_path());
+
+    if (info->u.hvm.smbios_firmware) {
+        data = NULL;
+        e = libxl_read_file_contents(ctx, info->u.hvm.smbios_firmware,
+                                     &data, &datalen);
+        if (e) {
+            LOGEV(ERROR, e, "failed to read SMBIOS firmware file %s",
+                info->u.hvm.smbios_firmware);
+            goto out;
+        }
+        libxl__ptr_add(gc, data);
+        if (datalen) {
+            /* Only accept non-empty files */
+            args->smbios_module.data = data;
+            args->smbios_module.length = (uint32_t)datalen;
+        }
+    }
+
+    if (info->u.hvm.acpi_firmware) {
+        data = NULL;
+        e = libxl_read_file_contents(ctx, info->u.hvm.acpi_firmware,
+                                     &data, &datalen);
+        if (e) {
+            LOGEV(ERROR, e, "failed to read ACPI firmware file %s",
+                info->u.hvm.acpi_firmware);
+            goto out;
+        }
+        libxl__ptr_add(gc, data);
+        if (datalen) {
+            /* Only accept non-empty files */
+            args->acpi_module.data = data;
+            args->acpi_module.length = (uint32_t)datalen;
+        }
+    }
+
+    return 0;
+out:
+    return rc;
 }
 
 int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
@@ -544,10 +634,6 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
     libxl_ctx *ctx = libxl__gc_owner(gc);
     struct xc_hvm_build_args args = {};
     int ret, rc = ERROR_FAIL;
-    const char *firmware = libxl__domain_firmware(gc, info);
-
-    if (!firmware)
-        goto out;
 
     memset(&args, 0, sizeof(struct xc_hvm_build_args));
     /* The params from the configuration file are in Mb, which are then
@@ -557,22 +643,34 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
      */
     args.mem_size = (uint64_t)(info->max_memkb - info->video_memkb) << 10;
     args.mem_target = (uint64_t)(info->target_memkb - info->video_memkb) << 10;
-    args.image_file_name = firmware;
+
+    if (libxl__domain_firmware(gc, info, &args)) {
+        LOG(ERROR, "initializing domain firmware failed");
+        goto out;
+    }
 
     ret = xc_hvm_build(ctx->xch, domid, &args);
     if (ret) {
-        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm building failed");
+        LOGEV(ERROR, ret, "hvm building failed");
         goto out;
     }
+
     ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port,
                                &state->store_mfn, state->console_port,
                                &state->console_mfn, state->store_domid,
                                state->console_domid);
     if (ret) {
-        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm build set params failed");
+        LOGEV(ERROR, ret, "hvm build set params failed");
         goto out;
     }
-    rc = 0;
+
+    ret = hvm_build_set_xs_values(gc, domid, &args);
+    if (ret) {
+        LOG(ERROR, "hvm build set xenstore values failed (ret=%d)", ret);
+        goto out;
+    }
+
+    return 0;
 out:
     return rc;
 }
@@ -634,7 +732,7 @@ int libxl__toolstack_restore(uint32_t domid, const uint8_t *buf,
 
     memcpy(&count, ptr, sizeof(count));
     ptr += sizeof(count);
+
     if (size < sizeof(version) + sizeof(count) +
             count * (sizeof(struct libxl__physmap_info))) {
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "wrong size");
@@ -848,7 +946,7 @@ static void switch_logdirty_xswatch(libxl__egc *egc, libxl__ev_xswatch *watch,
         rc = libxl__xs_rm_checked(gc, t, lds->ret_path);
         if (rc) goto out;
 
-        rc = libxl__xs_transaction_commit(gc, &t); 
+        rc = libxl__xs_transaction_commit(gc, &t);
         if (!rc) break;
         if (rc<0) goto out;
     }
@@ -1320,7 +1418,7 @@ void libxl__xc_domain_save_done(libxl__egc *egc, void *dss_void,
     if (type == LIBXL_DOMAIN_TYPE_HVM) {
         rc = libxl__domain_suspend_device_model(gc, dss);
         if (rc) goto out;
-        
+
         libxl__domain_save_device_model(egc, dss, domain_suspend_done);
         return;
     }
index acc4bc9d9c2212da7daf25915ec5cb804c6f443e..89a80300fef4e48ceea1127163ac4c90c5065840 100644 (file)
@@ -308,6 +308,8 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                        ("vpt_align",        libxl_defbool),
                                        ("timer_mode",       libxl_timer_mode),
                                        ("nested_hvm",       libxl_defbool),
+                                       ("smbios_firmware",  string),
+                                       ("acpi_firmware",    string),
                                        ("nographic",        libxl_defbool),
                                        ("vga",              libxl_vga_interface_info),
                                        ("vnc",              libxl_vnc_info),
index bdd1865bf6e8fd975bfaceaaa2692d5577ae6c89..9c554ba040fcf9d2d67b48799b71a40676015945 100644 (file)
@@ -882,6 +882,11 @@ static void parse_config_data(const char *config_source,
         }
 
         xlu_cfg_get_defbool(config, "nestedhvm", &b_info->u.hvm.nested_hvm, 0);
+
+        xlu_cfg_replace_string(config, "smbios_firmware",
+                               &b_info->u.hvm.smbios_firmware, 0);
+        xlu_cfg_replace_string(config, "acpi_firmware",
+                               &b_info->u.hvm.acpi_firmware, 0);
         break;
     case LIBXL_DOMAIN_TYPE_PV:
     {