diff mbox

[V3,6/29] tools/libxl: Add a user configurable parameter to control vIOMMU attributes

Message ID 1506049330-11196-7-git-send-email-tianyu.lan@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

lan,Tianyu Sept. 22, 2017, 3:01 a.m. UTC
From: Chao Gao <chao.gao@intel.com>

A field, viommu_info, is added to struct libxl_domain_build_info. Several
attributes can be specified by guest config file for virtual IOMMU. These
attributes are used for DMAR construction and vIOMMU creation.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>

---
v3:
 - allow an array of viommu other than only one viommu to present to guest.
 During domain building, an error would be raised for
 multiple viommus case since we haven't implemented this yet.
 - provide a libxl__viommu_set_default() for viommu

---
 docs/man/xl.cfg.pod.5.in    | 27 +++++++++++++++++++++++
 tools/libxl/libxl_create.c  | 52 +++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_types.idl | 12 +++++++++++
 tools/xl/xl_parse.c         | 52 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 142 insertions(+), 1 deletion(-)

Comments

Roger Pau Monné Oct. 19, 2017, 9:49 a.m. UTC | #1
On Thu, Sep 21, 2017 at 11:01:47PM -0400, Lan Tianyu wrote:
> From: Chao Gao <chao.gao@intel.com>
> 
> A field, viommu_info, is added to struct libxl_domain_build_info. Several
> attributes can be specified by guest config file for virtual IOMMU. These
> attributes are used for DMAR construction and vIOMMU creation.

IMHO this should come much later in the series, ideally you would
introduce the xl/libxl code in the last patches, together with the
xl.cfg man page change.

> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
> 
> ---
> v3:
>  - allow an array of viommu other than only one viommu to present to guest.
>  During domain building, an error would be raised for
>  multiple viommus case since we haven't implemented this yet.
>  - provide a libxl__viommu_set_default() for viommu
> 
> ---
>  docs/man/xl.cfg.pod.5.in    | 27 +++++++++++++++++++++++
>  tools/libxl/libxl_create.c  | 52 +++++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/libxl_types.idl | 12 +++++++++++
>  tools/xl/xl_parse.c         | 52 ++++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 142 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/man/xl.cfg.pod.5.in b/docs/man/xl.cfg.pod.5.in
> index 79cb2ea..9cd7dd7 100644
> --- a/docs/man/xl.cfg.pod.5.in
> +++ b/docs/man/xl.cfg.pod.5.in
> @@ -1547,6 +1547,33 @@ L<http://www.microsoft.com/en-us/download/details.aspx?id=30707>
>  
>  =back 
>  
> +=item B<viommu=[ "VIOMMU_STRING", "VIOMMU_STRING", ...]>
> +
> +Specifies the vIOMMUs which are to be provided to the guest.
> +
> +B<VIOMMU_STRING> has the form C<KEY=VALUE,KEY=VALUE,...> where:
> +
> +=over 4
> +
> +=item B<KEY=VALUE>
> +
> +Possible B<KEY>s are:
> +
> +=over 4
> +
> +=item B<type="STRING">
> +
> +Currently there is only one valid type:
> +
> +(x86 only) "intel_vtd" means providing a emulated Intel VT-d to the guest.
> +
> +=item B<intremap=BOOLEAN>
> +
> +Specifies whether the vIOMMU should support interrupt remapping
> +and default 'true'.
> +
> +=back
> +
>  =head3 Guest Virtual Time Controls
>  
>  =over 4
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 9123585..decd7a8 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -27,6 +27,8 @@
>  
>  #include <xen-xsm/flask/flask.h>
>  
> +#define VIOMMU_VTD_BASE_ADDR        0xfed90000ULL

This should be in libxl_arch.h see LAPIC_BASE_ADDRESS.

> +
>  int libxl__domain_create_info_setdefault(libxl__gc *gc,
>                                           libxl_domain_create_info *c_info)
>  {
> @@ -59,6 +61,47 @@ void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
>                              LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT;
>  }
>  
> +static int libxl__viommu_set_default(libxl__gc *gc,
> +                                     libxl_domain_build_info *b_info)
> +{
> +    int i;
> +
> +    if (!b_info->num_viommus)
> +        return 0;
> +
> +    for (i = 0; i < b_info->num_viommus; i++) {
> +        libxl_viommu_info *viommu = &b_info->viommu[i];
> +
> +        if (libxl_defbool_is_default(viommu->intremap))
> +            libxl_defbool_set(&viommu->intremap, true);
> +
> +        if (!libxl_defbool_val(viommu->intremap)) {
> +            LOGE(ERROR, "Cannot create one virtual VTD without intremap");
> +            return ERROR_INVAL;
> +        }
> +
> +        if (viommu->type == LIBXL_VIOMMU_TYPE_INTEL_VTD) {
> +            /*
> +             * If there are multiple vIOMMUs, we need arrange all vIOMMUs to
> +             * avoid overlap. Put a check here in case we get here for multiple
> +             * vIOMMUs case.
> +             */
> +            if (b_info->num_viommus > 1) {
> +                LOGE(ERROR, "Multiple vIOMMUs support is under implementation");

s/LOGE/LOG/ LOGE should only be used when errno is set (which is not
the case here).

> +                return ERROR_INVAL;
> +            }
> +
> +            /* Set default values to unexposed fields */
> +            viommu->base_addr = VIOMMU_VTD_BASE_ADDR;
> +
> +            /* Set desired capbilities */
> +            viommu->cap = VIOMMU_CAP_IRQ_REMAPPING;

I'm not sure whether this code should be in libxl_x86.c, but
libxl__domain_build_info_setdefault is already quite messed up, so I
guess it's fine.

> +        }

Shouldn't this be:

switch(viommu->type) {
case LIBXL_VIOMMU_TYPE_INTEL_VTD:
    ...
    break;

default:
    return ERROR_INVAL;
}

So that you catch type being set to an invalid vIOMMU type?

> +    }
> +
> +    return 0;
> +}
> +
>  int libxl__domain_build_info_setdefault(libxl__gc *gc,
>                                          libxl_domain_build_info *b_info)
>  {
> @@ -214,6 +257,9 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
>  
>      libxl__arch_domain_build_info_acpi_setdefault(b_info);
>  
> +    if (libxl__viommu_set_default(gc, b_info))
> +        return ERROR_FAIL;
> +
>      switch (b_info->type) {
>      case LIBXL_DOMAIN_TYPE_HVM:
>          if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
> @@ -890,6 +936,12 @@ static void initiate_domain_create(libxl__egc *egc,
>          goto error_out;
>      }
>  
> +    if (d_config->b_info.num_viommus > 1) {
> +        ret = ERROR_INVAL;
> +        LOGD(ERROR, domid, "Cannot support multiple vIOMMUs");
> +        goto error_out;
> +    }

Er, you already have this check in libxl__viommu_set_default, and in
any case I would just rely on the hypervisor failing to create more
than one vIOMMU per domain, rather than adding the same check here.

> +
>      ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info);
>      if (ret) {
>          LOGD(ERROR, domid, "Unable to set domain create info defaults");
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 173d70a..286c960 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -450,6 +450,17 @@ libxl_altp2m_mode = Enumeration("altp2m_mode", [
>      (3, "limited"),
>      ], init_val = "LIBXL_ALTP2M_MODE_DISABLED")
>  
> +libxl_viommu_type = Enumeration("viommu_type", [
> +    (1, "intel_vtd"),
> +    ])
> +
> +libxl_viommu_info = Struct("viommu_info", [
> +    ("type",            libxl_viommu_type),
> +    ("intremap",        libxl_defbool),
> +    ("cap",             uint64),
> +    ("base_addr",       uint64),
> +    ])
> +
>  libxl_domain_build_info = Struct("domain_build_info",[
>      ("max_vcpus",       integer),
>      ("avail_vcpus",     libxl_bitmap),
> @@ -506,6 +517,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
>      # 65000 which is reserved by the toolstack.
>      ("device_tree",      string),
>      ("acpi",             libxl_defbool),
> +    ("viommu",           Array(libxl_viommu_info, "num_viommus")),
>      ("u", KeyedUnion(None, libxl_domain_type, "type",
>                  [("hvm", Struct(None, [("firmware",         string),
>                                         ("bios",             libxl_bios_type),
> diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
> index 02ddd2e..34f8128 100644
> --- a/tools/xl/xl_parse.c
> +++ b/tools/xl/xl_parse.c
> @@ -804,6 +804,38 @@ int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
>      return 0;
>  }
>  
> +/* Parses viommu data and adds info into viommu
> + * Returns 1 if the input doesn't form a valid viommu
> + * or parsed values are not correct. Successful parse returns 0 */
> +static int parse_viommu_config(libxl_viommu_info *viommu, const char *info)
> +{
> +    char *ptr, *oparg, *saveptr = NULL, *buf = xstrdup(info);
> +
> +    ptr = strtok_r(buf, ",", &saveptr);
> +    if (MATCH_OPTION("type", ptr, oparg)) {
> +        if (!strcmp(oparg, "intel_vtd")) {
> +            viommu->type = LIBXL_VIOMMU_TYPE_INTEL_VTD;
> +        } else {
> +            fprintf(stderr, "Invalid viommu type: %s\n", oparg);
> +            return 1;
> +        }
> +    } else {
> +        fprintf(stderr, "viommu type should be set first: %s\n", oparg);
> +        return 1;
> +    }
> +
> +    for (ptr = strtok_r(NULL, ",", &saveptr); ptr;
> +         ptr = strtok_r(NULL, ",", &saveptr)) {
> +        if (MATCH_OPTION("intremap", ptr, oparg)) {
> +            libxl_defbool_set(&viommu->intremap, !!strtoul(oparg, NULL, 0));

No need for the !!.

> +        } else {
> +            fprintf(stderr, "Unknown string `%s' in viommu spec\n", ptr);
> +            return 1;
> +        }
> +    }
> +    return 0;
> +}
> +
>  void parse_config_data(const char *config_source,
>                         const char *config_data,
>                         int config_len,
> @@ -813,7 +845,7 @@ void parse_config_data(const char *config_source,
>      long l, vcpus = 0;
>      XLU_Config *config;
>      XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
> -                   *usbctrls, *usbdevs, *p9devs;
> +                   *usbctrls, *usbdevs, *p9devs, *iommus;
>      XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
>                     *mca_caps;
>      int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
> @@ -1037,6 +1069,24 @@ void parse_config_data(const char *config_source,
>      xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0);
>      xlu_cfg_get_defbool(config, "acpi", &b_info->acpi, 0);
>  
> +    if (!xlu_cfg_get_list (config, "viommu", &iommus, 0, 0)) {
> +        b_info->num_viommus = 0;
> +        b_info->viommu = NULL;

This should not be needed, num_viommus and viommu should already be
zeroed by the initialize functions.

Thanks, Roger.
Chao Gao Oct. 20, 2017, 1:36 a.m. UTC | #2
On Thu, Oct 19, 2017 at 10:49:22AM +0100, Roger Pau Monné wrote:
>On Thu, Sep 21, 2017 at 11:01:47PM -0400, Lan Tianyu wrote:
>> From: Chao Gao <chao.gao@intel.com>
>> 
>> A field, viommu_info, is added to struct libxl_domain_build_info. Several
>> attributes can be specified by guest config file for virtual IOMMU. These
>> attributes are used for DMAR construction and vIOMMU creation.
>
>IMHO this should come much later in the series, ideally you would
>introduce the xl/libxl code in the last patches, together with the
>xl.cfg man page change.

It can be put to the end of this series. But I prefer to introduce the
vIOMMU from up to down (means the use interface goes first and then how
to implement a vIOMMU step by step) for it may be easier to understand. 

>
>> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
>> index 9123585..decd7a8 100644
>> --- a/tools/libxl/libxl_create.c
>> +++ b/tools/libxl/libxl_create.c
>> @@ -27,6 +27,8 @@
>>  
>>  #include <xen-xsm/flask/flask.h>
>>  
>> +#define VIOMMU_VTD_BASE_ADDR        0xfed90000ULL
>
>This should be in libxl_arch.h see LAPIC_BASE_ADDRESS.

Agree.

>
>> +
>>  int libxl__domain_create_info_setdefault(libxl__gc *gc,
>>                                           libxl_domain_create_info *c_info)
>>  {
>> @@ -59,6 +61,47 @@ void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
>>                              LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT;
>>  }
>>  
>> +static int libxl__viommu_set_default(libxl__gc *gc,
>> +                                     libxl_domain_build_info *b_info)
>> +{
>> +    int i;
>> +
>> +    if (!b_info->num_viommus)
>> +        return 0;
>> +
>> +    for (i = 0; i < b_info->num_viommus; i++) {
>> +        libxl_viommu_info *viommu = &b_info->viommu[i];
>> +
>> +        if (libxl_defbool_is_default(viommu->intremap))
>> +            libxl_defbool_set(&viommu->intremap, true);
>> +
>> +        if (!libxl_defbool_val(viommu->intremap)) {
>> +            LOGE(ERROR, "Cannot create one virtual VTD without intremap");
>> +            return ERROR_INVAL;
>> +        }
>> +
>> +        if (viommu->type == LIBXL_VIOMMU_TYPE_INTEL_VTD) {
>> +            /*
>> +             * If there are multiple vIOMMUs, we need arrange all vIOMMUs to
>> +             * avoid overlap. Put a check here in case we get here for multiple
>> +             * vIOMMUs case.
>> +             */
>> +            if (b_info->num_viommus > 1) {
>> +                LOGE(ERROR, "Multiple vIOMMUs support is under implementation");
>
>s/LOGE/LOG/ LOGE should only be used when errno is set (which is not
>the case here).

yes.

>
>> +                return ERROR_INVAL;
>> +            }
>> +
>> +            /* Set default values to unexposed fields */
>> +            viommu->base_addr = VIOMMU_VTD_BASE_ADDR;
>> +
>> +            /* Set desired capbilities */
>> +            viommu->cap = VIOMMU_CAP_IRQ_REMAPPING;
>
>I'm not sure whether this code should be in libxl_x86.c, but
>libxl__domain_build_info_setdefault is already quite messed up, so I
>guess it's fine.
>
>> +        }
>
>Shouldn't this be:
>
>switch(viommu->type) {
>case LIBXL_VIOMMU_TYPE_INTEL_VTD:
>    ...
>    break;
>
>default:
>    return ERROR_INVAL;
>}
>
>So that you catch type being set to an invalid vIOMMU type?

sure. Will update.

>
>> +    if (d_config->b_info.num_viommus > 1) {
>> +        ret = ERROR_INVAL;
>> +        LOGD(ERROR, domid, "Cannot support multiple vIOMMUs");
>> +        goto error_out;
>> +    }
>
>Er, you already have this check in libxl__viommu_set_default, and in
>any case I would just rely on the hypervisor failing to create more
>than one vIOMMU per domain, rather than adding the same check here.

It is fine to me. Will remove all checks against viommu numbers in
toolstack.

Thanks
chao
diff mbox

Patch

diff --git a/docs/man/xl.cfg.pod.5.in b/docs/man/xl.cfg.pod.5.in
index 79cb2ea..9cd7dd7 100644
--- a/docs/man/xl.cfg.pod.5.in
+++ b/docs/man/xl.cfg.pod.5.in
@@ -1547,6 +1547,33 @@  L<http://www.microsoft.com/en-us/download/details.aspx?id=30707>
 
 =back 
 
+=item B<viommu=[ "VIOMMU_STRING", "VIOMMU_STRING", ...]>
+
+Specifies the vIOMMUs which are to be provided to the guest.
+
+B<VIOMMU_STRING> has the form C<KEY=VALUE,KEY=VALUE,...> where:
+
+=over 4
+
+=item B<KEY=VALUE>
+
+Possible B<KEY>s are:
+
+=over 4
+
+=item B<type="STRING">
+
+Currently there is only one valid type:
+
+(x86 only) "intel_vtd" means providing a emulated Intel VT-d to the guest.
+
+=item B<intremap=BOOLEAN>
+
+Specifies whether the vIOMMU should support interrupt remapping
+and default 'true'.
+
+=back
+
 =head3 Guest Virtual Time Controls
 
 =over 4
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 9123585..decd7a8 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -27,6 +27,8 @@ 
 
 #include <xen-xsm/flask/flask.h>
 
+#define VIOMMU_VTD_BASE_ADDR        0xfed90000ULL
+
 int libxl__domain_create_info_setdefault(libxl__gc *gc,
                                          libxl_domain_create_info *c_info)
 {
@@ -59,6 +61,47 @@  void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
                             LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT;
 }
 
+static int libxl__viommu_set_default(libxl__gc *gc,
+                                     libxl_domain_build_info *b_info)
+{
+    int i;
+
+    if (!b_info->num_viommus)
+        return 0;
+
+    for (i = 0; i < b_info->num_viommus; i++) {
+        libxl_viommu_info *viommu = &b_info->viommu[i];
+
+        if (libxl_defbool_is_default(viommu->intremap))
+            libxl_defbool_set(&viommu->intremap, true);
+
+        if (!libxl_defbool_val(viommu->intremap)) {
+            LOGE(ERROR, "Cannot create one virtual VTD without intremap");
+            return ERROR_INVAL;
+        }
+
+        if (viommu->type == LIBXL_VIOMMU_TYPE_INTEL_VTD) {
+            /*
+             * If there are multiple vIOMMUs, we need arrange all vIOMMUs to
+             * avoid overlap. Put a check here in case we get here for multiple
+             * vIOMMUs case.
+             */
+            if (b_info->num_viommus > 1) {
+                LOGE(ERROR, "Multiple vIOMMUs support is under implementation");
+                return ERROR_INVAL;
+            }
+
+            /* Set default values to unexposed fields */
+            viommu->base_addr = VIOMMU_VTD_BASE_ADDR;
+
+            /* Set desired capbilities */
+            viommu->cap = VIOMMU_CAP_IRQ_REMAPPING;
+        }
+    }
+
+    return 0;
+}
+
 int libxl__domain_build_info_setdefault(libxl__gc *gc,
                                         libxl_domain_build_info *b_info)
 {
@@ -214,6 +257,9 @@  int libxl__domain_build_info_setdefault(libxl__gc *gc,
 
     libxl__arch_domain_build_info_acpi_setdefault(b_info);
 
+    if (libxl__viommu_set_default(gc, b_info))
+        return ERROR_FAIL;
+
     switch (b_info->type) {
     case LIBXL_DOMAIN_TYPE_HVM:
         if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
@@ -890,6 +936,12 @@  static void initiate_domain_create(libxl__egc *egc,
         goto error_out;
     }
 
+    if (d_config->b_info.num_viommus > 1) {
+        ret = ERROR_INVAL;
+        LOGD(ERROR, domid, "Cannot support multiple vIOMMUs");
+        goto error_out;
+    }
+
     ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info);
     if (ret) {
         LOGD(ERROR, domid, "Unable to set domain create info defaults");
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 173d70a..286c960 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -450,6 +450,17 @@  libxl_altp2m_mode = Enumeration("altp2m_mode", [
     (3, "limited"),
     ], init_val = "LIBXL_ALTP2M_MODE_DISABLED")
 
+libxl_viommu_type = Enumeration("viommu_type", [
+    (1, "intel_vtd"),
+    ])
+
+libxl_viommu_info = Struct("viommu_info", [
+    ("type",            libxl_viommu_type),
+    ("intremap",        libxl_defbool),
+    ("cap",             uint64),
+    ("base_addr",       uint64),
+    ])
+
 libxl_domain_build_info = Struct("domain_build_info",[
     ("max_vcpus",       integer),
     ("avail_vcpus",     libxl_bitmap),
@@ -506,6 +517,7 @@  libxl_domain_build_info = Struct("domain_build_info",[
     # 65000 which is reserved by the toolstack.
     ("device_tree",      string),
     ("acpi",             libxl_defbool),
+    ("viommu",           Array(libxl_viommu_info, "num_viommus")),
     ("u", KeyedUnion(None, libxl_domain_type, "type",
                 [("hvm", Struct(None, [("firmware",         string),
                                        ("bios",             libxl_bios_type),
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 02ddd2e..34f8128 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -804,6 +804,38 @@  int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
     return 0;
 }
 
+/* Parses viommu data and adds info into viommu
+ * Returns 1 if the input doesn't form a valid viommu
+ * or parsed values are not correct. Successful parse returns 0 */
+static int parse_viommu_config(libxl_viommu_info *viommu, const char *info)
+{
+    char *ptr, *oparg, *saveptr = NULL, *buf = xstrdup(info);
+
+    ptr = strtok_r(buf, ",", &saveptr);
+    if (MATCH_OPTION("type", ptr, oparg)) {
+        if (!strcmp(oparg, "intel_vtd")) {
+            viommu->type = LIBXL_VIOMMU_TYPE_INTEL_VTD;
+        } else {
+            fprintf(stderr, "Invalid viommu type: %s\n", oparg);
+            return 1;
+        }
+    } else {
+        fprintf(stderr, "viommu type should be set first: %s\n", oparg);
+        return 1;
+    }
+
+    for (ptr = strtok_r(NULL, ",", &saveptr); ptr;
+         ptr = strtok_r(NULL, ",", &saveptr)) {
+        if (MATCH_OPTION("intremap", ptr, oparg)) {
+            libxl_defbool_set(&viommu->intremap, !!strtoul(oparg, NULL, 0));
+        } else {
+            fprintf(stderr, "Unknown string `%s' in viommu spec\n", ptr);
+            return 1;
+        }
+    }
+    return 0;
+}
+
 void parse_config_data(const char *config_source,
                        const char *config_data,
                        int config_len,
@@ -813,7 +845,7 @@  void parse_config_data(const char *config_source,
     long l, vcpus = 0;
     XLU_Config *config;
     XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
-                   *usbctrls, *usbdevs, *p9devs;
+                   *usbctrls, *usbdevs, *p9devs, *iommus;
     XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
                    *mca_caps;
     int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
@@ -1037,6 +1069,24 @@  void parse_config_data(const char *config_source,
     xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0);
     xlu_cfg_get_defbool(config, "acpi", &b_info->acpi, 0);
 
+    if (!xlu_cfg_get_list (config, "viommu", &iommus, 0, 0)) {
+        b_info->num_viommus = 0;
+        b_info->viommu = NULL;
+        while ((buf = xlu_cfg_get_listitem (iommus, b_info->num_viommus))
+                != NULL) {
+            libxl_viommu_info *viommu;
+
+            viommu = ARRAY_EXTEND_INIT_NODEVID(b_info->viommu,
+                                               b_info->num_viommus,
+                                               libxl_viommu_info_init);
+
+            if (parse_viommu_config(viommu, buf)) {
+                fprintf(stderr, "ERROR: invalid viommu setting\n");
+                exit (1);
+            }
+        }
+    }
+
     switch(b_info->type) {
     case LIBXL_DOMAIN_TYPE_HVM:
         kernel_basename = libxl_basename(b_info->kernel);