]> xenbits.xensource.com Git - xen.git/commitdiff
xl, libxl: Add per-device and global permissive config options for pci passthrough
authorGeorge Dunlap <george.dunlap@eu.citrix.com>
Wed, 4 Apr 2012 15:06:42 +0000 (16:06 +0100)
committerGeorge Dunlap <george.dunlap@eu.citrix.com>
Wed, 4 Apr 2012 15:06:42 +0000 (16:06 +0100)
By default pciback only allows PV guests to write "known safe" values into
PCI config space.  But many devices require writes to other areas of config
space in order to operate properly.  One way to do that is with the "quirks"
interface, which specifies areas known safe to a particular device; the
other way is to mark a device as "permissive", which tells pciback to allow
all config space writes for that domain and device.

This adds a "permissive" flag to the libxl_pci struct and teaches libxl how
to write the appropriate value into sysfs to enable the permissive feature for
devices being passed through.  It also adds the permissive config options either
on a per-device basis, or as a global option in the xl command-line.

Because of the potential stability and security implications of enabling
permissive, the flag is left off by default.

Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson.citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
docs/man/xl.cfg.pod.5
tools/libxl/libxl_pci.c
tools/libxl/libxl_types.idl
tools/libxl/libxlu_pci.c
tools/libxl/xl_cmdimpl.c

index 9c54bc720caec067c1a8e8409f0a6cdbd1e12ff2..e2cd2519ce31d45b0b4a91b5790e018b71ea7a50 100644 (file)
@@ -301,10 +301,31 @@ XXX
 
 XXX
 
+=item B<permissive=BOOLEAN>
+
+(PV only) By default pciback only allows PV guests to write "known
+safe" values into PCI config space.  But many devices require writes
+to other areas of config space in order to operate properly.  This
+tells the pciback driver to allow all writes to PCI config space of
+this device by this domain.  This option should be enabled with
+caution: it gives the guest much more control over the device, which
+may have security or stability implications.  It is recommended to
+enable this option only for trusted VMs under administrator control.
+
 =back
 
 =back
 
+=item B<pci_permissive=BOOLEAN>
+
+(PV only) Changes the default value of 'permissive' for all PCI
+devices for this VM.  This can still be overriden on a per-device
+basis. This option should be enabled with caution: it gives the guest
+much more control over the device, which may have security or
+stability implications.  It is recommended to enable this option only
+for trusted VMs under administrator control.  See the "pci=" section
+for more information on the "permissive" flag.
+
 =back
 
 =head2 Paravirtualised (PV) Guest Specific Options
index 94077c94d27dbb1e29a67cd4415edea392378b95..e8b88398478963216de6a202984d1d5b2fae7fad 100644 (file)
@@ -55,7 +55,10 @@ static void libxl_create_pci_backend_device(libxl__gc *gc, flexarray_t *back, in
     if (pcidev->vdevfn)
         flexarray_append_pair(back, libxl__sprintf(gc, "vdevfn-%d", num), libxl__sprintf(gc, "%x", pcidev->vdevfn));
     flexarray_append(back, libxl__sprintf(gc, "opts-%d", num));
-    flexarray_append(back, libxl__sprintf(gc, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
+    flexarray_append(back,
+              libxl__sprintf(gc, "msitranslate=%d,power_mgmt=%d,permissive=%d",
+                             pcidev->msitranslate, pcidev->power_mgmt,
+                             pcidev->permissive));
     flexarray_append_pair(back, libxl__sprintf(gc, "state-%d", num), libxl__sprintf(gc, "%d", 1));
 }
 
@@ -565,6 +568,31 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, i
             }
         }
         fclose(f);
+
+        /* Don't restrict writes to the PCI config space from this VM */
+        if (pcidev->permissive) {
+            int fd;
+            char *buf;
+            
+            sysfs_path = libxl__sprintf(gc, SYSFS_PCIBACK_DRIVER"/permissive");
+            fd = open(sysfs_path, O_WRONLY);
+            if (fd < 0) {
+                LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't open %s",
+                                 sysfs_path);
+                return ERROR_FAIL;
+            }
+            buf = libxl__sprintf(gc, PCI_BDF, pcidev->domain, pcidev->bus,
+                                 pcidev->dev, pcidev->func);
+            rc = write(fd, buf, strlen(buf));
+            /* Annoying to have two if's, but we need the errno */
+            if (rc < 0)
+                LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                                 "write to %s returned %d", sysfs_path, rc);
+            close(fd);
+            if (rc < 0)
+                return ERROR_FAIL;
+        }
         break;
     }
     default:
@@ -958,6 +986,9 @@ static void libxl__device_pci_from_xs_be(libxl__gc *gc,
             } else if (!strcmp(p, "power_mgmt")) {
                 p = strtok_r(NULL, ",=", &saveptr);
                 pci->power_mgmt = atoi(p);
+            } else if (!strcmp(p, "permissive")) {
+                p = strtok_r(NULL, ",=", &saveptr);
+                pci->permissive = atoi(p);
             }
         } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
     }
index 09089b219fcb7d292b4f4e3e7de657c8674e9f16..5cf9708c4c3d8e2761f78fc5b81c5b1fa5fbb92c 100644 (file)
@@ -354,6 +354,7 @@ libxl_device_pci = Struct("device_pci", [
     ("vfunc_mask", uint32),
     ("msitranslate", bool),
     ("power_mgmt", bool),
+    ("permissive", bool),
     ])
 
 libxl_diskinfo = Struct("diskinfo", [
index cc70d9fdf5fc1ea508daeb8e1265fa0b02a0e392..f5dee93b7918e3eb332c1a14b0776803bd9cc1bf 100644 (file)
@@ -139,6 +139,8 @@ int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str
                     pcidev->msitranslate = atoi(tok);
                 }else if ( !strcmp(optkey, "power_mgmt") ) {
                     pcidev->power_mgmt = atoi(tok);
+                }else if ( !strcmp(optkey, "permissive") ) {
+                    pcidev->permissive = atoi(tok);
                 }else{
                     XLU__PCI_ERR(cfg, "Unknown PCI BDF option: %s", optkey);
                 }
index fd458a61c5e1c2fd0e05eede6df9acd3deb356ad..6f4dd09c8857f630228d3fa909b7f70a6aed3e6b 100644 (file)
@@ -518,6 +518,7 @@ static void parse_config_data(const char *configfile_filename_report,
     XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids;
     int pci_power_mgmt = 0;
     int pci_msitranslate = 1;
+    int pci_permissive = 0;
     int e;
 
     libxl_domain_create_info *c_info = &d_config->c_info;
@@ -991,6 +992,9 @@ skip_vfb:
     if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l, 0))
         pci_power_mgmt = l;
 
+    if (!xlu_cfg_get_long (config, "pci_permissive", &l, 0))
+        pci_permissive = l;
+
     /* To be reworked (automatically enabled) once the auto ballooning
      * after guest starts is done (with PCI devices passed in). */
     if (c_info->type == LIBXL_DOMAIN_TYPE_PV) {
@@ -1010,6 +1014,7 @@ skip_vfb:
 
             pcidev->msitranslate = pci_msitranslate;
             pcidev->power_mgmt = pci_power_mgmt;
+            pcidev->permissive = pci_permissive;
             if (!xlu_pci_parse_bdf(config, pcidev, buf))
                 d_config->num_pcidevs++;
         }