@@ -29,11 +29,13 @@
#define PCID_MSG_FIELD_ARGS "arguments"
#define PCID_CMD_LIST "ls"
+#define PCID_CMD_UNBIND "unbind"
#define PCID_CMD_DIR_ID "dir_id"
#define PCID_CMD_WRITE "write"
#define PCID_CMD_READ_HEX "read_hex"
#define PCID_CMD_EXISTS "exists"
+#define PCID_CMD_READ_RESOURCES "read_resources"
#define PCID_CMD_PCI_PATH "pci_path"
#define PCID_CMD_PCI_INFO "pci_info"
@@ -44,12 +46,17 @@
#if defined(__linux__)
#define SYSFS_PCIBACK_DRIVER "/sys/bus/pci/drivers/pciback"
+#define SYSFS_PCI_DEV "/sys/bus/pci/devices"
#endif
#define PCI_INFO_PATH "/libxl/pci"
#define PCI_BDF_XSPATH "%04x-%02x-%02x-%01x"
#define PCI_BDF "%04x:%02x:%02x.%01x"
+#define RESOURCE_START "start"
+#define RESOURCE_END "end"
+#define RESOURCE_FLAGS "flags"
+
int libxl_pcid_process(libxl_ctx *ctx);
#endif /* PCID_H */
@@ -599,34 +599,32 @@ void libxl_device_pci_assignable_list_free(libxl_device_pci *list, int num)
static int sysfs_dev_unbind(libxl__gc *gc, libxl_device_pci *pci,
char **driver_path)
{
- char *spath, *pci_path, *dp = NULL;
- struct stat st;
+ char *pci_path, *dp = NULL;
pci_path = GCSPRINTF("/"PCI_BDF"/driver", pci->domain, pci->bus,
pci->dev, pci->func);
+ char *pci_info;
+ struct vchan_info *vchan;
+ libxl__json_object *args = NULL, *result = NULL;
- spath = GCSPRINTF(SYSFS_PCI_DEV"%s", pci_path);
- if ( !lstat(spath, &st) ) {
- /* Find the canonical path to the driver. */
- dp = libxl__zalloc(gc, PATH_MAX);
- dp = realpath(spath, dp);
- if ( !dp ) {
- LOGE(ERROR, "realpath() failed");
- return -1;
- }
-
- LOG(DEBUG, "Driver re-plug path: %s", dp);
+ vchan = pci_prepare_vchan(gc);
+ if (!vchan)
+ return ERROR_FAIL;
- /* Unbind from the old driver */
- spath = GCSPRINTF("%s/unbind", dp);
- if (sysfs_write_bdf(gc, SYSFS_PCI_DEV, pci_path, pci) < 0) {
- LOGE(ERROR, "Couldn't unbind device");
- return -1;
- }
+ pci_info = GCSPRINTF(PCI_BDF, pci->domain, pci->bus, pci->dev, pci->func);
+ libxl__vchan_param_add_string(gc, &args, PCID_CMD_PCI_PATH, pci_path);
+ libxl__vchan_param_add_string(gc, &args, PCID_CMD_PCI_INFO, pci_info);
+ result = vchan_send_command(gc, vchan, PCID_CMD_UNBIND, args);
+ if (!result) {
+ LOGE(WARN, "Write to %s%s failed\n", SYSFS_PCI_DEV, pci_path);
+ return -1;
}
- if ( driver_path )
+ if (driver_path) {
+ if (strcmp(result->u.string, "nolstat") != 0)
+ dp = (char *)libxl__json_object_get_string(result);
*driver_path = dp;
+ }
return 0;
}
@@ -1488,8 +1486,6 @@ static void pci_add_dm_done(libxl__egc *egc,
STATE_AO_GC(pas->aodev->ao);
libxl_ctx *ctx = libxl__gc_owner(gc);
libxl_domid domid = pas->pci_domid;
- char *sysfs_path;
- FILE *f;
unsigned long long start, end, flags, size;
int irq, i;
int r;
@@ -1510,20 +1506,38 @@ static void pci_add_dm_done(libxl__egc *egc,
if (isstubdom)
starting = false;
- sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/resource", pci->domain,
- pci->bus, pci->dev, pci->func);
- f = fopen(sysfs_path, "r");
- start = end = flags = size = 0;
- irq = 0;
+ struct vchan_info *vchan;
+ libxl__json_object *result = NULL, *args = NULL;
+ const libxl__json_object *addr, *node;
+ char *resource_path, *irq_path;
- if (f == NULL) {
- LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
+ vchan = pci_prepare_vchan(gc);
+ if (!vchan)
+ goto out;
+
+ resource_path = GCSPRINTF("/"PCI_BDF"/resource", pci->domain,
+ pci->bus, pci->dev, pci->func);
+ libxl__vchan_param_add_string(gc, &args, PCID_CMD_PCI_INFO, resource_path);
+ result = vchan_send_command(gc, vchan, PCID_CMD_READ_RESOURCES, args);
+ if (!result) {
+ LOGED(ERROR, domainid, "Couldn't get resources from %s", resource_path);
rc = ERROR_FAIL;
goto out;
}
+
+ start = end = flags = size = 0;
+ irq = 0;
+
for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
- if (fscanf(f, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
- continue;
+ node = libxl__json_array_get(result, i);
+
+ addr = libxl__json_map_get(RESOURCE_START, node, JSON_INTEGER);
+ start = libxl__json_object_get_integer(addr);
+ addr = libxl__json_map_get(RESOURCE_END, node, JSON_INTEGER);
+ end = libxl__json_object_get_integer(addr);
+ addr = libxl__json_map_get(RESOURCE_FLAGS, node, JSON_INTEGER);
+ flags = libxl__json_object_get_integer(addr);
+
size = end - start + 1;
if (start) {
if (flags & PCI_BAR_IO) {
@@ -1532,7 +1546,6 @@ static void pci_add_dm_done(libxl__egc *egc,
LOGED(ERROR, domainid,
"xc_domain_ioport_permission 0x%llx/0x%llx (error %d)",
start, size, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
@@ -1543,27 +1556,30 @@ static void pci_add_dm_done(libxl__egc *egc,
LOGED(ERROR, domainid,
"xc_domain_iomem_permission 0x%llx/0x%llx (error %d)",
start, size, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
}
}
}
- fclose(f);
- sysfs_path = GCSPRINTF(SYSFS_PCI_DEV"/"PCI_BDF"/irq", pci->domain,
- pci->bus, pci->dev, pci->func);
- f = fopen(sysfs_path, "r");
- if (f == NULL) {
- LOGED(ERROR, domainid, "Couldn't open %s", sysfs_path);
+
+ irq_path = GCSPRINTF("/"PCI_BDF"/irq", pci->domain,
+ pci->bus, pci->dev, pci->func);
+ libxl__vchan_param_add_string(gc, &args, PCID_CMD_PCI_INFO, irq_path);
+ libxl__vchan_param_add_string(gc, &args, PCID_CMD_DIR_ID, PCID_PCI_DEV);
+ result = vchan_send_command(gc, vchan, PCID_CMD_READ_HEX, args);
+ if (!result) {
+ LOGED(ERROR, domainid, "Couldn't get irq from %s", irq_path);
+ rc = ERROR_FAIL;
goto out_no_irq;
}
- if ((fscanf(f, "%u", &irq) == 1) && irq) {
+
+ irq = libxl__json_object_get_integer(result);
+ if (irq) {
r = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
if (r < 0) {
LOGED(ERROR, domainid, "xc_physdev_map_pirq irq=%d (error=%d)",
irq, r);
- fclose(f);
rc = ERROR_FAIL;
goto out;
}
@@ -1578,7 +1594,6 @@ static void pci_add_dm_done(libxl__egc *egc,
}
#endif
}
- fclose(f);
/* Don't restrict writes to the PCI config space from this VM */
if (pci->permissive) {
@@ -247,6 +247,107 @@ out:
return result;
}
+static libxl__json_object *process_read_rsc_cmd(libxl__gc *gc,
+ const struct libxl__json_object *resp)
+{
+ libxl__json_object *result = NULL;
+ const libxl__json_object *args, *pci_info;
+ libxl__json_object *node;
+ unsigned long long start, end, flags;
+ int i;
+ char *sysfs_path;
+ FILE *f;
+
+ args = libxl__json_map_get(PCID_MSG_FIELD_ARGS, resp, JSON_MAP);
+ if (!args)
+ goto out;
+ pci_info = libxl__json_map_get(PCID_CMD_PCI_INFO, args, JSON_ANY);
+ if (!pci_info)
+ goto out;
+
+ sysfs_path = libxl__sprintf(gc, SYSFS_PCI_DEV"%s", pci_info->u.string);
+ f = fopen(sysfs_path, "r");
+ if (!f) {
+ LOGE(ERROR, "Failed to open %s\n", sysfs_path);
+ goto out;
+ }
+
+ result = libxl__json_object_alloc(gc, JSON_ARRAY);
+ if (!result) {
+ LOGE(ERROR, "Memory allocation failed\n");
+ goto fail_mem_alloc;
+ }
+
+ for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
+ if (fscanf(f, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
+ continue;
+
+ node = libxl__json_object_alloc(gc, JSON_MAP);
+ if (!node) {
+ LOGE(ERROR, "Memory allocation failed\n");
+ goto fail_mem_alloc;
+ }
+ libxl__vchan_param_add_integer(gc, &node, RESOURCE_START, start);
+ libxl__vchan_param_add_integer(gc, &node, RESOURCE_END, end);
+ libxl__vchan_param_add_integer(gc, &node, RESOURCE_FLAGS, flags);
+ flexarray_append(result->u.array, node);
+ }
+
+fail_mem_alloc:
+ fclose(f);
+out:
+ return result;
+}
+
+static libxl__json_object *process_unbind_cmd(libxl__gc *gc,
+ const struct libxl__json_object *resp)
+{
+ libxl__json_object *result = NULL;
+ const struct libxl__json_object *args, *pci_path, *pci_info;
+ char *msg, *spath, *new_path, *dp = NULL;
+ struct stat st;
+
+ args = libxl__json_map_get(PCID_MSG_FIELD_ARGS, resp, JSON_MAP);
+ if (!args)
+ goto out;
+ pci_info = libxl__json_map_get(PCID_CMD_PCI_INFO, args, JSON_ANY);
+ if (!pci_info)
+ goto out;
+ pci_path = libxl__json_map_get(PCID_CMD_PCI_PATH, args, JSON_ANY);
+ if (!pci_path)
+ goto out;
+
+ spath = libxl__sprintf(gc, SYSFS_PCI_DEV"%s", pci_path->u.string);
+
+ if (!lstat(spath, &st)) {
+ /* Find the canonical path to the driver. */
+ dp = libxl__zalloc(gc, PATH_MAX);
+ if (!(realpath(spath, dp))) {
+ LOGE(ERROR, "realpath() failed\n");
+ goto out;
+ }
+ msg = dp;
+ /* Unbind from the old driver */
+ new_path = libxl__sprintf(gc, "%s/unbind", dp);
+
+ if (handle_write_cmd(gc, new_path, pci_info->u.string) != 0) {
+ LOGE(ERROR, "Couldn't unbind device\n");
+ goto out;
+ }
+ } else {
+ msg = libxl__sprintf(gc, "nolstat");
+ }
+ result = libxl__json_object_alloc(gc, JSON_STRING);
+ if (!result) {
+ LOGE(ERROR, "Memory allocation failed\n");
+ goto out;
+ }
+ result->u.string = msg;
+
+out:
+ return result;
+}
+
static int pcid_handle_message(libxl__gc *gc, const libxl__json_object *request,
libxl__json_object **result)
{
@@ -268,6 +369,10 @@ static int pcid_handle_message(libxl__gc *gc, const libxl__json_object *request,
*result = process_read_hex_cmd(gc, request);
else if (strcmp(command_name, PCID_CMD_EXISTS) == 0)
*result = process_exists_cmd(gc, request);
+ else if (strcmp(command_name, PCID_CMD_READ_RESOURCES) == 0)
+ *result = process_read_rsc_cmd(gc, request);
+ else if (strcmp(command_name, PCID_CMD_UNBIND) == 0)
+ *result = process_unbind_cmd(gc, request);
else
return ERROR_NOTFOUND;