@@ -1803,6 +1803,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
@@ -81,6 +81,7 @@ int libxl__arch_extra_memory(libxl__gc *gc,
#if defined(__i386__) || defined(__x86_64__)
#define LAPIC_BASE_ADDRESS 0xfee00000
+#define VTD_BASE_ADDRESS 0xfed90000
int libxl__dom_load_acpi(libxl__gc *gc,
const libxl_domain_build_info *b_info,
@@ -59,6 +59,50 @@ 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;
+
+ 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)) {
+ LOG(ERROR, "Cannot create one virtual VTD without intremap");
+ return ERROR_INVAL;
+ }
+
+ switch (viommu->type) {
+ case 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) {
+ LOG(ERROR, "Multiple vIOMMUs support is under implementation");
+ return ERROR_INVAL;
+ }
+
+ /* Set default values to unexposed fields */
+ viommu->base_addr = VTD_BASE_ADDRESS;
+
+ /* Set desired capbilities */
+ viommu->cap = VIOMMU_CAP_IRQ_REMAPPING;
+
+ break;
+
+ default:
+ return ERROR_INVAL;
+ }
+ }
+
+ return 0;
+}
+
int libxl__domain_build_info_setdefault(libxl__gc *gc,
libxl_domain_build_info *b_info)
{
@@ -218,6 +262,9 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
libxl__arch_domain_build_info_acpi_setdefault(b_info);
libxl_defbool_setdefault(&b_info->dm_restrict, false);
+ 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)
@@ -457,6 +457,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),
@@ -522,6 +533,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
("nested_hvm", libxl_defbool),
("apic", libxl_defbool),
("dm_restrict", 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),
@@ -851,6 +851,38 @@ out:
return rc;
}
+/* 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,
@@ -860,7 +892,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, *vdispls;
+ *usbctrls, *usbdevs, *p9devs, *vdispls, *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;
@@ -1199,6 +1231,22 @@ void parse_config_data(const char *config_source,
xlu_cfg_get_defbool(config, "nestedhvm", &b_info->nested_hvm, 0);
xlu_cfg_get_defbool(config, "apic", &b_info->apic, 0);
+ if (!xlu_cfg_get_list (config, "viommu", &iommus, 0, 0)) {
+ 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);