debuggers.hg

annotate tools/libxl/libxl.c @ 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 50d33023051d
children 014579af0350
rev   line source
keir@20462 1 /*
keir@20462 2 * Copyright (C) 2009 Citrix Ltd.
keir@20462 3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
keir@20462 4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
keir@20462 5 *
keir@20462 6 * This program is free software; you can redistribute it and/or modify
keir@20462 7 * it under the terms of the GNU Lesser General Public License as published
keir@20462 8 * by the Free Software Foundation; version 2.1 only. with the special
keir@20462 9 * exception on linking described in file LICENSE.
keir@20462 10 *
keir@20462 11 * This program is distributed in the hope that it will be useful,
keir@20462 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
keir@20462 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
keir@20462 14 * GNU Lesser General Public License for more details.
keir@20462 15 */
keir@20462 16
keir@20462 17 #include <stdio.h>
keir@20462 18 #include <string.h>
keir@20462 19 #include <stdlib.h>
keir@20462 20 #include <sys/stat.h>
keir@20462 21 #include <sys/types.h>
keir@20462 22 #include <fcntl.h>
keir@20462 23 #include <sys/select.h>
keir@20462 24 #include <signal.h>
keir@20468 25 #include <unistd.h> /* for write, unlink and close */
keir@20462 26 #include "libxl.h"
keir@20462 27 #include "libxl_utils.h"
keir@20462 28 #include "libxl_internal.h"
keir@20462 29 #include "flexarray.h"
keir@20462 30
keir@20462 31 int libxl_ctx_init(struct libxl_ctx *ctx)
keir@20462 32 {
keir@20462 33 memset(ctx, 0, sizeof(struct libxl_ctx));
keir@20462 34 ctx->alloc_maxsize = 256;
keir@20462 35 ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
keir@20462 36 if (!ctx->alloc_ptrs)
keir@20462 37 return ERROR_NOMEM;
keir@20462 38
keir@20462 39 ctx->xch = xc_interface_open();
keir@20462 40 ctx->xsh = xs_daemon_open();
keir@20462 41 return 0;
keir@20462 42 }
keir@20462 43
keir@20462 44 int libxl_ctx_free(struct libxl_ctx *ctx)
keir@20462 45 {
keir@20462 46 libxl_free_all(ctx);
keir@20462 47 free(ctx->alloc_ptrs);
keir@20462 48 ctx->alloc_ptrs = NULL;
keir@20462 49 xc_interface_close(ctx->xch);
keir@20462 50 xs_daemon_close(ctx->xsh);
keir@20462 51 return 0;
keir@20462 52 }
keir@20462 53
keir@20462 54 int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data)
keir@20462 55 {
keir@20462 56 ctx->log_callback = log_callback;
keir@20462 57 ctx->log_userdata = log_data;
keir@20462 58 return 0;
keir@20462 59 }
keir@20462 60
keir@20462 61 /******************************************************************************/
keir@20462 62
keir@20462 63 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
keir@20462 64 uint32_t *domid)
keir@20462 65 {
keir@20462 66 int flags, ret, i;
keir@20468 67 char *uuid_string;
keir@20462 68 char *rw_paths[] = { "device" };
keir@20462 69 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
keir@20462 70 "control", "attr", "data", "messages" };
keir@20462 71 char *dom_path, *vm_path, *vss_path;
keir@20462 72 struct xs_permissions roperm[2];
keir@20462 73 struct xs_permissions rwperm[1];
keir@20462 74 xs_transaction_t t;
keir@20468 75 xen_domain_handle_t handle;
keir@20462 76
keir@20468 77 uuid_string = libxl_uuid_to_string(ctx, info->uuid);
keir@20462 78 if (!uuid_string) {
keir@20462 79 XL_LOG(ctx, XL_LOG_ERROR, "missing uuid");
keir@20462 80 return ERROR_FAIL;
keir@20462 81 }
keir@20462 82
keir@20462 83 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
keir@20462 84 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
keir@20462 85 *domid = 0;
keir@20462 86
keir@20468 87 /* XXX handle has to be initialised here.
keir@20468 88 * info->uuid != xen_domain_handle_t
keir@20468 89 * See:
keir@20468 90 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
keir@20468 91 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
keir@20468 92 *
keir@20468 93 * A DCE 1.1 compatible source representation of UUIDs.
keir@20468 94 *
keir@20468 95 * struct uuid {
keir@20468 96 * uint32_t time_low;
keir@20468 97 * uint16_t time_mid;
keir@20468 98 * uint16_t time_hi_and_version;
keir@20468 99 * uint8_t clock_seq_hi_and_reserved;
keir@20468 100 * uint8_t clock_seq_low;
keir@20468 101 * uint8_t node[_UUID_NODE_LEN];
keir@20468 102 * };
keir@20468 103 */
keir@20468 104
keir@20468 105 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
keir@20462 106 if (ret < 0) {
keir@20462 107 XL_LOG(ctx, XL_LOG_ERROR, "domain creation fail: %d", ret);
keir@20462 108 return ERROR_FAIL;
keir@20462 109 }
keir@20462 110
keir@20462 111 dom_path = libxl_xs_get_dompath(ctx, *domid);
keir@20462 112 vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string);
keir@20462 113 vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string);
keir@20462 114 if (!dom_path || !vm_path || !vss_path) {
keir@20462 115 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths");
keir@20462 116 return ERROR_FAIL;
keir@20462 117 }
keir@20462 118
keir@20462 119 roperm[0].id = 0;
keir@20462 120 roperm[0].perms = XS_PERM_NONE;
keir@20462 121 roperm[1].id = *domid;
keir@20462 122 roperm[1].perms = XS_PERM_READ;
keir@20462 123 rwperm[0].id = *domid;
keir@20462 124 rwperm[0].perms = XS_PERM_NONE;
keir@20462 125
keir@20462 126 retry_transaction:
keir@20462 127 t = xs_transaction_start(ctx->xsh);
keir@20462 128 xs_rm(ctx->xsh, t, dom_path);
keir@20462 129 xs_mkdir(ctx->xsh, t, dom_path);
keir@20462 130 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
keir@20462 131
keir@20462 132 xs_rm(ctx->xsh, t, vm_path);
keir@20462 133 xs_mkdir(ctx->xsh, t, vm_path);
keir@20462 134 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
keir@20462 135
keir@20462 136 xs_rm(ctx->xsh, t, vss_path);
keir@20462 137 xs_mkdir(ctx->xsh, t, vss_path);
keir@20462 138 xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm));
keir@20462 139
keir@20462 140 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path));
keir@20462 141 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path));
keir@20462 142 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name));
keir@20462 143
keir@20462 144 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
keir@20462 145 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
keir@20462 146 xs_mkdir(ctx->xsh, t, path);
keir@20462 147 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
keir@20462 148 libxl_free(ctx, path);
keir@20462 149 }
keir@20462 150 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
keir@20462 151 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]);
keir@20462 152 xs_mkdir(ctx->xsh, t, path);
keir@20462 153 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
keir@20462 154 libxl_free(ctx, path);
keir@20462 155 }
keir@20462 156
keir@20462 157 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
keir@20462 158 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
keir@20482 159 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/image/ostype", vm_path), "hvm", strlen("hvm"));
keir@20462 160
keir@20462 161 libxl_xs_writev(ctx, t, dom_path, info->xsdata);
keir@20462 162 libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
keir@20462 163
keir@20462 164 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
keir@20462 165
keir@20462 166 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20462 167 if (errno == EAGAIN)
keir@20462 168 goto retry_transaction;
keir@20462 169 return 0;
keir@20462 170 }
keir@20462 171
keir@20462 172 int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid)
keir@20462 173 {
keir@20462 174 libxl_domain_build_state state;
keir@20462 175 char **vments = NULL, **localents = NULL;
keir@20462 176
keir@20462 177 memset(&state, '\0', sizeof(state));
keir@20462 178
keir@20462 179 build_pre(ctx, domid, info, &state);
keir@20462 180 if (info->hvm) {
keir@20462 181 build_hvm(ctx, domid, info, &state);
keir@20462 182 vments = libxl_calloc(ctx, 4, sizeof(char *));
keir@20462 183 vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
keir@20462 184 vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
keir@20462 185 } else {
keir@20462 186 build_pv(ctx, domid, info, &state);
keir@20462 187 }
keir@20462 188 build_post(ctx, domid, info, &state, vments, localents);
keir@20462 189 return 0;
keir@20462 190 }
keir@20462 191
keir@20462 192 int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
keir@20462 193 uint32_t domid, int fd)
keir@20462 194 {
keir@20462 195 libxl_domain_build_state state;
keir@20462 196 char **vments = NULL, **localents = NULL;
keir@20462 197
keir@20462 198 memset(&state, '\0', sizeof(state));
keir@20462 199
keir@20462 200 build_pre(ctx, domid, info, &state);
keir@20462 201 restore_common(ctx, domid, info, &state, fd);
keir@20462 202 if (info->hvm) {
keir@20462 203 vments = libxl_calloc(ctx, 4, sizeof(char *));
keir@20462 204 vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
keir@20462 205 vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
keir@20462 206 } else {
keir@20462 207 localents = libxl_calloc(ctx, 4 * 2, sizeof(char *));
keir@20462 208 localents[0] = libxl_sprintf(ctx, "serial/0/limit");
keir@20462 209 localents[1] = libxl_sprintf(ctx, "%d", 65536);
keir@20462 210 localents[2] = libxl_sprintf(ctx, "console/port");
keir@20462 211 localents[3] = libxl_sprintf(ctx, "%d", state.console_port);
keir@20462 212 localents[4] = libxl_sprintf(ctx, "console/ring-ref");
keir@20462 213 localents[5] = libxl_sprintf(ctx, "%ld", state.console_mfn);
keir@20462 214 }
keir@20462 215 build_post(ctx, domid, info, &state, vments, localents);
keir@20462 216 return 0;
keir@20462 217 }
keir@20462 218
keir@20462 219 struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain)
keir@20462 220 {
keir@20462 221 struct libxl_dominfo *ptr;
keir@20462 222 int index, i, ret, first_domain;
keir@20462 223 xc_domaininfo_t info[16];
keir@20462 224 int size = 16;
keir@20462 225
keir@20462 226 first_domain = 1;
keir@20462 227 index = 0;
keir@20462 228 ptr = libxl_calloc(ctx, size, sizeof(struct libxl_dominfo));
keir@20462 229 if (!ptr)
keir@20462 230 return NULL;
keir@20462 231 redo:
keir@20462 232 ret = xc_domain_getinfolist(ctx->xch, first_domain, 16, info);
keir@20462 233 for (i = 0; i < ret; i++) {
keir@20462 234 if (index == size) {
keir@20462 235 struct libxl_dominfo *ptr2;
keir@20462 236
keir@20462 237 ptr2 = libxl_calloc(ctx, size * 2, sizeof(struct libxl_dominfo));
keir@20462 238 if (!ptr2) {
keir@20462 239 libxl_free(ctx, ptr);
keir@20462 240 return NULL;
keir@20462 241 }
keir@20462 242 memcpy(ptr2, ptr, sizeof(struct libxl_dominfo) * size);
keir@20462 243 libxl_free(ctx, ptr);
keir@20462 244 ptr = ptr2;
keir@20462 245 size *= 2;
keir@20462 246 }
keir@20462 247 memcpy(ptr[index].uuid, info[i].handle, 16 * sizeof(uint8_t));
keir@20462 248 ptr[index].domid = info[i].domain;
keir@20462 249 first_domain = info[i].domain + 1;
keir@20462 250 index++;
keir@20462 251 }
keir@20462 252 if (ret == 16)
keir@20462 253 goto redo;
keir@20462 254 *nb_domain = index;
keir@20462 255 return ptr;
keir@20462 256 }
keir@20462 257
keir@20462 258 xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain)
keir@20462 259 {
keir@20462 260 int index, first_domain;
keir@20462 261 xc_dominfo_t *info;
keir@20462 262 int size = 1024;
keir@20462 263
keir@20462 264 first_domain = 0;
keir@20462 265 index = 0;
keir@20462 266 info = (xc_dominfo_t *) libxl_calloc(ctx, size, sizeof(xc_dominfo_t));
keir@20462 267 if (!info) {
keir@20462 268 *nb_domain = 0;
keir@20462 269 return NULL;
keir@20462 270 }
keir@20462 271 *nb_domain = xc_domain_getinfo(ctx->xch, first_domain, 1024, info);
keir@20462 272 return info;
keir@20462 273 }
keir@20462 274
keir@20462 275 int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
keir@20462 276 uint32_t domid, int fd)
keir@20462 277 {
keir@20462 278 int hvm = 1;
keir@20462 279 int live = 0;
keir@20462 280 int debug = 0;
keir@20462 281 char savesig[] = "XenSavedDomain\n";
keir@20462 282
keir@20462 283 write(fd, savesig, strlen(savesig));
keir@20462 284
keir@20462 285 core_suspend(ctx, domid, fd, hvm, live, debug);
keir@20462 286
keir@20462 287 return 0;
keir@20462 288 }
keir@20462 289
keir@20462 290 int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 291 {
keir@20462 292 xc_domain_pause(ctx->xch, domid);
keir@20462 293 return 0;
keir@20462 294 }
keir@20462 295
keir@20462 296 int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 297 {
keir@20462 298 xc_domain_unpause(ctx->xch, domid);
keir@20462 299 return 0;
keir@20462 300 }
keir@20462 301
keir@20462 302 static char *req_table[] = {
keir@20462 303 [0] = "poweroff",
keir@20462 304 [1] = "reboot",
keir@20462 305 [2] = "suspend",
keir@20462 306 [3] = "crash",
keir@20462 307 [4] = "halt",
keir@20462 308 };
keir@20462 309
keir@20462 310 int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
keir@20462 311 {
keir@20462 312 char *shutdown_path;
keir@20462 313 char *dom_path;
keir@20462 314
keir@20462 315 if (req > ARRAY_SIZE(req_table))
keir@20462 316 return ERROR_INVAL;
keir@20462 317
keir@20462 318 dom_path = libxl_xs_get_dompath(ctx, domid);
keir@20462 319 shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path);
keir@20462 320
keir@20462 321 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
keir@20462 322 if (/* hvm */ 0) {
keir@20462 323 unsigned long acpi_s_state = 0;
keir@20462 324 unsigned long pvdriver = 0;
keir@20462 325 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
keir@20462 326 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
keir@20462 327 if (!pvdriver && acpi_s_state != 0)
keir@20462 328 xc_domain_shutdown(ctx->xch, domid, req);
keir@20462 329 }
keir@20462 330 return 0;
keir@20462 331 }
keir@20462 332
keir@20462 333 static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 334 {
keir@20462 335 char *pid;
keir@20462 336 int ret;
keir@20462 337
keir@20462 338 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
keir@20462 339 if (!pid) {
keir@20462 340 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find device model's pid\n");
keir@20462 341 return -1;
keir@20462 342 }
keir@20462 343 xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid));
keir@20462 344
keir@20462 345 ret = kill(atoi(pid), SIGHUP);
keir@20462 346 if (ret < 0 && errno == ESRCH) {
keir@20462 347 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited\n");
keir@20462 348 ret = 0;
keir@20462 349 } else if (ret == 0) {
keir@20462 350 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled\n");
keir@20462 351 ret = 0;
keir@20462 352 } else {
keir@20462 353 XL_LOG(ctx, XL_LOG_ERROR, "kill %d returned %d errno=%d\n", atoi(pid), ret, errno);
keir@20462 354 }
keir@20462 355 return ret;
keir@20462 356 }
keir@20462 357
keir@20462 358 int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
keir@20462 359 {
keir@20462 360 char *dom_path, vm_path[41];
keir@20468 361 xen_uuid_t *uuid;
keir@20462 362
keir@20462 363 dom_path = libxl_xs_get_dompath(ctx, domid);
keir@20462 364 if (!dom_path) {
keir@20462 365 XL_LOG(ctx, XL_LOG_ERROR, "dompath doesn't exist for %d\n", domid);
keir@20462 366 return -1;
keir@20462 367 }
keir@20462 368 if (libxl_domid_to_uuid(ctx, &uuid, domid) < 0) {
keir@20462 369 XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
keir@20462 370 return -1;
keir@20462 371 }
keir@20482 372 if (libxl_device_pci_shutdown(ctx, domid) < 0)
keir@20482 373 XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid);
keir@20462 374 xs_write(ctx->xsh, XBT_NULL,
keir@20462 375 libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
keir@20462 376 "shutdown", strlen("shutdown"));
keir@20462 377 if (xc_domain_pause(ctx->xch, domid) < 0) {
keir@20462 378 XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
keir@20462 379 return -1;
keir@20462 380 }
keir@20462 381 if (xc_domain_destroy(ctx->xch, domid) < 0) {
keir@20462 382 XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
keir@20462 383 return -1;
keir@20462 384 }
keir@20462 385 if (libxl_devices_destroy(ctx, domid, force) < 0)
keir@20462 386 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d\n", domid);
keir@20462 387 if (libxl_destroy_device_model(ctx, domid) < 0)
keir@20462 388 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d\n", domid);
keir@20462 389 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
keir@20462 390 XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", dom_path);
keir@20468 391 snprintf(vm_path, sizeof(vm_path), "/vm/%s", libxl_uuid_to_string(ctx, uuid));
keir@20462 392 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
keir@20462 393 XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", vm_path);
keir@20462 394 return 0;
keir@20462 395 }
keir@20462 396
keir@20462 397 static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
keir@20462 398 libxl_device_model_info *info,
keir@20462 399 libxl_device_nic *vifs,
keir@20462 400 int num_vifs)
keir@20462 401 {
keir@20462 402 int num = 0, i;
keir@20462 403 flexarray_t *dm_args;
keir@20462 404 dm_args = flexarray_make(16, 1);
keir@20462 405 if (!dm_args)
keir@20462 406 return NULL;
keir@20462 407
keir@20462 408 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "qemu-dm"));
keir@20462 409 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-d"));
keir@20462 410
keir@20462 411 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid));
keir@20462 412
keir@20462 413 if (info->dom_name) {
keir@20462 414 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-domain-name"));
keir@20462 415 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->dom_name));
keir@20462 416 }
keir@20462 417 if (info->videoram) {
keir@20462 418 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-videoram"));
keir@20462 419 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram));
keir@20462 420 }
keir@20462 421 if (info->stdvga) {
keir@20462 422 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-std-vga"));
keir@20462 423 }
keir@20462 424 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
keir@20462 425 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vnc"));
keir@20462 426 if (info->vncdisplay) {
keir@20462 427 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
keir@20462 428 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay));
keir@20462 429 } else {
keir@20462 430 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay));
keir@20462 431 }
keir@20462 432 } else if (info->vnclisten) {
keir@20462 433 if (strchr(info->vnclisten, ':') != NULL) {
keir@20462 434 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->vnclisten));
keir@20462 435 } else {
keir@20462 436 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten));
keir@20462 437 }
keir@20462 438 } else {
keir@20462 439 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:0"));
keir@20462 440 }
keir@20462 441 if (info->vncunused) {
keir@20462 442 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vncunused"));
keir@20462 443 }
keir@20462 444 }
keir@20462 445 if (info->sdl || info->opengl) {
keir@20462 446 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-sdl"));
keir@20462 447 if (info->opengl) {
keir@20462 448 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-disable-opengl"));
keir@20462 449 }
keir@20462 450 }
keir@20462 451 if (info->keymap) {
keir@20462 452 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-k"));
keir@20462 453 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->keymap));
keir@20462 454 }
keir@20462 455 if (info->nographic && (!info->sdl && !info->vnc)) {
keir@20462 456 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-nographic"));
keir@20462 457 }
keir@20462 458 if (info->serial) {
keir@20462 459 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-serial"));
keir@20462 460 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->serial));
keir@20462 461 }
keir@20462 462 if (info->boot) {
keir@20462 463 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-boot"));
keir@20462 464 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->boot));
keir@20462 465 }
keir@20462 466 if (info->usb) {
keir@20462 467 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usb"));
keir@20462 468 if (info->usbdevice) {
keir@20462 469 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usbdevice"));
keir@20462 470 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->usbdevice));
keir@20462 471 }
keir@20462 472 }
keir@20462 473 if (info->apic) {
keir@20462 474 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-acpi"));
keir@20462 475 }
keir@20462 476 if (info->extra) {
keir@20462 477 int i = 0;
keir@20462 478 while (info->extra[i] != NULL) {
keir@20462 479 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->extra[i]));
keir@20462 480 }
keir@20462 481 }
keir@20462 482 for (i = 0; i < num_vifs; i++) {
keir@20462 483 if (vifs[i].nictype == NICTYPE_IOEMU) {
keir@20462 484 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
keir@20462 485 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s",
keir@20462 486 vifs[i].devid, vifs[i].smac, vifs[i].model));
keir@20462 487 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
keir@20462 488 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s",
keir@20462 489 vifs[i].devid, vifs[i].ifname, vifs[i].bridge));
keir@20462 490 }
keir@20462 491 }
keir@20462 492 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-M"));
keir@20462 493 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "xenfv"));
keir@20462 494 flexarray_set(dm_args, num++, NULL);
keir@20462 495
keir@20462 496 return (char **) flexarray_contents(dm_args);
keir@20462 497 }
keir@20462 498
keir@20462 499 int libxl_create_device_model(struct libxl_ctx *ctx,
keir@20462 500 libxl_device_model_info *info,
keir@20462 501 libxl_device_nic *vifs, int num_vifs)
keir@20462 502 {
keir@20462 503 char *dom_path, *path, *logfile, *logfile_new;
keir@20462 504 char *kvs[3];
keir@20462 505 struct stat stat_buf;
keir@20462 506 int logfile_w, null, pid;
keir@20462 507 int i;
keir@20462 508 char **args;
keir@20462 509
keir@20462 510 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
keir@20462 511 if (!args)
keir@20462 512 return ERROR_FAIL;
keir@20462 513
keir@20462 514 dom_path = libxl_xs_get_dompath(ctx, info->domid);
keir@20462 515
keir@20462 516 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
keir@20462 517 xs_mkdir(ctx->xsh, XBT_NULL, path);
keir@20462 518
keir@20462 519 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
keir@20462 520 if (stat(logfile, &stat_buf) == 0) {
keir@20462 521 /* file exists, rotate */
keir@20462 522 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.10", info->dom_name);
keir@20462 523 unlink(logfile);
keir@20462 524 for (i = 9; i > 0; i--) {
keir@20462 525 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i);
keir@20462 526 logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i + 1);
keir@20462 527 rename(logfile, logfile_new);
keir@20462 528 }
keir@20462 529 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
keir@20462 530 logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.1", info->dom_name);
keir@20462 531 rename(logfile, logfile_new);
keir@20462 532 }
keir@20462 533 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
keir@20467 534 logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
keir@20462 535 null = open("/dev/null", O_RDONLY);
keir@20462 536 pid = libxl_exec(ctx, null, logfile_w, logfile_w, info->device_model, args);
keir@20462 537 close(null);
keir@20462 538 close(logfile_w);
keir@20462 539
keir@20462 540 kvs[0] = libxl_sprintf(ctx, "image/device-model-pid");
keir@20462 541 kvs[1] = libxl_sprintf(ctx, "%d", pid);
keir@20462 542 kvs[2] = NULL;
keir@20462 543 libxl_xs_writev(ctx, XBT_NULL, dom_path, kvs);
keir@20462 544
keir@20462 545 return 0;
keir@20462 546 }
keir@20462 547
keir@20462 548 /******************************************************************************/
keir@20462 549 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
keir@20462 550 {
keir@20462 551 flexarray_t *front;
keir@20462 552 flexarray_t *back;
keir@20462 553 char *backend_type;
keir@20462 554 unsigned int boffset = 0;
keir@20462 555 unsigned int foffset = 0;
keir@20462 556 int devid;
keir@20462 557 libxl_device device;
keir@20462 558
keir@20462 559 front = flexarray_make(16, 1);
keir@20462 560 if (!front)
keir@20462 561 return ERROR_NOMEM;
keir@20462 562 back = flexarray_make(16, 1);
keir@20462 563 if (!back) /* leaks front if error */
keir@20462 564 return ERROR_NOMEM;
keir@20462 565
keir@20462 566 backend_type = device_disk_backend_type_of_phystype(disk->phystype);
keir@20462 567 devid = device_disk_dev_number(disk->virtpath);
keir@20462 568
keir@20462 569 device.backend_devid = devid;
keir@20462 570 device.backend_domid = disk->backend_domid;
keir@20462 571 device.devid = devid;
keir@20462 572 device.domid = disk->domid;
keir@20462 573 device.kind = DEVICE_VBD;
keir@20462 574
keir@20462 575 switch (disk->phystype) {
keir@20462 576 case PHYSTYPE_FILE:
keir@20462 577 return ERROR_NI; /* FIXME */
keir@20462 578 break;
keir@20462 579 case PHYSTYPE_PHY: {
keir@20462 580 int major, minor;
keir@20462 581
keir@20462 582 device_disk_major_minor(disk->virtpath, &major, &minor);
keir@20462 583 flexarray_set(back, boffset++, libxl_sprintf(ctx, "physical-device"));
keir@20462 584 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
keir@20462 585
keir@20462 586 flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
keir@20462 587 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->physpath));
keir@20462 588
keir@20462 589 device.backend_kind = DEVICE_VBD;
keir@20462 590 break;
keir@20462 591 }
keir@20462 592 case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD:
keir@20462 593 flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
keir@20462 594 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s",
keir@20462 595 device_disk_string_of_phystype(disk->phystype), disk->physpath));
keir@20462 596
keir@20462 597 device.backend_kind = DEVICE_TAP;
keir@20462 598 break;
keir@20462 599 }
keir@20462 600
keir@20462 601 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
keir@20462 602 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid));
keir@20462 603 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
keir@20462 604 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
keir@20462 605 flexarray_set(back, boffset++, libxl_sprintf(ctx, "removable"));
keir@20462 606 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0));
keir@20462 607 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
keir@20462 608 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20462 609 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev"));
keir@20462 610 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->virtpath));
keir@20462 611 flexarray_set(back, boffset++, libxl_sprintf(ctx, "type"));
keir@20462 612 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", backend_type));
keir@20462 613 flexarray_set(back, boffset++, libxl_sprintf(ctx, "mode"));
keir@20462 614 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", (disk->readwrite) ? "w" : "r"));
keir@20462 615
keir@20462 616 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
keir@20462 617 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid));
keir@20462 618 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
keir@20462 619 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20462 620 flexarray_set(front, foffset++, libxl_sprintf(ctx, "virtual-device"));
keir@20462 621 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid));
keir@20462 622 flexarray_set(front, foffset++, libxl_sprintf(ctx, "device-type"));
keir@20462 623 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%s", (disk->is_cdrom) ? "cdrom" : "disk"));
keir@20462 624
keir@20462 625 if (0 /* protocol != native*/) {
keir@20462 626 flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
keir@20462 627 flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
keir@20462 628 }
keir@20462 629
keir@20462 630 libxl_device_generic_add(ctx, &device,
keir@20462 631 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20462 632 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20462 633 /* leaks both flexarray here */
keir@20462 634 return 0;
keir@20462 635 }
keir@20462 636
keir@20462 637 int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 638 {
keir@20462 639 return ERROR_NI;
keir@20462 640 }
keir@20462 641
keir@20462 642 int libxl_device_disk_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 643 {
keir@20462 644 return ERROR_NI;
keir@20462 645 }
keir@20462 646
keir@20462 647 /******************************************************************************/
keir@20462 648 int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
keir@20462 649 {
keir@20462 650 flexarray_t *front;
keir@20462 651 flexarray_t *back;
keir@20462 652 unsigned int boffset = 0;
keir@20462 653 unsigned int foffset = 0;
keir@20462 654 libxl_device device;
keir@20462 655
keir@20462 656 front = flexarray_make(16, 1);
keir@20462 657 if (!front)
keir@20462 658 return ERROR_NOMEM;
keir@20462 659 back = flexarray_make(16, 1);
keir@20462 660 if (!back)
keir@20462 661 return ERROR_NOMEM;
keir@20462 662
keir@20462 663 device.backend_devid = nic->devid;
keir@20462 664 device.backend_domid = nic->backend_domid;
keir@20462 665 device.backend_kind = DEVICE_VIF;
keir@20462 666 device.devid = nic->devid;
keir@20462 667 device.domid = nic->domid;
keir@20462 668 device.kind = DEVICE_VIF;
keir@20462 669
keir@20462 670 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
keir@20462 671 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid));
keir@20462 672 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
keir@20462 673 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
keir@20462 674 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
keir@20462 675 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20462 676 flexarray_set(back, boffset++, libxl_sprintf(ctx, "script"));
keir@20462 677 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->script));
keir@20462 678 flexarray_set(back, boffset++, libxl_sprintf(ctx, "mac"));
keir@20462 679 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
keir@20462 680 nic->mac[0], nic->mac[1], nic->mac[2],
keir@20462 681 nic->mac[3], nic->mac[4], nic->mac[5]));
keir@20462 682 flexarray_set(back, boffset++, libxl_sprintf(ctx, "handle"));
keir@20462 683 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
keir@20462 684
keir@20462 685 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
keir@20462 686 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid));
keir@20462 687 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
keir@20462 688 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20462 689 flexarray_set(front, foffset++, libxl_sprintf(ctx, "handle"));
keir@20462 690 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid));
keir@20462 691 flexarray_set(front, foffset++, libxl_sprintf(ctx, "mac"));
keir@20462 692 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
keir@20462 693 nic->mac[0], nic->mac[1], nic->mac[2],
keir@20462 694 nic->mac[3], nic->mac[4], nic->mac[5]));
keir@20462 695 if (0 /* protocol != native*/) {
keir@20462 696 flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
keir@20462 697 flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
keir@20462 698 }
keir@20462 699
keir@20462 700 libxl_device_generic_add(ctx, &device,
keir@20462 701 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20462 702 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20462 703
keir@20462 704 /* FIXME: wait for plug */
keir@20462 705 return 0;
keir@20462 706 }
keir@20462 707
keir@20462 708 int libxl_device_nic_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 709 {
keir@20462 710 return ERROR_NI;
keir@20462 711 }
keir@20462 712
keir@20462 713 int libxl_device_nic_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 714 {
keir@20462 715 return ERROR_NI;
keir@20462 716 }
keir@20462 717
keir@20462 718 /******************************************************************************/
keir@20462 719 int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 720 {
keir@20462 721 return ERROR_NI;
keir@20462 722 }
keir@20462 723
keir@20462 724 int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 725 {
keir@20462 726 return ERROR_NI;
keir@20462 727 }
keir@20462 728
keir@20462 729 int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 730 {
keir@20462 731 return ERROR_NI;
keir@20462 732 }
keir@20462 733
keir@20462 734 /******************************************************************************/
keir@20462 735 int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 736 {
keir@20462 737 return ERROR_NI;
keir@20462 738 }
keir@20462 739
keir@20462 740 int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 741 {
keir@20462 742 return ERROR_NI;
keir@20462 743 }
keir@20462 744
keir@20462 745 int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 746 {
keir@20462 747 return ERROR_NI;
keir@20462 748 }
keir@20462 749
keir@20462 750 /******************************************************************************/
keir@20482 751
keir@20482 752 int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
keir@20482 753 unsigned int bus, unsigned int dev,
keir@20482 754 unsigned int func, unsigned int vdevfn)
keir@20482 755 {
keir@20482 756 pcidev->domain = domain;
keir@20482 757 pcidev->bus = bus;
keir@20482 758 pcidev->dev = dev;
keir@20482 759 pcidev->func = func;
keir@20482 760 pcidev->vdevfn = vdevfn;
keir@20482 761 return 0;
keir@20482 762 }
keir@20482 763
keir@20482 764 static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
keir@20482 765 {
keir@20482 766 flexarray_t *front;
keir@20482 767 flexarray_t *back;
keir@20482 768 unsigned int boffset = 0;
keir@20482 769 unsigned int foffset = 0;
keir@20482 770 libxl_device device;
keir@20482 771 int i;
keir@20482 772
keir@20482 773 front = flexarray_make(16, 1);
keir@20482 774 if (!front)
keir@20482 775 return ERROR_NOMEM;
keir@20482 776 back = flexarray_make(16, 1);
keir@20482 777 if (!back)
keir@20482 778 return ERROR_NOMEM;
keir@20482 779
keir@20482 780 XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n");
keir@20482 781
keir@20482 782 /* add pci device */
keir@20482 783 device.backend_devid = 0;
keir@20482 784 device.backend_domid = 0;
keir@20482 785 device.backend_kind = DEVICE_PCI;
keir@20482 786 device.devid = 0;
keir@20482 787 device.domid = domid;
keir@20482 788 device.kind = DEVICE_PCI;
keir@20482 789
keir@20482 790 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
keir@20482 791 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
keir@20482 792 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
keir@20482 793 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
keir@20482 794 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
keir@20482 795 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 796 flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
keir@20482 797 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
keir@20482 798 for (i = 0; i < num; i++) {
keir@20482 799 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
keir@20482 800 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 801 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
keir@20482 802 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 803 if (pcidev->vdevfn) {
keir@20482 804 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
keir@20482 805 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
keir@20482 806 }
keir@20482 807 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
keir@20482 808 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
keir@20482 809 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
keir@20482 810 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 811 }
keir@20482 812 flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
keir@20482 813 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
keir@20482 814
keir@20482 815 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
keir@20482 816 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
keir@20482 817 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
keir@20482 818 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 819
keir@20482 820 libxl_device_generic_add(ctx, &device,
keir@20482 821 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20482 822 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20482 823
keir@20482 824 flexarray_free(back);
keir@20482 825 flexarray_free(front);
keir@20482 826 return 0;
keir@20482 827 }
keir@20482 828
keir@20482 829 static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 830 {
keir@20482 831 flexarray_t *back;
keir@20482 832 char *num_devs, *be_path;
keir@20482 833 int num = 0;
keir@20482 834 unsigned int boffset = 0;
keir@20482 835 xs_transaction_t t;
keir@20482 836
keir@20482 837 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
keir@20482 838 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
keir@20482 839 if (!num_devs)
keir@20482 840 return libxl_create_pci_backend(ctx, domid, pcidev, 1);
keir@20482 841
keir@20482 842 if (!is_hvm(ctx, domid)) {
keir@20482 843 if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
keir@20482 844 return -1;
keir@20482 845 }
keir@20482 846
keir@20482 847 back = flexarray_make(16, 1);
keir@20482 848 if (!back)
keir@20482 849 return ERROR_NOMEM;
keir@20482 850
keir@20482 851 XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n");
keir@20482 852 num = atoi(num_devs);
keir@20482 853 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
keir@20482 854 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 855 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
keir@20482 856 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 857 if (pcidev->vdevfn) {
keir@20482 858 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
keir@20482 859 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
keir@20482 860 }
keir@20482 861 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
keir@20482 862 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
keir@20482 863 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
keir@20482 864 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 865 flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
keir@20482 866 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
keir@20482 867 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
keir@20482 868 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
keir@20482 869
keir@20482 870 retry_transaction:
keir@20482 871 t = xs_transaction_start(ctx->xsh);
keir@20482 872 libxl_xs_writev(ctx, t, be_path,
keir@20482 873 libxl_xs_kvs_of_flexarray(ctx, back, boffset));
keir@20482 874 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20482 875 if (errno == EAGAIN)
keir@20482 876 goto retry_transaction;
keir@20482 877
keir@20482 878 flexarray_free(back);
keir@20482 879 return 0;
keir@20482 880 }
keir@20482 881
keir@20482 882 static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20482 883 {
keir@20482 884 char *be_path, *num_devs_path, *num_devs, *xsdev;
keir@20482 885 int num, i;
keir@20482 886 xs_transaction_t t;
keir@20482 887 unsigned int domain = 0, bus = 0, dev = 0, func = 0;
keir@20482 888
keir@20482 889 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
keir@20482 890 num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
keir@20482 891 num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
keir@20482 892 if (!num_devs)
keir@20482 893 return -1;
keir@20482 894 num = atoi(num_devs);
keir@20482 895 if (num == 1) {
keir@20482 896 libxl_device_destroy(ctx, be_path, 1);
keir@20482 897 xs_rm(ctx->xsh, XBT_NULL, be_path);
keir@20482 898 return 0;
keir@20482 899 }
keir@20482 900
keir@20482 901 if (!is_hvm(ctx, domid)) {
keir@20482 902 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
keir@20482 903 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n");
keir@20482 904 return -1;
keir@20482 905 }
keir@20482 906 }
keir@20482 907
keir@20482 908 for (i = 0; i < num; i++) {
keir@20482 909 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
keir@20482 910 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
keir@20482 911 if (domain == pcidev->domain && bus == pcidev->bus &&
keir@20482 912 pcidev->dev == dev && pcidev->func == func) {
keir@20482 913 break;
keir@20482 914 }
keir@20482 915 }
keir@20482 916 if (i == num) {
keir@20482 917 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n");
keir@20482 918 return -1;
keir@20482 919 }
keir@20482 920
keir@20482 921 retry_transaction:
keir@20482 922 t = xs_transaction_start(ctx->xsh);
keir@20482 923 libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
keir@20482 924 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", strlen("6"));
keir@20482 925 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
keir@20482 926 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20482 927 if (errno == EAGAIN)
keir@20482 928 goto retry_transaction;
keir@20482 929 return 0;
keir@20462 930 }
keir@20462 931
keir@20482 932 int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 933 {
keir@20482 934 char path[50];
keir@20482 935 char *state, *vdevfn;
keir@20482 936 int rc, hvm;
keir@20482 937
keir@20482 938 /* TODO: check if the device can be assigned */
keir@20482 939
keir@20482 940 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 941
keir@20482 942 hvm = is_hvm(ctx, domid);
keir@20482 943 if (hvm) {
keir@20482 944 if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
keir@20482 945 return -1;
keir@20482 946 }
keir@20482 947 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
keir@20482 948 state = libxl_xs_read(ctx, XBT_NULL, path);
keir@20482 949 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 950 if (pcidev->vdevfn)
keir@20482 951 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
keir@20482 952 pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
keir@20482 953 else
keir@20482 954 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
keir@20482 955 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 956 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
keir@20482 957 xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
keir@20482 958 if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
keir@20482 959 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
keir@20482 960 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 961 vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
keir@20482 962 sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
keir@20482 963 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
keir@20482 964 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
keir@20482 965 } else {
keir@20482 966 char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
keir@20482 967 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 968 FILE *f = fopen(sysfs_path, "r");
keir@20482 969 unsigned int start = 0, end = 0, flags = 0, size = 0;
keir@20482 970 int irq = 0;
keir@20482 971 int i;
keir@20482 972
keir@20482 973 if (f == NULL) {
keir@20482 974 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
keir@20482 975 return -1;
keir@20482 976 }
keir@20482 977 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
keir@20482 978 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
keir@20482 979 size = end - start + 1;
keir@20482 980 if (start) {
keir@20482 981 if (flags & PCI_BAR_IO) {
keir@20482 982 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
keir@20482 983 if (rc < 0)
keir@20482 984 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc);
keir@20482 985 } else {
keir@20482 986 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
keir@20482 987 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
keir@20482 988 if (rc < 0)
keir@20482 989 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc);
keir@20482 990 }
keir@20482 991 }
keir@20482 992 }
keir@20482 993 fclose(f);
keir@20482 994 sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
keir@20482 995 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 996 f = fopen(sysfs_path, "r");
keir@20482 997 if (f == NULL) {
keir@20482 998 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
keir@20482 999 goto out;
keir@20482 1000 }
keir@20482 1001 fscanf(f, "%u", &irq);
keir@20482 1002 if (irq) {
keir@20482 1003 rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
keir@20482 1004 if (rc < 0) {
keir@20482 1005 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
keir@20482 1006 }
keir@20482 1007 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
keir@20482 1008 if (rc < 0) {
keir@20482 1009 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
keir@20482 1010 }
keir@20482 1011 }
keir@20482 1012 fclose(f);
keir@20482 1013 }
keir@20482 1014 out:
keir@20482 1015 if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0)
keir@20482 1016 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc);
keir@20482 1017
keir@20482 1018 libxl_device_pci_add_xenstore(ctx, domid, pcidev);
keir@20482 1019 return 0;
keir@20462 1020 }
keir@20462 1021
keir@20482 1022 int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 1023 {
keir@20482 1024 char path[50];
keir@20482 1025 char *state;
keir@20482 1026 int hvm, rc;
keir@20482 1027
keir@20482 1028 /* TODO: check if the device can be detached */
keir@20482 1029
keir@20482 1030 hvm = is_hvm(ctx, domid);
keir@20482 1031 if (hvm) {
keir@20482 1032 if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
keir@20482 1033 return -1;
keir@20482 1034 }
keir@20482 1035 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
keir@20482 1036 state = libxl_xs_read(ctx, XBT_NULL, path);
keir@20482 1037 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 1038 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
keir@20482 1039 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 1040 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
keir@20482 1041 xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
keir@20482 1042 if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
keir@20482 1043 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
keir@20482 1044 return -1;
keir@20482 1045 }
keir@20482 1046 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
keir@20482 1047 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
keir@20482 1048 } else {
keir@20482 1049 char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
keir@20482 1050 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 1051 FILE *f = fopen(sysfs_path, "r");
keir@20482 1052 unsigned int start = 0, end = 0, flags = 0, size = 0;
keir@20482 1053 int irq = 0;
keir@20482 1054 int i;
keir@20482 1055
keir@20482 1056 if (f == NULL) {
keir@20482 1057 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
keir@20482 1058 goto skip1;
keir@20482 1059 }
keir@20482 1060 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
keir@20482 1061 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
keir@20482 1062 size = end - start + 1;
keir@20482 1063 if (start) {
keir@20482 1064 if (flags & PCI_BAR_IO) {
keir@20482 1065 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
keir@20482 1066 if (rc < 0)
keir@20482 1067 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc);
keir@20482 1068 } else {
keir@20482 1069 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
keir@20482 1070 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
keir@20482 1071 if (rc < 0)
keir@20482 1072 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc);
keir@20482 1073 }
keir@20482 1074 }
keir@20482 1075 }
keir@20482 1076 fclose(f);
keir@20482 1077 skip1:
keir@20482 1078 sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
keir@20482 1079 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 1080 f = fopen(sysfs_path, "r");
keir@20482 1081 if (f == NULL) {
keir@20482 1082 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
keir@20482 1083 goto out;
keir@20482 1084 }
keir@20482 1085 fscanf(f, "%u", &irq);
keir@20482 1086 if (irq) {
keir@20482 1087 rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
keir@20482 1088 if (rc < 0) {
keir@20482 1089 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
keir@20482 1090 }
keir@20482 1091 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
keir@20482 1092 if (rc < 0) {
keir@20482 1093 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
keir@20482 1094 }
keir@20482 1095 }
keir@20482 1096 fclose(f);
keir@20482 1097 }
keir@20482 1098 out:
keir@20482 1099 libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
keir@20482 1100
keir@20482 1101 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 1102
keir@20482 1103 if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0)
keir@20482 1104 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc);
keir@20482 1105 return 0;
keir@20462 1106 }
keir@20482 1107
keir@20482 1108 libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
keir@20482 1109 {
keir@20482 1110 char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
keir@20482 1111 int n, i;
keir@20482 1112 unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
keir@20482 1113 libxl_device_pci *pcidevs;
keir@20482 1114
keir@20482 1115 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
keir@20482 1116 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
keir@20482 1117 if (!num_devs) {
keir@20482 1118 *num = 0;
keir@20482 1119 return NULL;
keir@20482 1120 }
keir@20482 1121 n = atoi(num_devs);
keir@20482 1122 pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, sizeof(libxl_device_pci));
keir@20482 1123 *num = n;
keir@20482 1124
keir@20482 1125 for (i = 0; i < n; i++) {
keir@20482 1126 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
keir@20482 1127 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
keir@20482 1128 xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
keir@20482 1129 if (xsvdevfn)
keir@20482 1130 vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
keir@20482 1131 libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
keir@20482 1132 xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
keir@20482 1133 if (xsopts) {
keir@20482 1134 char *saveptr;
keir@20482 1135 char *p = strtok_r(xsopts, ",=", &saveptr);
keir@20482 1136 do {
keir@20482 1137 while (*p == ' ')
keir@20482 1138 p++;
keir@20482 1139 if (!strcmp(p, "msitranslate")) {
keir@20482 1140 p = strtok_r(NULL, ",=", &saveptr);
keir@20482 1141 pcidevs[i].msitranslate = atoi(p);
keir@20482 1142 } else if (!strcmp(p, "power_mgmt")) {
keir@20482 1143 p = strtok_r(NULL, ",=", &saveptr);
keir@20482 1144 pcidevs[i].power_mgmt = atoi(p);
keir@20482 1145 }
keir@20482 1146 } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
keir@20482 1147 }
keir@20482 1148 }
keir@20482 1149 return pcidevs;
keir@20482 1150 }
keir@20482 1151
keir@20482 1152 int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20482 1153 {
keir@20482 1154 libxl_device_pci *pcidevs;
keir@20482 1155 int num, i;
keir@20482 1156
keir@20482 1157 pcidevs = libxl_device_pci_list(ctx, domid, &num);
keir@20482 1158 for (i = 0; i < num; i++) {
keir@20482 1159 if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
keir@20482 1160 return -1;
keir@20482 1161 }
keir@20482 1162 return 0;
keir@20482 1163 }
keir@20482 1164