debuggers.hg

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