debuggers.hg

changeset 20482:8a1d2e35edfa

libxenlight: implement pci passthrough

This patch implements pci passthrough (hotplug and coldplug) in
libxenlight, it also adds three new commands to xl: pci-attach,
pci-detach and pci-list.
Currently flr on a device is done writing to
/sys/bus/pci/drivers/pciback/do_flr
pciback do_flr is present in both XCI and XCP 2.6.27 kernels.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Nov 13 15:31:16 2009 +0000 (2009-11-13)
parents d714386b668f
children 64599a2d310d
files tools/libxl/libxl.c tools/libxl/libxl.h tools/libxl/libxl_device.c tools/libxl/libxl_internal.h tools/libxl/xl.c
line diff
     1.1 --- a/tools/libxl/libxl.c	Fri Nov 13 15:30:24 2009 +0000
     1.2 +++ b/tools/libxl/libxl.c	Fri Nov 13 15:31:16 2009 +0000
     1.3 @@ -156,6 +156,7 @@ retry_transaction:
     1.4  
     1.5      xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
     1.6      xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
     1.7 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/image/ostype", vm_path), "hvm", strlen("hvm"));
     1.8  
     1.9      libxl_xs_writev(ctx, t, dom_path, info->xsdata);
    1.10      libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
    1.11 @@ -368,6 +369,8 @@ int libxl_domain_destroy(struct libxl_ct
    1.12          XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
    1.13          return -1;
    1.14      }
    1.15 +    if (libxl_device_pci_shutdown(ctx, domid) < 0)
    1.16 +        XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid);
    1.17      xs_write(ctx->xsh, XBT_NULL,
    1.18               libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
    1.19               "shutdown", strlen("shutdown"));
    1.20 @@ -375,7 +378,6 @@ int libxl_domain_destroy(struct libxl_ct
    1.21          XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
    1.22          return -1;
    1.23      }
    1.24 -    /* do_FLR */
    1.25      if (xc_domain_destroy(ctx->xch, domid) < 0) {
    1.26          XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
    1.27          return -1;
    1.28 @@ -746,17 +748,417 @@ int libxl_device_vfb_hard_shutdown(struc
    1.29  }
    1.30  
    1.31  /******************************************************************************/
    1.32 -int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid)
    1.33 +
    1.34 +int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
    1.35 +                          unsigned int bus, unsigned int dev,
    1.36 +                          unsigned int func, unsigned int vdevfn)
    1.37 +{
    1.38 +    pcidev->domain = domain;
    1.39 +    pcidev->bus = bus;
    1.40 +    pcidev->dev = dev;
    1.41 +    pcidev->func = func;
    1.42 +    pcidev->vdevfn = vdevfn;
    1.43 +    return 0;
    1.44 +}
    1.45 +
    1.46 +static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
    1.47 +{
    1.48 +    flexarray_t *front;
    1.49 +    flexarray_t *back;
    1.50 +    unsigned int boffset = 0;
    1.51 +    unsigned int foffset = 0;
    1.52 +    libxl_device device;
    1.53 +    int i;
    1.54 +
    1.55 +    front = flexarray_make(16, 1);
    1.56 +    if (!front)
    1.57 +        return ERROR_NOMEM;
    1.58 +    back = flexarray_make(16, 1);
    1.59 +    if (!back)
    1.60 +        return ERROR_NOMEM;
    1.61 +
    1.62 +    XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n");
    1.63 +
    1.64 +    /* add pci device */
    1.65 +    device.backend_devid = 0;
    1.66 +    device.backend_domid = 0;
    1.67 +    device.backend_kind = DEVICE_PCI;
    1.68 +    device.devid = 0;
    1.69 +    device.domid = domid;
    1.70 +    device.kind = DEVICE_PCI;
    1.71 +
    1.72 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
    1.73 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
    1.74 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
    1.75 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
    1.76 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
    1.77 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
    1.78 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
    1.79 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
    1.80 +    for (i = 0; i < num; i++) {
    1.81 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
    1.82 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
    1.83 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
    1.84 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
    1.85 +        if (pcidev->vdevfn) {
    1.86 +            flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
    1.87 +            flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
    1.88 +        }
    1.89 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
    1.90 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
    1.91 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
    1.92 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
    1.93 +    }
    1.94 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
    1.95 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
    1.96 +
    1.97 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
    1.98 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
    1.99 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
   1.100 +    flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
   1.101 +
   1.102 +    libxl_device_generic_add(ctx, &device,
   1.103 +                             libxl_xs_kvs_of_flexarray(ctx, back, boffset),
   1.104 +                             libxl_xs_kvs_of_flexarray(ctx, front, foffset));
   1.105 +
   1.106 +    flexarray_free(back);
   1.107 +    flexarray_free(front);
   1.108 +    return 0;
   1.109 +}
   1.110 +
   1.111 +static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.112  {
   1.113 -    return ERROR_NI;
   1.114 +    flexarray_t *back;
   1.115 +    char *num_devs, *be_path;
   1.116 +    int num = 0;
   1.117 +    unsigned int boffset = 0;
   1.118 +    xs_transaction_t t;
   1.119 +
   1.120 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.121 +    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
   1.122 +    if (!num_devs)
   1.123 +        return libxl_create_pci_backend(ctx, domid, pcidev, 1);
   1.124 +
   1.125 +    if (!is_hvm(ctx, domid)) {
   1.126 +        if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
   1.127 +            return -1;
   1.128 +    }
   1.129 +
   1.130 +    back = flexarray_make(16, 1);
   1.131 +    if (!back)
   1.132 +        return ERROR_NOMEM;
   1.133 +
   1.134 +    XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n");
   1.135 +    num = atoi(num_devs);
   1.136 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
   1.137 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
   1.138 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
   1.139 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
   1.140 +    if (pcidev->vdevfn) {
   1.141 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
   1.142 +        flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
   1.143 +    }
   1.144 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
   1.145 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
   1.146 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
   1.147 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
   1.148 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
   1.149 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
   1.150 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
   1.151 +    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
   1.152 +
   1.153 +retry_transaction:
   1.154 +    t = xs_transaction_start(ctx->xsh);
   1.155 +    libxl_xs_writev(ctx, t, be_path,
   1.156 +                    libxl_xs_kvs_of_flexarray(ctx, back, boffset));
   1.157 +    if (!xs_transaction_end(ctx->xsh, t, 0))
   1.158 +        if (errno == EAGAIN)
   1.159 +            goto retry_transaction;
   1.160 +
   1.161 +    flexarray_free(back);
   1.162 +    return 0;
   1.163 +}
   1.164 +
   1.165 +static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.166 +{
   1.167 +    char *be_path, *num_devs_path, *num_devs, *xsdev;
   1.168 +    int num, i;
   1.169 +    xs_transaction_t t;
   1.170 +    unsigned int domain = 0, bus = 0, dev = 0, func = 0;
   1.171 +
   1.172 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.173 +    num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
   1.174 +    num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
   1.175 +    if (!num_devs)
   1.176 +        return -1;
   1.177 +    num = atoi(num_devs);
   1.178 +    if (num == 1) {
   1.179 +        libxl_device_destroy(ctx, be_path, 1);
   1.180 +        xs_rm(ctx->xsh, XBT_NULL, be_path);
   1.181 +        return 0;
   1.182 +    }
   1.183 +
   1.184 +    if (!is_hvm(ctx, domid)) {
   1.185 +        if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
   1.186 +            XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n");
   1.187 +            return -1;
   1.188 +        }
   1.189 +    }
   1.190 +
   1.191 +    for (i = 0; i < num; i++) {
   1.192 +        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
   1.193 +        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
   1.194 +        if (domain == pcidev->domain && bus == pcidev->bus &&
   1.195 +            pcidev->dev == dev && pcidev->func == func) {
   1.196 +            break;
   1.197 +        }
   1.198 +    }
   1.199 +    if (i == num) {
   1.200 +        XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n");
   1.201 +        return -1;
   1.202 +    }
   1.203 +
   1.204 +retry_transaction:
   1.205 +    t = xs_transaction_start(ctx->xsh);
   1.206 +    libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
   1.207 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", strlen("6"));
   1.208 +    xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
   1.209 +    if (!xs_transaction_end(ctx->xsh, t, 0))
   1.210 +        if (errno == EAGAIN)
   1.211 +            goto retry_transaction;
   1.212 +    return 0;
   1.213  }
   1.214  
   1.215 -int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.216 +int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.217  {
   1.218 -    return ERROR_NI;
   1.219 +    char path[50];
   1.220 +    char *state, *vdevfn;
   1.221 +    int rc, hvm;
   1.222 +
   1.223 +    /* TODO: check if the device can be assigned */
   1.224 +
   1.225 +    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
   1.226 +
   1.227 +    hvm = is_hvm(ctx, domid);
   1.228 +    if (hvm) {
   1.229 +        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
   1.230 +            return -1;
   1.231 +        }
   1.232 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.233 +        state = libxl_xs_read(ctx, XBT_NULL, path);
   1.234 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.235 +        if (pcidev->vdevfn)
   1.236 +            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
   1.237 +                           pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
   1.238 +        else
   1.239 +            libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
   1.240 +                           pcidev->bus, pcidev->dev, pcidev->func);
   1.241 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
   1.242 +        xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
   1.243 +        if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
   1.244 +            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
   1.245 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.246 +        vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
   1.247 +        sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
   1.248 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.249 +        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
   1.250 +    } else {
   1.251 +        char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
   1.252 +                                         pcidev->bus, pcidev->dev, pcidev->func);
   1.253 +        FILE *f = fopen(sysfs_path, "r");
   1.254 +        unsigned int start = 0, end = 0, flags = 0, size = 0;
   1.255 +        int irq = 0;
   1.256 +        int i;
   1.257 +
   1.258 +        if (f == NULL) {
   1.259 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.260 +            return -1;
   1.261 +        }
   1.262 +        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
   1.263 +            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
   1.264 +            size = end - start + 1;
   1.265 +            if (start) {
   1.266 +                if (flags & PCI_BAR_IO) {
   1.267 +                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
   1.268 +                    if (rc < 0)
   1.269 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.270 +                } else {
   1.271 +                    rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
   1.272 +                                                    (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
   1.273 +                    if (rc < 0)
   1.274 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.275 +                }
   1.276 +            }
   1.277 +        }
   1.278 +        fclose(f);
   1.279 +        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
   1.280 +                                   pcidev->bus, pcidev->dev, pcidev->func);
   1.281 +        f = fopen(sysfs_path, "r");
   1.282 +        if (f == NULL) {
   1.283 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.284 +            goto out;
   1.285 +        }
   1.286 +        fscanf(f, "%u", &irq);
   1.287 +        if (irq) {
   1.288 +            rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
   1.289 +            if (rc < 0) {
   1.290 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
   1.291 +            }
   1.292 +            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
   1.293 +            if (rc < 0) {
   1.294 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
   1.295 +            }
   1.296 +        }
   1.297 +        fclose(f);
   1.298 +    }
   1.299 +out:
   1.300 +    if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0)
   1.301 +        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc);
   1.302 +
   1.303 +    libxl_device_pci_add_xenstore(ctx, domid, pcidev);
   1.304 +    return 0;
   1.305  }
   1.306  
   1.307 -int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.308 +int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
   1.309  {
   1.310 -    return ERROR_NI;
   1.311 +    char path[50];
   1.312 +    char *state;
   1.313 +    int hvm, rc;
   1.314 +
   1.315 +    /* TODO: check if the device can be detached */
   1.316 +
   1.317 +    hvm = is_hvm(ctx, domid);
   1.318 +    if (hvm) {
   1.319 +        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
   1.320 +            return -1;
   1.321 +        }
   1.322 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.323 +        state = libxl_xs_read(ctx, XBT_NULL, path);
   1.324 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
   1.325 +        libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
   1.326 +                       pcidev->bus, pcidev->dev, pcidev->func);
   1.327 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
   1.328 +        xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
   1.329 +        if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
   1.330 +            XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
   1.331 +            return -1;
   1.332 +        }
   1.333 +        snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
   1.334 +        xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
   1.335 +    } else {
   1.336 +        char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
   1.337 +                                         pcidev->bus, pcidev->dev, pcidev->func);
   1.338 +        FILE *f = fopen(sysfs_path, "r");
   1.339 +        unsigned int start = 0, end = 0, flags = 0, size = 0;
   1.340 +        int irq = 0;
   1.341 +        int i;
   1.342 +
   1.343 +        if (f == NULL) {
   1.344 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.345 +            goto skip1;
   1.346 +        }
   1.347 +        for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
   1.348 +            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
   1.349 +            size = end - start + 1;
   1.350 +            if (start) {
   1.351 +                if (flags & PCI_BAR_IO) {
   1.352 +                    rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
   1.353 +                    if (rc < 0)
   1.354 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.355 +                } else {
   1.356 +                    rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
   1.357 +                                                    (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
   1.358 +                    if (rc < 0)
   1.359 +                        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x:  %d\n", start, size, rc);
   1.360 +                }
   1.361 +            }
   1.362 +        }
   1.363 +        fclose(f);
   1.364 +skip1:
   1.365 +        sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
   1.366 +                                   pcidev->bus, pcidev->dev, pcidev->func);
   1.367 +        f = fopen(sysfs_path, "r");
   1.368 +        if (f == NULL) {
   1.369 +            XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
   1.370 +            goto out;
   1.371 +        }
   1.372 +        fscanf(f, "%u", &irq);
   1.373 +        if (irq) {
   1.374 +            rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
   1.375 +            if (rc < 0) {
   1.376 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
   1.377 +            }
   1.378 +            rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
   1.379 +            if (rc < 0) {
   1.380 +                XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
   1.381 +            }
   1.382 +        }
   1.383 +        fclose(f);
   1.384 +    }
   1.385 +out:
   1.386 +    libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
   1.387 +
   1.388 +    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
   1.389 +
   1.390 +    if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0)
   1.391 +        XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc);
   1.392 +    return 0;
   1.393  }
   1.394 +
   1.395 +libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
   1.396 +{
   1.397 +    char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
   1.398 +    int n, i;
   1.399 +    unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
   1.400 +    libxl_device_pci *pcidevs;
   1.401 +
   1.402 +    be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
   1.403 +    num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
   1.404 +    if (!num_devs) {
   1.405 +        *num = 0;
   1.406 +        return NULL;
   1.407 +    }
   1.408 +    n = atoi(num_devs);
   1.409 +    pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, sizeof(libxl_device_pci));
   1.410 +    *num = n;
   1.411 +
   1.412 +    for (i = 0; i < n; i++) {
   1.413 +        xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
   1.414 +        sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
   1.415 +        xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
   1.416 +        if (xsvdevfn)
   1.417 +            vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
   1.418 +        libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
   1.419 +        xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
   1.420 +        if (xsopts) {
   1.421 +            char *saveptr;
   1.422 +            char *p = strtok_r(xsopts, ",=", &saveptr);
   1.423 +            do {
   1.424 +                while (*p == ' ')
   1.425 +                    p++;
   1.426 +                if (!strcmp(p, "msitranslate")) {
   1.427 +                    p = strtok_r(NULL, ",=", &saveptr);
   1.428 +                    pcidevs[i].msitranslate = atoi(p);
   1.429 +                } else if (!strcmp(p, "power_mgmt")) {
   1.430 +                    p = strtok_r(NULL, ",=", &saveptr);
   1.431 +                    pcidevs[i].power_mgmt = atoi(p);
   1.432 +                }
   1.433 +            } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
   1.434 +        }
   1.435 +    }
   1.436 +    return pcidevs;
   1.437 +}
   1.438 +
   1.439 +int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
   1.440 +{
   1.441 +    libxl_device_pci *pcidevs;
   1.442 +    int num, i;
   1.443 +
   1.444 +    pcidevs = libxl_device_pci_list(ctx, domid, &num);
   1.445 +    for (i = 0; i < num; i++) {
   1.446 +        if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
   1.447 +            return -1;
   1.448 +    }
   1.449 +    return 0;
   1.450 +}
   1.451 +
     2.1 --- a/tools/libxl/libxl.h	Fri Nov 13 15:30:24 2009 +0000
     2.2 +++ b/tools/libxl/libxl.h	Fri Nov 13 15:31:16 2009 +0000
     2.3 @@ -148,6 +148,25 @@ typedef struct {
     2.4      libxl_nic_type nictype;
     2.5  } libxl_device_nic;
     2.6  
     2.7 +typedef struct  {
     2.8 +    union {
     2.9 +        unsigned int value;
    2.10 +        struct {
    2.11 +            unsigned int reserved1:2;
    2.12 +            unsigned int reg:6;
    2.13 +            unsigned int func:3;
    2.14 +            unsigned int dev:5;
    2.15 +            unsigned int bus:8;
    2.16 +            unsigned int reserved2:7;
    2.17 +            unsigned int enable:1;
    2.18 +        };
    2.19 +    };
    2.20 +    unsigned int domain;
    2.21 +    unsigned int vdevfn;
    2.22 +    bool msitranslate;
    2.23 +    bool power_mgmt;
    2.24 +} libxl_device_pci;
    2.25 +
    2.26  #define ERROR_FAIL (-2)
    2.27  #define ERROR_NI (-101)
    2.28  #define ERROR_NOMEM (-1032)
    2.29 @@ -194,8 +213,14 @@ int libxl_device_vfb_add(struct libxl_ct
    2.30  int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
    2.31  int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
    2.32  
    2.33 -int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid);
    2.34 -int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
    2.35 -int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
    2.36 +#define PCI_BDF                "%04x:%02x:%02x.%01x"
    2.37 +#define PCI_BDF_VDEVFN         "%04x:%02x:%02x.%01x@%02x"
    2.38 +int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev);
    2.39 +int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev);
    2.40 +int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid);
    2.41 +libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num);
    2.42 +int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
    2.43 +                          unsigned int bus, unsigned int dev,
    2.44 +                          unsigned int func, unsigned int vdevfn);
    2.45  
    2.46  #endif
     3.1 --- a/tools/libxl/libxl_device.c	Fri Nov 13 15:30:24 2009 +0000
     3.2 +++ b/tools/libxl/libxl_device.c	Fri Nov 13 15:31:16 2009 +0000
     3.3 @@ -15,6 +15,7 @@
     3.4   */
     3.5  
     3.6  #include <string.h>
     3.7 +#include <stdio.h>
     3.8  #include "libxl.h"
     3.9  #include "libxl_internal.h"
    3.10  #include <sys/time.h> /* for struct timeval */
    3.11 @@ -83,9 +84,12 @@ retry_transaction:
    3.12      libxl_xs_writev(ctx, t, backend_path, bents);
    3.13      libxl_xs_writev(ctx, t, frontend_path, fents);
    3.14  
    3.15 -    if (!xs_transaction_end(ctx->xsh, t, 0))
    3.16 +    if (!xs_transaction_end(ctx->xsh, t, 0)) {
    3.17          if (errno == EAGAIN)
    3.18              goto retry_transaction;
    3.19 +        else
    3.20 +            XL_LOG(ctx, XL_LOG_ERROR, "xs transaction failed errno=%d\n", errno);
    3.21 +    }
    3.22      return 0;
    3.23  }
    3.24  
    3.25 @@ -154,7 +158,7 @@ int libxl_device_destroy(struct libxl_ct
    3.26      char *state = libxl_xs_read(ctx, XBT_NULL, state_path);
    3.27      if (!state)
    3.28          return 0;
    3.29 -    if (atoi(state) <= 3) {
    3.30 +    if (atoi(state) != 4) {
    3.31          xs_rm(ctx->xsh, XBT_NULL, be_path);
    3.32          return 0;
    3.33      }
    3.34 @@ -240,3 +244,72 @@ int libxl_devices_destroy(struct libxl_c
    3.35      flexarray_free(toremove);
    3.36      return 0;
    3.37  }
    3.38 +
    3.39 +int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned int bus,
    3.40 +                         unsigned int dev, unsigned int func)
    3.41 +{
    3.42 +    FILE *fd;
    3.43 +
    3.44 +    fd = fopen("/sys/bus/pci/drivers/pciback/do_flr", "w");
    3.45 +    if (fd != NULL) {
    3.46 +        fprintf(fd, PCI_BDF, domain, bus, dev, func);
    3.47 +        fclose(fd);
    3.48 +        return 0;
    3.49 +    }
    3.50 +    XL_LOG(ctx, XL_LOG_ERROR, "Pciback doesn't support do_flr, cannot flr the device\n");
    3.51 +    return -1;
    3.52 +}
    3.53 +
    3.54 +int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char *state)
    3.55 +{
    3.56 +    char path[50];
    3.57 +    char *p;
    3.58 +    int watchdog = 100;
    3.59 +    unsigned int len;
    3.60 +
    3.61 +    snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
    3.62 +    while (watchdog > 0) {
    3.63 +        p = xs_read(ctx->xsh, XBT_NULL, path, &len);
    3.64 +        if (p == NULL) {
    3.65 +            usleep(100000);
    3.66 +            watchdog--;
    3.67 +        } else {
    3.68 +            if (state == NULL || !strcmp(state, p)) {
    3.69 +                free(p);
    3.70 +                return 0;
    3.71 +            } else {
    3.72 +                free(p);
    3.73 +                usleep(100000);
    3.74 +                watchdog--;
    3.75 +            }
    3.76 +        }
    3.77 +    }
    3.78 +    XL_LOG(ctx, XL_LOG_ERROR, "Device Model not ready\n");
    3.79 +    return -1;
    3.80 +}
    3.81 +
    3.82 +int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state)
    3.83 +{
    3.84 +    int watchdog = 100;
    3.85 +    unsigned int len;
    3.86 +    char *p;
    3.87 +    char *path = libxl_sprintf(ctx, "%s/state", be_path);
    3.88 +
    3.89 +    while (watchdog > 0) {
    3.90 +        p = xs_read(ctx->xsh, XBT_NULL, path, &len);
    3.91 +        if (p == NULL) {
    3.92 +            XL_LOG(ctx, XL_LOG_ERROR, "Backend %s does not exist\n", be_path);
    3.93 +            return -1;
    3.94 +        } else {
    3.95 +            if (!strcmp(p, state)) {
    3.96 +                return 0;
    3.97 +            } else {
    3.98 +                usleep(100000);
    3.99 +                watchdog--;
   3.100 +            }
   3.101 +        }
   3.102 +    }
   3.103 +    XL_LOG(ctx, XL_LOG_ERROR, "Backend %s not ready\n", be_path);
   3.104 +    return -1;
   3.105 +}
   3.106 +
     4.1 --- a/tools/libxl/libxl_internal.h	Fri Nov 13 15:30:24 2009 +0000
     4.2 +++ b/tools/libxl/libxl_internal.h	Fri Nov 13 15:31:16 2009 +0000
     4.3 @@ -72,6 +72,12 @@ typedef struct {
     4.4      libxl_device_kinds kind;
     4.5  } libxl_device;
     4.6  
     4.7 +#define XC_PCI_BDF             "0x%x, 0x%x, 0x%x, 0x%x"
     4.8 +#define AUTO_PHP_SLOT          0x100
     4.9 +#define SYSFS_PCI_DEV          /sys/bus/pci/devices
    4.10 +#define PROC_PCI_NUM_RESOURCES 7
    4.11 +#define PCI_BAR_IO             0x01
    4.12 +
    4.13  #define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y)))
    4.14  
    4.15  /* memory allocation tracking/helpers */
    4.16 @@ -92,7 +98,7 @@ char *libxl_xs_get_dompath(struct libxl_
    4.17  char *libxl_xs_read(struct libxl_ctx *ctx, xs_transaction_t t, char *path);
    4.18  char **libxl_xs_directory(struct libxl_ctx *ctx, xs_transaction_t t, char *path, unsigned int *nb);
    4.19  
    4.20 -/* from xd_dom */
    4.21 +/* from xl_dom */
    4.22  int is_hvm(struct libxl_ctx *ctx, uint32_t domid);
    4.23  int build_pre(struct libxl_ctx *ctx, uint32_t domid,
    4.24                libxl_domain_build_info *info, libxl_domain_build_state *state);
    4.25 @@ -109,7 +115,7 @@ int restore_common(struct libxl_ctx *ctx
    4.26                     libxl_domain_build_info *info, libxl_domain_build_state *state, int fd);
    4.27  int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int live, int debug);
    4.28  
    4.29 -/* from xd_device */
    4.30 +/* from xl_device */
    4.31  char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype);
    4.32  char *device_disk_string_of_phystype(libxl_disk_phystype phystype);
    4.33  
    4.34 @@ -120,13 +126,17 @@ int libxl_device_generic_add(struct libx
    4.35                               char **bents, char **fents);
    4.36  int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force);
    4.37  int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
    4.38 +int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char *state);
    4.39 +int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state);
    4.40 +int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned int bus,
    4.41 +                         unsigned int dev, unsigned int func);
    4.42  
    4.43  /* from xenguest (helper */
    4.44  int hvm_build_set_params(int handle, uint32_t domid,
    4.45                           int apic, int acpi, int pae, int nx, int viridian,
    4.46                           int vcpus, int store_evtchn, unsigned long *store_mfn);
    4.47  
    4.48 -/* xd_exec */
    4.49 +/* xl_exec */
    4.50  int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
    4.51                 char *arg0, char **args);
    4.52  
     5.1 --- a/tools/libxl/xl.c	Fri Nov 13 15:30:24 2009 +0000
     5.2 +++ b/tools/libxl/xl.c	Fri Nov 13 15:31:16 2009 +0000
     5.3 @@ -40,6 +40,8 @@ static void printf_info(libxl_domain_cre
     5.4                          int num_disks,
     5.5                          libxl_device_nic *vifs,
     5.6                          int num_vifs,
     5.7 +                        libxl_device_pci *pcidevs,
     5.8 +                        int num_pcidevs,
     5.9                          libxl_device_model_info *dm_info)
    5.10  {
    5.11      int i;
    5.12 @@ -106,6 +108,12 @@ static void printf_info(libxl_domain_cre
    5.13          printf("smac %s\n", vifs[i].mac);
    5.14      }
    5.15  
    5.16 +    for (i = 0; i < num_pcidevs; i++) {
    5.17 +        printf("\n\n\n*** pcidevs_info: %d ***\n", i);
    5.18 +        printf("pci dev "PCI_BDF_VDEVFN"\n", pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func, pcidevs[i].vdevfn);
    5.19 +        printf("opts msitranslate %d power_mgmt %d\n", pcidevs[i].msitranslate, pcidevs[i].power_mgmt);
    5.20 +    }
    5.21 +
    5.22      printf("\n\n\n*** device_model_info ***\n");
    5.23      printf("domid: %d\n", dm_info->domid);
    5.24      printf("dom_name: %s\n", dm_info->dom_name);
    5.25 @@ -286,13 +294,17 @@ static void parse_config_file(const char
    5.26                                int *num_disks,
    5.27                                libxl_device_nic **vifs,
    5.28                                int *num_vifs,
    5.29 +                              libxl_device_pci **pcidevs,
    5.30 +                              int *num_pcidevs,
    5.31                                libxl_device_model_info *dm_info)
    5.32  {
    5.33      const char *buf;
    5.34      xen_uuid_t uuid[16];
    5.35      long l;
    5.36      struct config_t config;
    5.37 -    struct config_setting_t *vbds, *nics;
    5.38 +    struct config_setting_t *vbds, *nics, *pcis;
    5.39 +    int pci_power_mgmt = 0;
    5.40 +    int pci_msitranslate = 1;
    5.41  
    5.42      config_init (&config);
    5.43  
    5.44 @@ -482,6 +494,48 @@ skip:
    5.45          }
    5.46      }
    5.47  
    5.48 +    if (config_lookup_int (&config, "pci_msitranslate", &l) == CONFIG_TRUE)
    5.49 +        pci_msitranslate = l;
    5.50 +
    5.51 +    if (config_lookup_int (&config, "pci_power_mgmt", &l) == CONFIG_TRUE)
    5.52 +        pci_power_mgmt = l;
    5.53 +
    5.54 +    if ((pcis = config_lookup (&config, "pci")) != NULL) {
    5.55 +        *num_pcidevs = 0;
    5.56 +        *pcidevs = NULL;
    5.57 +        while ((buf = config_setting_get_string_elem (pcis, *num_pcidevs)) != NULL) {
    5.58 +            unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
    5.59 +            char *buf2 = strdup(buf);
    5.60 +            char *p;
    5.61 +            *pcidevs = (libxl_device_pci *) realloc(*pcidevs, sizeof (libxl_device_pci) * ((*num_pcidevs) + 1));
    5.62 +            memset(*pcidevs + *num_pcidevs, 0x00, sizeof(libxl_device_pci));
    5.63 +            p = strtok(buf2, ",");
    5.64 +            if (!p)
    5.65 +                goto skip_pci;
    5.66 +            if (!sscanf(p, PCI_BDF_VDEVFN, &domain, &bus, &dev, &func, &vdevfn)) {
    5.67 +                sscanf(p, "%02x:%02x.%01x@%02x", &bus, &dev, &func, &vdevfn);
    5.68 +                domain = 0;
    5.69 +            }
    5.70 +            libxl_device_pci_init(*pcidevs + *num_pcidevs, domain, bus, dev, func, vdevfn);
    5.71 +            (*pcidevs)[*num_pcidevs].msitranslate = pci_msitranslate;
    5.72 +            (*pcidevs)[*num_pcidevs].power_mgmt = pci_power_mgmt;
    5.73 +            while ((p = strtok(NULL, ",=")) != NULL) {
    5.74 +                while (*p == ' ')
    5.75 +                    p++;
    5.76 +                if (!strcmp(p, "msitranslate")) {
    5.77 +                    p = strtok(NULL, ",=");
    5.78 +                    (*pcidevs)[*num_pcidevs].msitranslate = atoi(p);
    5.79 +                } else if (!strcmp(p, "power_mgmt")) {
    5.80 +                    p = strtok(NULL, ",=");
    5.81 +                    (*pcidevs)[*num_pcidevs].power_mgmt = atoi(p);
    5.82 +                }
    5.83 +            }
    5.84 +            *num_pcidevs = (*num_pcidevs) + 1;
    5.85 +skip_pci:
    5.86 +            free(buf2);
    5.87 +        }
    5.88 +    }
    5.89 +
    5.90      /* init dm from c and b */
    5.91      init_dm_info(dm_info, c_info, b_info);
    5.92  
    5.93 @@ -527,13 +581,14 @@ static void create_domain(int debug, con
    5.94      libxl_device_model_info dm_info;
    5.95      libxl_device_disk *disks = NULL;
    5.96      libxl_device_nic *vifs = NULL;
    5.97 -    int num_disks = 0, num_vifs = 0;
    5.98 +    libxl_device_pci *pcidevs = NULL;
    5.99 +    int num_disks = 0, num_vifs = 0, num_pcidevs = 0;
   5.100      int i;
   5.101  
   5.102      printf("Parsing config file %s\n", filename);
   5.103 -    parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &dm_info);
   5.104 +    parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &dm_info);
   5.105      if (debug)
   5.106 -        printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, &dm_info);
   5.107 +        printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, num_pcidevs, &dm_info);
   5.108  
   5.109      libxl_ctx_init(&ctx);
   5.110      libxl_ctx_set_log(&ctx, log_callback, NULL);
   5.111 @@ -551,6 +606,8 @@ static void create_domain(int debug, con
   5.112          libxl_device_nic_add(&ctx, domid, &vifs[i]);
   5.113      }
   5.114      libxl_create_device_model(&ctx, &dm_info, vifs, num_vifs);
   5.115 +    for (i = 0; i < num_pcidevs; i++)
   5.116 +        libxl_device_pci_add(&ctx, domid, &pcidevs[i]);
   5.117      libxl_domain_unpause(&ctx, domid);
   5.118  
   5.119  }
   5.120 @@ -560,9 +617,12 @@ static void help(char *command)
   5.121      if (!command || !strcmp(command, "help")) {
   5.122          printf("Usage xl <subcommand> [args]\n\n");
   5.123          printf("xl full list of subcommands:\n\n");
   5.124 -        printf(" create                                create a domain from config file <filename>\n\n");
   5.125 +        printf(" create                        create a domain from config file <filename>\n\n");
   5.126          printf(" list                          list information about all domains\n\n");
   5.127          printf(" destroy                       terminate a domain immediately\n\n");
   5.128 +        printf(" pci-attach                    insert a new pass-through pci device\n\n");
   5.129 +        printf(" pci-detach                    remove a domain's pass-through pci device\n\n");
   5.130 +        printf(" pci-list                      list pass-through pci devices for a domain\n\n");
   5.131      } else if(!strcmp(command, "create")) {
   5.132          printf("Usage: xl create <ConfigFile> [options] [vars]\n\n");
   5.133          printf("Create a domain based on <ConfigFile>.\n\n");
   5.134 @@ -572,12 +632,167 @@ static void help(char *command)
   5.135      } else if(!strcmp(command, "list")) {
   5.136          printf("Usage: xl list [Domain]\n\n");
   5.137          printf("List information about all/some domains.\n\n");
   5.138 +    } else if(!strcmp(command, "pci-attach")) {
   5.139 +        printf("Usage: xl pci-attach <Domain> <BDF> [Virtual Slot]\n\n");
   5.140 +        printf("Insert a new pass-through pci device.\n\n");
   5.141 +    } else if(!strcmp(command, "pci-detach")) {
   5.142 +        printf("Usage: xl pci-detach <Domain> <BDF>\n\n");
   5.143 +        printf("Remove a domain's pass-through pci device.\n\n");
   5.144 +    } else if(!strcmp(command, "pci-list")) {
   5.145 +        printf("Usage: xl pci-list <Domain>\n\n");
   5.146 +        printf("List pass-through pci devices for a domain.\n\n");
   5.147      } else if(!strcmp(command, "destroy")) {
   5.148          printf("Usage: xl destroy <Domain>\n\n");
   5.149          printf("Terminate a domain immediately.\n\n");
   5.150      }
   5.151  }
   5.152  
   5.153 +void pcilist(char *dom)
   5.154 +{
   5.155 +    struct libxl_ctx ctx;
   5.156 +    uint32_t domid;
   5.157 +    libxl_device_pci *pcidevs;
   5.158 +    int num, i;
   5.159 +
   5.160 +    libxl_ctx_init(&ctx);
   5.161 +    libxl_ctx_set_log(&ctx, log_callback, NULL);
   5.162 +
   5.163 +    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
   5.164 +        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
   5.165 +        exit(2);
   5.166 +    }
   5.167 +    pcidevs = libxl_device_pci_list(&ctx, domid, &num);
   5.168 +    if (!num)
   5.169 +        return;
   5.170 +    printf("VFn  domain bus  slot func\n");
   5.171 +    for (i = 0; i < num; i++) {
   5.172 +        printf("0x%02x 0x%04x 0x%02x 0x%02x 0x%01x\n", pcidevs[i].vdevfn, pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func);
   5.173 +    }
   5.174 +}
   5.175 +
   5.176 +int main_pcilist(int argc, char **argv)
   5.177 +{
   5.178 +    int opt;
   5.179 +    char *domname = NULL;
   5.180 +
   5.181 +    while ((opt = getopt(argc, argv, "h")) != -1) {
   5.182 +        switch (opt) {
   5.183 +        case 'h':
   5.184 +            help("pci-list");
   5.185 +            exit(0);
   5.186 +        default:
   5.187 +            fprintf(stderr, "option not supported\n");
   5.188 +            break;
   5.189 +        }
   5.190 +    }
   5.191 +    if (optind >= argc) {
   5.192 +        help("pci-list");
   5.193 +        exit(2);
   5.194 +    }
   5.195 +
   5.196 +    domname = argv[optind];
   5.197 +
   5.198 +    pcilist(domname);
   5.199 +    exit(0);
   5.200 +}
   5.201 +
   5.202 +void pcidetach(char *dom, char *bdf)
   5.203 +{
   5.204 +    struct libxl_ctx ctx;
   5.205 +    uint32_t domid;
   5.206 +    libxl_device_pci pcidev;
   5.207 +    unsigned int domain, bus, dev, func;
   5.208 +
   5.209 +    libxl_ctx_init(&ctx);
   5.210 +    libxl_ctx_set_log(&ctx, log_callback, NULL);
   5.211 +
   5.212 +    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
   5.213 +        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
   5.214 +        exit(2);
   5.215 +    }
   5.216 +    memset(&pcidev, 0x00, sizeof(pcidev));
   5.217 +    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
   5.218 +    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
   5.219 +    libxl_device_pci_remove(&ctx, domid, &pcidev);
   5.220 +}
   5.221 +
   5.222 +int main_pcidetach(int argc, char **argv)
   5.223 +{
   5.224 +    int opt;
   5.225 +    char *domname = NULL, *bdf = NULL;
   5.226 +
   5.227 +    while ((opt = getopt(argc, argv, "h")) != -1) {
   5.228 +        switch (opt) {
   5.229 +        case 'h':
   5.230 +            help("pci-attach");
   5.231 +            exit(0);
   5.232 +        default:
   5.233 +            fprintf(stderr, "option not supported\n");
   5.234 +            break;
   5.235 +        }
   5.236 +    }
   5.237 +    if (optind >= argc - 1) {
   5.238 +        help("pci-detach");
   5.239 +        exit(2);
   5.240 +    }
   5.241 +
   5.242 +    domname = argv[optind];
   5.243 +    bdf = argv[optind + 1];
   5.244 +
   5.245 +    pcidetach(domname, bdf);
   5.246 +    exit(0);
   5.247 +}
   5.248 +void pciattach(char *dom, char *bdf, char *vs)
   5.249 +{
   5.250 +    struct libxl_ctx ctx;
   5.251 +    uint32_t domid;
   5.252 +    libxl_device_pci pcidev;
   5.253 +    unsigned int domain, bus, dev, func;
   5.254 +
   5.255 +    libxl_ctx_init(&ctx);
   5.256 +    libxl_ctx_set_log(&ctx, log_callback, NULL);
   5.257 +
   5.258 +    if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
   5.259 +        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
   5.260 +        exit(2);
   5.261 +    }
   5.262 +    memset(&pcidev, 0x00, sizeof(pcidev));
   5.263 +    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
   5.264 +    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
   5.265 +    libxl_device_pci_add(&ctx, domid, &pcidev);
   5.266 +}
   5.267 +
   5.268 +int main_pciattach(int argc, char **argv)
   5.269 +{
   5.270 +    int opt;
   5.271 +    char *domname = NULL, *bdf = NULL, *vs = NULL;
   5.272 +
   5.273 +    while ((opt = getopt(argc, argv, "h")) != -1) {
   5.274 +        switch (opt) {
   5.275 +        case 'h':
   5.276 +            help("pci-attach");
   5.277 +            exit(0);
   5.278 +        default:
   5.279 +            fprintf(stderr, "option not supported\n");
   5.280 +            break;
   5.281 +        }
   5.282 +    }
   5.283 +    if (optind >= argc - 1) {
   5.284 +        help("pci-attach");
   5.285 +        exit(2);
   5.286 +    }
   5.287 +
   5.288 +    domname = argv[optind];
   5.289 +    bdf = argv[optind + 1];
   5.290 +
   5.291 +    if (optind + 1 < argc)
   5.292 +        vs = argv[optind + 2];
   5.293 +
   5.294 +    pciattach(domname, bdf, vs);
   5.295 +    exit(0);
   5.296 +}
   5.297 +
   5.298 +
   5.299  void destroy_domain(char *p)
   5.300  {
   5.301      struct libxl_ctx ctx;
   5.302 @@ -713,6 +928,12 @@ int main(int argc, char **argv)
   5.303          main_list(argc - 1, argv + 1);
   5.304      } else if (!strcmp(argv[1], "destroy")) {
   5.305          main_destroy(argc - 1, argv + 1);
   5.306 +    } else if (!strcmp(argv[1], "pci-attach")) {
   5.307 +        main_pciattach(argc - 1, argv + 1);
   5.308 +    } else if (!strcmp(argv[1], "pci-detach")) {
   5.309 +        main_pcidetach(argc - 1, argv + 1);
   5.310 +    } else if (!strcmp(argv[1], "pci-list")) {
   5.311 +        main_pcilist(argc - 1, argv + 1);
   5.312      } else if (!strcmp(argv[1], "help")) {
   5.313          if (argc > 2)
   5.314              help(argv[2]);