debuggers.hg

view tools/libxl/libxl.c @ 20846:7a412f9f6aae

libxenlight: add error in disk_add if phystype is not recognized

Signed-off-by: Vincent Hanquez <vincent.hanquez@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 14 09:42:06 2010 +0000 (2010-01-14)
parents 517364d0823d
children abc717dc6c2a
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 "libxl_osdeps.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <sys/select.h>
25 #include <sys/wait.h>
26 #include <signal.h>
27 #include <unistd.h> /* for write, unlink and close */
28 #include <stdint.h>
29 #include <inttypes.h>
30 #include <assert.h>
32 #include "libxl.h"
33 #include "libxl_utils.h"
34 #include "libxl_internal.h"
35 #include "flexarray.h"
37 int libxl_ctx_init(struct libxl_ctx *ctx, int version)
38 {
39 if (version != LIBXL_VERSION)
40 return ERROR_VERSION;
41 memset(ctx, 0, sizeof(struct libxl_ctx));
42 ctx->alloc_maxsize = 256;
43 ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
44 if (!ctx->alloc_ptrs)
45 return ERROR_NOMEM;
47 ctx->xch = xc_interface_open();
48 if (ctx->xch == -1) {
49 free(ctx->alloc_ptrs);
50 return ERROR_FAIL;
51 }
53 ctx->xsh = xs_daemon_open();
54 if (!ctx->xsh) {
55 xc_interface_close(ctx->xch);
56 free(ctx->alloc_ptrs);
57 return ERROR_FAIL;
58 }
59 return 0;
60 }
62 int libxl_ctx_free(struct libxl_ctx *ctx)
63 {
64 libxl_free_all(ctx);
65 free(ctx->alloc_ptrs);
66 xc_interface_close(ctx->xch);
67 xs_daemon_close(ctx->xsh);
68 return 0;
69 }
71 int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data)
72 {
73 ctx->log_callback = log_callback;
74 ctx->log_userdata = log_data;
75 return 0;
76 }
78 /******************************************************************************/
80 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
81 uint32_t *domid)
82 {
83 int flags, ret, i;
84 char *uuid_string;
85 char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
86 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
87 "control", "attr", "messages" };
88 char *dom_path, *vm_path, *vss_path;
89 struct xs_permissions roperm[2];
90 struct xs_permissions rwperm[1];
91 xs_transaction_t t;
92 xen_domain_handle_t handle;
94 uuid_string = string_of_uuid(ctx, info->uuid);
95 if (!uuid_string) {
96 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate uuid string");
97 return ERROR_FAIL;
98 }
100 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
101 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
102 *domid = -1;
104 /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
105 memcpy(handle, info->uuid, sizeof(xen_domain_handle_t));
107 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
108 if (ret < 0) {
109 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "domain creation fail");
110 return ERROR_FAIL;
111 }
113 dom_path = libxl_xs_get_dompath(ctx, *domid);
114 if (!dom_path)
115 return ERROR_FAIL;
117 vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string);
118 vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string);
119 if (!vm_path || !vss_path) {
120 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths");
121 return ERROR_FAIL;
122 }
124 roperm[0].id = 0;
125 roperm[0].perms = XS_PERM_NONE;
126 roperm[1].id = *domid;
127 roperm[1].perms = XS_PERM_READ;
128 rwperm[0].id = *domid;
129 rwperm[0].perms = XS_PERM_NONE;
131 retry_transaction:
132 t = xs_transaction_start(ctx->xsh);
133 xs_rm(ctx->xsh, t, dom_path);
134 xs_mkdir(ctx->xsh, t, dom_path);
135 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
137 xs_rm(ctx->xsh, t, vm_path);
138 xs_mkdir(ctx->xsh, t, vm_path);
139 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
141 xs_rm(ctx->xsh, t, vss_path);
142 xs_mkdir(ctx->xsh, t, vss_path);
143 xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm));
145 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path));
146 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path));
147 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name));
149 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
150 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
151 xs_mkdir(ctx->xsh, t, path);
152 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
153 libxl_free(ctx, path);
154 }
155 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
156 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]);
157 xs_mkdir(ctx->xsh, t, path);
158 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
159 libxl_free(ctx, path);
160 }
162 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
163 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
165 libxl_xs_writev(ctx, t, dom_path, info->xsdata);
166 libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
168 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
170 if (!xs_transaction_end(ctx->xsh, t, 0))
171 if (errno == EAGAIN)
172 goto retry_transaction;
173 return 0;
174 }
176 int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state)
177 {
178 char **vments = NULL, **localents = NULL;
179 int i, ret;
181 ret = build_pre(ctx, domid, info, state);
182 if (ret) goto out;
184 if (info->hvm) {
185 ret = build_hvm(ctx, domid, info, state);
186 if (ret) goto out;
188 vments = libxl_calloc(ctx, 5, sizeof(char *));
189 vments[0] = "rtc/timeoffset";
190 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
191 vments[2] = "image/ostype";
192 vments[3] = "hvm";
193 } else {
194 ret = build_pv(ctx, domid, info, state);
195 if (ret) goto out;
197 vments = libxl_calloc(ctx, 9, sizeof(char *));
198 i = 0;
199 vments[i++] = "image/ostype";
200 vments[i++] = "linux";
201 vments[i++] = "image/kernel";
202 vments[i++] = (char*) info->kernel;
203 if (info->u.pv.ramdisk) {
204 vments[i++] = "image/ramdisk";
205 vments[i++] = (char*) info->u.pv.ramdisk;
206 }
207 if (info->u.pv.cmdline) {
208 vments[i++] = "image/cmdline";
209 vments[i++] = (char*) info->u.pv.cmdline;
210 }
211 }
212 ret = build_post(ctx, domid, info, state, vments, localents);
213 out:
214 return ret;
215 }
217 int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
218 uint32_t domid, int fd, libxl_domain_build_state *state,
219 libxl_device_model_info *dm_info)
220 {
221 char **vments = NULL, **localents = NULL;
222 int i, ret;
224 ret = build_pre(ctx, domid, info, state);
225 if (ret) goto out;
227 ret = restore_common(ctx, domid, info, state, fd);
228 if (ret) goto out;
230 if (info->hvm) {
231 vments = libxl_calloc(ctx, 5, sizeof(char *));
232 vments[0] = "rtc/timeoffset";
233 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
234 vments[2] = "image/ostype";
235 vments[3] = "hvm";
236 } else {
237 vments = libxl_calloc(ctx, 9, sizeof(char *));
238 i = 0;
239 vments[i++] = "image/ostype";
240 vments[i++] = "linux";
241 vments[i++] = "image/kernel";
242 vments[i++] = (char*) info->kernel;
243 if (info->u.pv.ramdisk) {
244 vments[i++] = "image/ramdisk";
245 vments[i++] = (char*) info->u.pv.ramdisk;
246 }
247 if (info->u.pv.cmdline) {
248 vments[i++] = "image/cmdline";
249 vments[i++] = (char*) info->u.pv.cmdline;
250 }
251 }
252 ret = build_post(ctx, domid, info, state, vments, localents);
253 if (ret) goto out;
255 if (info->hvm)
256 asprintf(&(dm_info->saved_state), "/var/lib/xen/qemu-save.%d", domid);
257 else
258 dm_info->saved_state = NULL;
259 out:
260 return ret;
261 }
263 int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid)
264 {
265 if (is_hvm(ctx, domid)) {
266 XL_LOG(ctx, XL_LOG_DEBUG, "Called domain_resume on "
267 "non-cooperative hvm domain %u", domid);
268 return ERROR_NI;
269 }
270 if (xc_domain_resume(ctx->xch, domid, 1)) {
271 XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
272 "xc_domain_resume failed for domain %u",
273 domid);
274 return ERROR_FAIL;
275 }
276 if (!xs_resume_domain(ctx->xsh, domid)) {
277 XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
278 "xs_resume_domain failed for domain %u",
279 domid);
280 return ERROR_FAIL;
281 }
282 return 0;
283 }
285 struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain)
286 {
287 struct libxl_dominfo *ptr;
288 int index, i, ret, first_domain;
289 xc_domaininfo_t info[1024];
290 int size = 1024;
292 first_domain = 1;
293 index = 0;
294 ptr = calloc(size, sizeof(struct libxl_dominfo));
295 if (!ptr)
296 return NULL;
298 ret = xc_domain_getinfolist(ctx->xch, first_domain, 1024, info);
299 for (i = 0; i < ret; i++) {
300 memcpy(&(ptr[index].uuid), info[i].handle, sizeof(xen_domain_handle_t));
301 ptr[index].domid = info[i].domain;
303 if (info[i].flags & XEN_DOMINF_dying)
304 ptr[index].dying = 1;
305 else if (info[i].flags & XEN_DOMINF_paused)
306 ptr[index].paused = 1;
307 else if (info[i].flags & XEN_DOMINF_blocked || info[i].flags & XEN_DOMINF_running)
308 ptr[index].running = 1;
310 first_domain = info[i].domain + 1;
311 index++;
312 }
313 *nb_domain = index;
314 return ptr;
315 }
317 int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
318 uint32_t domid, int fd)
319 {
320 int hvm = is_hvm(ctx, domid);
321 int live = info != NULL && info->flags & XL_SUSPEND_LIVE;
322 int debug = info != NULL && info->flags & XL_SUSPEND_LIVE;
324 core_suspend(ctx, domid, fd, hvm, live, debug);
325 if (hvm)
326 save_device_model(ctx, domid, fd);
327 return 0;
328 }
330 int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid)
331 {
332 xc_domain_pause(ctx->xch, domid);
333 return 0;
334 }
336 int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid)
337 {
338 char *path;
339 char *state;
341 if (is_hvm(ctx, domid)) {
342 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
343 state = libxl_xs_read(ctx, XBT_NULL, path);
344 if (state != NULL && !strcmp(state, "paused")) {
345 libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "continue", strlen("continue"));
346 libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL);
347 }
348 }
349 xc_domain_unpause(ctx->xch, domid);
351 return 0;
352 }
354 static char *req_table[] = {
355 [0] = "poweroff",
356 [1] = "reboot",
357 [2] = "suspend",
358 [3] = "crash",
359 [4] = "halt",
360 };
362 int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
363 {
364 char *shutdown_path;
365 char *dom_path;
367 if (req > ARRAY_SIZE(req_table))
368 return ERROR_INVAL;
370 dom_path = libxl_xs_get_dompath(ctx, domid);
371 if (!dom_path)
372 return ERROR_FAIL;
374 shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path);
376 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
377 if (/* hvm */ 0) {
378 unsigned long acpi_s_state = 0;
379 unsigned long pvdriver = 0;
380 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
381 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
382 if (!pvdriver && acpi_s_state != 0)
383 xc_domain_shutdown(ctx->xch, domid, req);
384 }
385 return 0;
386 }
388 int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd)
389 {
390 *fd = xs_fileno(ctx->xsh);
391 return 0;
392 }
394 int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
395 {
396 waiter->path = strdup("@releaseDomain");
397 asprintf(&(waiter->token), "%d", DOMAIN_DEATH);
398 if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
399 return -1;
400 return 0;
401 }
403 int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
404 {
405 int i;
406 uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
408 if (!domid)
409 domid = guest_domid;
411 for (i = 0; i < num_disks; i++) {
412 asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", libxl_xs_get_dompath(ctx, domid), device_disk_dev_number(disks[i].virtpath));
413 asprintf(&(waiter[i].token), "%d", DISK_EJECT);
414 xs_watch(ctx->xsh, waiter->path, waiter->token);
415 }
416 return 0;
417 }
419 int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event)
420 {
421 unsigned int num;
422 char **events = xs_read_watch(ctx->xsh, &num);
423 if (num != 2) {
424 free(events);
425 return -1;
426 }
427 event->path = strdup(events[XS_WATCH_PATH]);
428 event->token = strdup(events[XS_WATCH_TOKEN]);
429 event->type = atoi(event->token);
430 free(events);
431 return 0;
432 }
434 int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter)
435 {
436 if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
437 return -1;
438 else
439 return 0;
440 }
442 int libxl_free_event(libxl_event *event)
443 {
444 free(event->path);
445 free(event->token);
446 return 0;
447 }
449 int libxl_free_waiter(libxl_waiter *waiter)
450 {
451 free(waiter->path);
452 free(waiter->token);
453 return 0;
454 }
456 int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_domaininfo_t *info)
457 {
458 int rc = 0, ret;
460 if (event && event->type == DOMAIN_DEATH) {
461 ret = xc_domain_getinfolist(ctx->xch, domid, 1, info);
462 if (ret == 1 && info->domain == domid) {
463 if (info->flags & XEN_DOMINF_running ||
464 (!(info->flags & XEN_DOMINF_shutdown) && !(info->flags & XEN_DOMINF_dying)))
465 goto out;
466 rc = 1;
467 goto out;
468 }
469 memset(info, 0, sizeof(xc_dominfo_t));
470 rc = 1;
471 goto out;
472 }
473 out:
474 return rc;
475 }
477 int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
478 {
479 if (event && event->type == DISK_EJECT) {
480 char *path;
481 char *backend;
482 char *value = libxl_xs_read(ctx, XBT_NULL, event->path);
484 if (!value || strcmp(value, "eject"))
485 return 0;
487 path = strdup(event->path);
488 path[strlen(path) - 6] = '\0';
489 backend = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", path));
491 disk->backend_domid = 0;
492 disk->domid = domid;
493 disk->physpath = NULL;
494 disk->phystype = 0;
495 /* this value is returned to the user: do not free right away */
496 disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", backend));
497 disk->unpluggable = 1;
498 disk->readwrite = 0;
499 disk->is_cdrom = 1;
501 free(path);
502 return 1;
503 }
504 return 0;
505 }
507 static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
508 {
509 char *pid;
510 int ret;
512 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
513 if (!pid) {
514 int stubdomid = libxl_get_stubdom_id(ctx, domid);
515 if (!stubdomid) {
516 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't find device model's pid");
517 return -1;
518 }
519 XL_LOG(ctx, XL_LOG_ERROR, "Device model is a stubdom, domid=%d\n", stubdomid);
520 return libxl_domain_destroy(ctx, stubdomid, 0);
521 }
522 xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid));
524 ret = kill(atoi(pid), SIGHUP);
525 if (ret < 0 && errno == ESRCH) {
526 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited");
527 ret = 0;
528 } else if (ret == 0) {
529 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled");
530 ret = 0;
531 } else {
532 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to kill Device Model [%d]",
533 atoi(pid));
534 }
535 return ret;
536 }
538 int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
539 {
540 char *dom_path;
541 char *vm_path, *vss_path, *xapi_path;
542 int rc, dm_present;
544 if (is_hvm(ctx, domid)) {
545 dm_present = 1;
546 } else {
547 char *pid;
548 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
549 dm_present = (pid != NULL);
550 libxl_free(ctx, pid);
551 }
553 dom_path = libxl_xs_get_dompath(ctx, domid);
554 if (!dom_path)
555 return -1;
557 if (libxl_device_pci_shutdown(ctx, domid) < 0)
558 XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d", domid);
559 if (dm_present) {
560 xs_write(ctx->xsh, XBT_NULL,
561 libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
562 "shutdown", strlen("shutdown"));
563 }
564 rc = xc_domain_pause(ctx->xch, domid);
565 if (rc < 0) {
566 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
567 return -1;
568 }
569 if (dm_present) {
570 if (libxl_destroy_device_model(ctx, domid) < 0)
571 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d", domid);
572 }
573 if (libxl_devices_destroy(ctx, domid, force) < 0)
574 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d", domid);
575 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
576 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", dom_path);
578 vm_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vm", domid));
579 if (vm_path)
580 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
581 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", vm_path);
583 vss_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vss", domid));
584 if (vss_path)
585 if (!xs_rm(ctx->xsh, XBT_NULL, vss_path))
586 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", vss_path);
588 xapi_path = libxl_sprintf(ctx, "/xapi/%u", domid);
589 if (xapi_path)
590 if (!xs_rm(ctx->xsh, XBT_NULL, xapi_path))
591 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", xapi_path);
593 rc = xc_domain_destroy(ctx->xch, domid);
594 if (rc < 0) {
595 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_destroy failed for %d", domid);
596 return -1;
597 }
598 return 0;
599 }
601 int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num)
602 {
603 struct stat st;
604 const char *XENCONSOLE = "/usr/lib/xen/bin/xenconsole";
605 char *cmd;
607 if (stat(XENCONSOLE, &st) != 0) {
608 XL_LOG(ctx, XL_LOG_ERROR, "could not access %s", XENCONSOLE);
609 return ERROR_FAIL;
610 }
612 cmd = libxl_sprintf(ctx, "%s %d --num %d", XENCONSOLE, domid, cons_num);
613 return (system(cmd) != 0) ? ERROR_FAIL : 0;
614 }
616 static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
617 libxl_device_model_info *info,
618 libxl_device_nic *vifs,
619 int num_vifs)
620 {
621 int num = 0, i;
622 flexarray_t *dm_args;
623 dm_args = flexarray_make(16, 1);
624 if (!dm_args)
625 return NULL;
627 flexarray_set(dm_args, num++, "qemu-dm");
628 flexarray_set(dm_args, num++, "-d");
630 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid));
632 if (info->dom_name) {
633 flexarray_set(dm_args, num++, "-domain-name");
634 flexarray_set(dm_args, num++, info->dom_name);
635 }
636 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
637 flexarray_set(dm_args, num++, "-vnc");
638 if (info->vncdisplay) {
639 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
640 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay));
641 } else {
642 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay));
643 }
644 } else if (info->vnclisten) {
645 if (strchr(info->vnclisten, ':') != NULL) {
646 flexarray_set(dm_args, num++, info->vnclisten);
647 } else {
648 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten));
649 }
650 } else {
651 flexarray_set(dm_args, num++, "127.0.0.1:0");
652 }
653 if (info->vncunused) {
654 flexarray_set(dm_args, num++, "-vncunused");
655 }
656 }
657 if (info->sdl || info->opengl) {
658 flexarray_set(dm_args, num++, "-sdl");
659 if (info->opengl) {
660 flexarray_set(dm_args, num++, "-disable-opengl");
661 }
662 }
663 if (info->keymap) {
664 flexarray_set(dm_args, num++, "-k");
665 flexarray_set(dm_args, num++, info->keymap);
666 }
667 if (info->nographic && (!info->sdl && !info->vnc)) {
668 flexarray_set(dm_args, num++, "-nographic");
669 }
670 if (info->serial) {
671 flexarray_set(dm_args, num++, "-serial");
672 flexarray_set(dm_args, num++, info->serial);
673 }
674 if (info->type == XENFV) {
675 if (info->videoram) {
676 flexarray_set(dm_args, num++, "-videoram");
677 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram));
678 }
679 if (info->stdvga) {
680 flexarray_set(dm_args, num++, "-std-vga");
681 }
683 if (info->boot) {
684 flexarray_set(dm_args, num++, "-boot");
685 flexarray_set(dm_args, num++, info->boot);
686 }
687 if (info->usb) {
688 flexarray_set(dm_args, num++, "-usb");
689 if (info->usbdevice) {
690 flexarray_set(dm_args, num++, "-usbdevice");
691 flexarray_set(dm_args, num++, info->usbdevice);
692 }
693 }
694 if (info->apic) {
695 flexarray_set(dm_args, num++, "-acpi");
696 }
697 for (i = 0; i < num_vifs; i++) {
698 if (vifs[i].nictype == NICTYPE_IOEMU) {
699 char *smac = libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
700 vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2],
701 vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
702 if (!vifs[i].ifname)
703 vifs[i].ifname = libxl_sprintf(ctx, "tap%d.%d", info->domid, vifs[i].devid - 1);
704 flexarray_set(dm_args, num++, "-net");
705 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s",
706 vifs[i].devid, smac, vifs[i].model));
707 flexarray_set(dm_args, num++, "-net");
708 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s",
709 vifs[i].devid, vifs[i].ifname, vifs[i].bridge));
710 }
711 }
712 }
713 if (info->saved_state) {
714 flexarray_set(dm_args, num++, "-loadvm");
715 flexarray_set(dm_args, num++, info->saved_state);
716 }
717 for (i = 0; info->extra && info->extra[i] != NULL; i++)
718 flexarray_set(dm_args, num++, info->extra[i]);
719 flexarray_set(dm_args, num++, "-M");
720 if (info->type == XENPV)
721 flexarray_set(dm_args, num++, "xenpv");
722 else
723 flexarray_set(dm_args, num++, "xenfv");
724 flexarray_set(dm_args, num++, NULL);
726 return (char **) flexarray_contents(dm_args);
727 }
729 void dm_xenstore_record_pid(void *for_spawn, pid_t innerchild)
730 {
731 struct libxl_device_model_starting *starting = for_spawn;
732 char *kvs[3];
733 int rc;
734 struct xs_handle *xsh;
736 xsh = xs_daemon_open();
737 /* we mustn't use the parent's handle in the child */
739 kvs[0] = "image/device-model-pid";
740 asprintf(&kvs[1], "%d", innerchild);
741 kvs[2] = NULL;
743 rc = xs_writev(xsh, XBT_NULL, starting->dom_path, kvs);
744 if (rc)
745 return;
746 xs_daemon_close(xsh);
747 }
749 static int libxl_vfb_and_vkb_from_device_model_info(struct libxl_ctx *ctx,
750 libxl_device_model_info *info,
751 libxl_device_vfb *vfb,
752 libxl_device_vkb *vkb)
753 {
754 memset(vfb, 0x00, sizeof(libxl_device_vfb));
755 memset(vkb, 0x00, sizeof(libxl_device_vkb));
757 vfb->backend_domid = 0;
758 vfb->devid = 0;
759 vfb->vnc = info->vnc;
760 vfb->vnclisten = info->vnclisten;
761 vfb->vncdisplay = info->vncdisplay;
762 vfb->vncunused = info->vncunused;
763 vfb->keymap = info->keymap;
764 vfb->sdl = info->sdl;
765 vfb->opengl = info->opengl;
767 vkb->backend_domid = 0;
768 vkb->devid = 0;
769 return 0;
770 }
772 static int libxl_write_dmargs(struct libxl_ctx *ctx, int domid, int guest_domid, char **args)
773 {
774 int i;
775 char *vm_path;
776 char *dmargs, *path;
777 int dmargs_size;
778 struct xs_permissions roperm[2];
779 xs_transaction_t t;
781 roperm[0].id = 0;
782 roperm[0].perms = XS_PERM_NONE;
783 roperm[1].id = domid;
784 roperm[1].perms = XS_PERM_READ;
786 vm_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vm", guest_domid));
788 i = 0;
789 dmargs_size = 0;
790 while (args[i] != NULL) {
791 dmargs_size = dmargs_size + strlen(args[i]) + 1;
792 i++;
793 }
794 dmargs_size++;
795 dmargs = (char *) malloc(dmargs_size);
796 i = 1;
797 dmargs[0] = '\0';
798 while (args[i] != NULL) {
799 if (strcmp(args[i], "-sdl") && strcmp(args[i], "-M") && strcmp(args[i], "xenfv")) {
800 strcat(dmargs, " ");
801 strcat(dmargs, args[i]);
802 }
803 i++;
804 }
805 path = libxl_sprintf(ctx, "%s/image/dmargs", vm_path);
807 retry_transaction:
808 t = xs_transaction_start(ctx->xsh);
809 xs_write(ctx->xsh, t, path, dmargs, strlen(dmargs));
810 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
811 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "%s/rtc/timeoffset", vm_path), roperm, ARRAY_SIZE(roperm));
812 if (!xs_transaction_end(ctx->xsh, t, 0))
813 if (errno == EAGAIN)
814 goto retry_transaction;
815 free(dmargs);
816 return 0;
817 }
819 static int libxl_create_stubdom(struct libxl_ctx *ctx,
820 libxl_device_model_info *info,
821 libxl_device_disk *disks, int num_disks,
822 libxl_device_nic *vifs, int num_vifs,
823 libxl_device_vfb *vfb,
824 libxl_device_vkb *vkb,
825 libxl_device_model_starting **starting_r)
826 {
827 int i, num_console = 1, ret;
828 libxl_device_console *console;
829 libxl_domain_create_info c_info;
830 libxl_domain_build_info b_info;
831 libxl_domain_build_state state;
832 uint32_t domid;
833 char **args;
834 struct xs_permissions perm[2];
835 xs_transaction_t t;
836 libxl_device_model_starting *dm_starting = 0;
838 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
839 if (!args)
840 return ERROR_FAIL;
842 memset(&c_info, 0x00, sizeof(libxl_domain_create_info));
843 c_info.hvm = 0;
844 c_info.name = libxl_sprintf(ctx, "%s-dm", libxl_domid_to_name(ctx, info->domid));
845 for (i = 0; i < 16; i++)
846 c_info.uuid[i] = info->uuid[i];
848 memset(&b_info, 0x00, sizeof(libxl_domain_build_info));
849 b_info.max_vcpus = 1;
850 b_info.max_memkb = 32 * 1024;
851 b_info.target_memkb = b_info.max_memkb;
852 b_info.kernel = "/usr/lib/xen/boot/ioemu-stubdom.gz";
853 b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid);
854 b_info.u.pv.ramdisk = "";
855 b_info.u.pv.features = "";
856 b_info.hvm = 0;
858 ret = libxl_domain_make(ctx, &c_info, &domid);
859 if (ret) return ret;
860 ret = libxl_domain_build(ctx, &b_info, domid, &state);
861 if (ret) return ret;
863 libxl_write_dmargs(ctx, domid, info->domid, args);
864 libxl_xs_write(ctx, XBT_NULL,
865 libxl_sprintf(ctx, "%s/image/device-model-domid", libxl_xs_get_dompath(ctx, info->domid)),
866 "%d", domid);
867 libxl_xs_write(ctx, XBT_NULL,
868 libxl_sprintf(ctx, "%s/target", libxl_xs_get_dompath(ctx, domid)),
869 "%d", info->domid);
870 xc_domain_set_target(ctx->xch, domid, info->domid);
871 xs_set_target(ctx->xsh, domid, info->domid);
873 perm[0].id = domid;
874 perm[0].perms = XS_PERM_NONE;
875 perm[1].id = info->domid;
876 perm[1].perms = XS_PERM_READ;
877 retry_transaction:
878 t = xs_transaction_start(ctx->xsh);
879 xs_mkdir(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid));
880 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid), perm, ARRAY_SIZE(perm));
881 xs_mkdir(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/%d/device/vfs", domid));
882 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/%d/device/vfs",domid), perm, ARRAY_SIZE(perm));
883 if (!xs_transaction_end(ctx->xsh, t, 0))
884 if (errno == EAGAIN)
885 goto retry_transaction;
887 for (i = 0; i < num_disks; i++) {
888 disks[i].domid = domid;
889 ret = libxl_device_disk_add(ctx, domid, &disks[i]);
890 if (ret) return ret;
891 }
892 for (i = 0; i < num_vifs; i++) {
893 vifs[i].domid = domid;
894 ret = libxl_device_nic_add(ctx, domid, &vifs[i]);
895 if (ret) return ret;
896 }
897 vfb->domid = domid;
898 ret = libxl_device_vfb_add(ctx, domid, vfb);
899 if (ret) return ret;
900 vkb->domid = domid;
901 ret = libxl_device_vkb_add(ctx, domid, vkb);
902 if (ret) return ret;
904 if (info->serial)
905 num_console++;
907 console = libxl_calloc(ctx, num_console, sizeof(libxl_device_console));
908 if (!console)
909 return ERROR_NOMEM;
911 for (i = 0; i < num_console; i++) {
912 console[i].devid = i;
913 console[i].constype = CONSTYPE_IOEMU;
914 console[i].domid = domid;
915 if (!i)
916 console[i].build_state = &state;
917 ret = libxl_device_console_add(ctx, domid, &console[i]);
918 if (ret) return ret;
919 }
920 if (libxl_create_xenpv_qemu(ctx, vfb, num_console, console, &dm_starting) < 0) {
921 free(args);
922 return -1;
923 }
924 if (libxl_confirm_device_model_startup(ctx, dm_starting) < 0) {
925 free(args);
926 return -1;
927 }
929 libxl_domain_unpause(ctx, domid);
931 if (starting_r) {
932 *starting_r = libxl_calloc(ctx, sizeof(libxl_device_model_starting), 1);
933 (*starting_r)->domid = info->domid;
934 (*starting_r)->dom_path = libxl_xs_get_dompath(ctx, info->domid);
935 (*starting_r)->for_spawn = NULL;
936 }
938 free(args);
939 return 0;
940 }
942 int libxl_create_device_model(struct libxl_ctx *ctx,
943 libxl_device_model_info *info,
944 libxl_device_disk *disks, int num_disks,
945 libxl_device_nic *vifs, int num_vifs,
946 libxl_device_model_starting **starting_r)
947 {
948 char *path, *logfile;
949 int logfile_w, null;
950 int rc;
951 char **args;
952 struct libxl_device_model_starting buf_starting, *p;
954 if (strstr(info->device_model, "stubdom-dm")) {
955 libxl_device_vfb vfb;
956 libxl_device_vkb vkb;
958 libxl_vfb_and_vkb_from_device_model_info(ctx, info, &vfb, &vkb);
959 return libxl_create_stubdom(ctx, info, disks, num_disks, vifs, num_vifs, &vfb, &vkb, starting_r);
960 }
962 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
963 if (!args)
964 return ERROR_FAIL;
966 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
967 xs_mkdir(ctx->xsh, XBT_NULL, path);
969 libxl_create_logfile(ctx, libxl_sprintf(ctx, "qemu-dm-%s", info->dom_name), &logfile);
970 logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
971 free(logfile);
972 null = open("/dev/null", O_RDONLY);
974 if (starting_r) {
975 rc = ERROR_NOMEM;
976 *starting_r = libxl_calloc(ctx, sizeof(libxl_device_model_starting), 1);
977 if (!*starting_r) goto xit;
978 p = *starting_r;
979 p->for_spawn = libxl_calloc(ctx, sizeof(struct libxl_spawn_starting), 1);
980 } else {
981 p = &buf_starting;
982 p->for_spawn = NULL;
983 }
985 p->domid = info->domid;
986 p->dom_path = libxl_xs_get_dompath(ctx, info->domid);
987 if (!p->dom_path) { libxl_free(ctx, p); return ERROR_FAIL; }
989 rc = libxl_spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid);
990 if (rc < 0) goto xit;
991 if (!rc) { /* inner child */
992 libxl_exec(null, logfile_w, logfile_w,
993 info->device_model, args);
994 }
996 rc = 0;
997 xit:
998 free(args);
999 close(null);
1000 close(logfile_w);
1002 return rc;
1005 int libxl_detach_device_model(struct libxl_ctx *ctx,
1006 libxl_device_model_starting *starting)
1008 int rc;
1009 rc = libxl_spawn_detach(ctx, starting->for_spawn);
1010 if (starting->for_spawn) libxl_free(ctx, starting->for_spawn);
1011 libxl_free(ctx, starting);
1012 return rc;
1016 int libxl_confirm_device_model_startup(struct libxl_ctx *ctx,
1017 libxl_device_model_starting *starting)
1019 int problem = libxl_wait_for_device_model(ctx, starting->domid, "running",
1020 libxl_spawn_check,
1021 starting->for_spawn);
1022 int detach = libxl_detach_device_model(ctx, starting);
1023 return problem ? problem : detach;
1024 return 0;
1028 /******************************************************************************/
1030 static int is_blktap2_supported(void)
1032 char buf[1024];
1033 FILE *f = fopen("/proc/devices", "r");
1036 while (fgets(buf, sizeof(buf), f) != NULL) {
1037 if (strstr(buf, "blktap2")) {
1038 fclose(f);
1039 return 1;
1042 fclose(f);
1043 return 0;
1046 static char *get_blktap2_device(struct libxl_ctx *ctx, char *name, char *type)
1048 char buf[1024];
1049 char *p;
1050 int devnum;
1051 FILE *f = fopen("/sys/class/blktap2/devices", "r");
1054 while (!feof(f)) {
1055 fscanf(f, "%d %s", &devnum, buf);
1056 p = strchr(buf, ':');
1057 if (p == NULL)
1058 continue;
1059 p++;
1060 if (!strcmp(p, name) && !strncmp(buf, type, 3)) {
1061 fclose(f);
1062 return libxl_sprintf(ctx, "/dev/xen/blktap-2/tapdev%d", devnum);
1065 fclose(f);
1066 return NULL;
1069 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
1071 flexarray_t *front;
1072 flexarray_t *back;
1073 char *backend_type;
1074 unsigned int boffset = 0;
1075 unsigned int foffset = 0;
1076 int devid;
1077 libxl_device device;
1078 int major, minor;
1080 front = flexarray_make(16, 1);
1081 if (!front)
1082 return ERROR_NOMEM;
1083 back = flexarray_make(16, 1);
1084 if (!back) /* leaks front if error */
1085 return ERROR_NOMEM;
1087 backend_type = device_disk_backend_type_of_phystype(disk->phystype);
1088 devid = device_disk_dev_number(disk->virtpath);
1090 device.backend_devid = devid;
1091 device.backend_domid = disk->backend_domid;
1092 device.devid = devid;
1093 device.domid = disk->domid;
1094 device.kind = DEVICE_VBD;
1096 switch (disk->phystype) {
1097 case PHYSTYPE_PHY: {
1099 device_physdisk_major_minor(disk->physpath, &major, &minor);
1100 flexarray_set(back, boffset++, "physical-device");
1101 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
1103 flexarray_set(back, boffset++, "params");
1104 flexarray_set(back, boffset++, disk->physpath);
1106 device.backend_kind = DEVICE_VBD;
1107 break;
1109 case PHYSTYPE_FILE:
1110 /* let's pretend is tap:aio for the moment */
1111 disk->phystype = PHYSTYPE_AIO;
1112 case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD:
1113 if (is_blktap2_supported()) {
1114 int rc, c, p[2], tot;
1115 char buf[1024], *dev;
1116 dev = get_blktap2_device(ctx, disk->physpath, device_disk_string_of_phystype(disk->phystype));
1117 if (dev == NULL) {
1118 if (pipe(p) < 0) {
1119 XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe");
1120 return -1;
1122 rc = fork();
1123 if (rc < 0) {
1124 XL_LOG(ctx, XL_LOG_ERROR, "Failed to fork a new process");
1125 return -1;
1126 } else if (!rc) { /* child */
1127 int null_r, null_w;
1128 char *args[4];
1129 args[0] = "tapdisk2";
1130 args[1] = "-n";
1131 args[2] = libxl_sprintf(ctx, "%s:%s", device_disk_string_of_phystype(disk->phystype), disk->physpath);
1132 args[3] = NULL;
1134 null_r = open("/dev/null", O_RDONLY);
1135 null_w = open("/dev/null", O_WRONLY);
1136 libxl_exec(null_r, p[1], null_w, "/usr/sbin/tapdisk2", args);
1137 XL_LOG(ctx, XL_LOG_ERROR, "Error execing tapdisk2");
1139 close(p[1]);
1140 tot = 0;
1141 while ((c = read(p[0], buf + tot, sizeof(buf) - tot)) > 0)
1142 tot = tot + c;
1143 close(p[0]);
1144 buf[tot - 1] = '\0';
1145 dev = buf;
1147 flexarray_set(back, boffset++, "tapdisk-params");
1148 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s", device_disk_string_of_phystype(disk->phystype), disk->physpath));
1149 flexarray_set(back, boffset++, "params");
1150 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", dev));
1151 backend_type = "phy";
1152 device_physdisk_major_minor(dev, &major, &minor);
1153 flexarray_set(back, boffset++, "physical-device");
1154 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
1155 device.backend_kind = DEVICE_VBD;
1157 break;
1159 flexarray_set(back, boffset++, "params");
1160 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s",
1161 device_disk_string_of_phystype(disk->phystype), disk->physpath));
1163 device.backend_kind = DEVICE_TAP;
1164 break;
1165 default:
1166 XL_LOG(ctx, XL_LOG_ERROR, "unrecognized disk physical type: %d\n", disk->phystype);
1167 return ERROR_INVAL;
1170 flexarray_set(back, boffset++, "frontend-id");
1171 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid));
1172 flexarray_set(back, boffset++, "online");
1173 flexarray_set(back, boffset++, "1");
1174 flexarray_set(back, boffset++, "removable");
1175 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0));
1176 flexarray_set(back, boffset++, "bootable");
1177 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1178 flexarray_set(back, boffset++, "state");
1179 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1180 flexarray_set(back, boffset++, "dev");
1181 flexarray_set(back, boffset++, disk->virtpath);
1182 flexarray_set(back, boffset++, "type");
1183 flexarray_set(back, boffset++, backend_type);
1184 flexarray_set(back, boffset++, "mode");
1185 flexarray_set(back, boffset++, disk->readwrite ? "w" : "r");
1187 flexarray_set(front, foffset++, "backend-id");
1188 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid));
1189 flexarray_set(front, foffset++, "state");
1190 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1191 flexarray_set(front, foffset++, "virtual-device");
1192 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid));
1193 flexarray_set(front, foffset++, "device-type");
1194 flexarray_set(front, foffset++, disk->is_cdrom ? "cdrom" : "disk");
1196 if (0 /* protocol != native*/) {
1197 flexarray_set(front, foffset++, "protocol");
1198 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
1201 libxl_device_generic_add(ctx, &device,
1202 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1203 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1204 flexarray_free(back);
1205 flexarray_free(front);
1206 return 0;
1209 int libxl_device_disk_del(struct libxl_ctx *ctx,
1210 libxl_device_disk *disk, int wait)
1212 libxl_device device;
1213 int devid;
1215 devid = device_disk_dev_number(disk->virtpath);
1216 device.backend_domid = disk->backend_domid;
1217 device.backend_devid = devid;
1218 device.backend_kind =
1219 (disk->phystype == PHYSTYPE_PHY) ? DEVICE_VBD : DEVICE_TAP;
1220 device.domid = disk->domid;
1221 device.devid = devid;
1222 device.kind = DEVICE_VBD;
1223 return libxl_device_del(ctx, &device, wait);
1226 /******************************************************************************/
1227 int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
1229 flexarray_t *front;
1230 flexarray_t *back;
1231 unsigned int boffset = 0;
1232 unsigned int foffset = 0;
1233 libxl_device device;
1235 front = flexarray_make(16, 1);
1236 if (!front)
1237 return ERROR_NOMEM;
1238 back = flexarray_make(16, 1);
1239 if (!back)
1240 return ERROR_NOMEM;
1242 device.backend_devid = nic->devid;
1243 device.backend_domid = nic->backend_domid;
1244 device.backend_kind = DEVICE_VIF;
1245 device.devid = nic->devid;
1246 device.domid = nic->domid;
1247 device.kind = DEVICE_VIF;
1249 flexarray_set(back, boffset++, "frontend-id");
1250 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid));
1251 flexarray_set(back, boffset++, "online");
1252 flexarray_set(back, boffset++, "1");
1253 flexarray_set(back, boffset++, "state");
1254 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1255 flexarray_set(back, boffset++, "script");
1256 flexarray_set(back, boffset++, nic->script);
1257 flexarray_set(back, boffset++, "mac");
1258 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1259 nic->mac[0], nic->mac[1], nic->mac[2],
1260 nic->mac[3], nic->mac[4], nic->mac[5]));
1261 flexarray_set(back, boffset++, "handle");
1262 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
1264 flexarray_set(front, foffset++, "backend-id");
1265 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid));
1266 flexarray_set(front, foffset++, "state");
1267 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1268 flexarray_set(front, foffset++, "handle");
1269 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid));
1270 flexarray_set(front, foffset++, "mac");
1271 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1272 nic->mac[0], nic->mac[1], nic->mac[2],
1273 nic->mac[3], nic->mac[4], nic->mac[5]));
1274 if (0 /* protocol != native*/) {
1275 flexarray_set(front, foffset++, "protocol");
1276 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
1279 libxl_device_generic_add(ctx, &device,
1280 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1281 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1283 /* FIXME: wait for plug */
1284 flexarray_free(back);
1285 flexarray_free(front);
1286 return 0;
1289 int libxl_device_nic_del(struct libxl_ctx *ctx,
1290 libxl_device_nic *nic, int wait)
1292 libxl_device device;
1294 device.backend_devid = nic->devid;
1295 device.backend_domid = nic->backend_domid;
1296 device.backend_kind = DEVICE_VIF;
1297 device.devid = nic->devid;
1298 device.domid = nic->domid;
1299 device.kind = DEVICE_VIF;
1301 return libxl_device_del(ctx, &device, wait);
1304 /******************************************************************************/
1305 int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
1307 flexarray_t *front;
1308 flexarray_t *back;
1309 unsigned int boffset = 0;
1310 unsigned int foffset = 0;
1311 libxl_device device;
1313 if (console->build_state) {
1314 xs_transaction_t t;
1315 char **ents = (char **) libxl_calloc(ctx, 9, sizeof(char *));
1316 ents[0] = "console/port";
1317 ents[1] = libxl_sprintf(ctx, "%"PRIu32, console->build_state->console_port);
1318 ents[2] = "console/ring-ref";
1319 ents[3] = libxl_sprintf(ctx, "%lu", console->build_state->console_mfn);
1320 ents[4] = "console/limit";
1321 ents[5] = libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT);
1322 ents[6] = "console/type";
1323 if (console->constype == CONSTYPE_XENCONSOLED)
1324 ents[7] = "xenconsoled";
1325 else
1326 ents[7] = "ioemu";
1327 retry_transaction:
1328 t = xs_transaction_start(ctx->xsh);
1329 libxl_xs_writev(ctx, t, libxl_xs_get_dompath(ctx, console->domid), ents);
1330 if (!xs_transaction_end(ctx->xsh, t, 0))
1331 if (errno == EAGAIN)
1332 goto retry_transaction;
1335 front = flexarray_make(16, 1);
1336 if (!front)
1337 return ERROR_NOMEM;
1338 back = flexarray_make(16, 1);
1339 if (!back)
1340 return ERROR_NOMEM;
1342 device.backend_devid = console->devid;
1343 device.backend_domid = console->backend_domid;
1344 device.backend_kind = DEVICE_CONSOLE;
1345 device.devid = console->devid;
1346 device.domid = console->domid;
1347 device.kind = DEVICE_CONSOLE;
1349 flexarray_set(back, boffset++, "frontend-id");
1350 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", console->domid));
1351 flexarray_set(back, boffset++, "online");
1352 flexarray_set(back, boffset++, "1");
1353 flexarray_set(back, boffset++, "state");
1354 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1355 flexarray_set(back, boffset++, "domain");
1356 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
1357 flexarray_set(back, boffset++, "protocol");
1358 flexarray_set(back, boffset++, LIBXL_XENCONSOLE_PROTOCOL);
1360 flexarray_set(front, foffset++, "backend-id");
1361 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", console->backend_domid));
1362 flexarray_set(front, foffset++, "state");
1363 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1364 flexarray_set(front, foffset++, "limit");
1365 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT));
1366 flexarray_set(front, foffset++, "protocol");
1367 flexarray_set(front, foffset++, LIBXL_XENCONSOLE_PROTOCOL);
1368 flexarray_set(front, foffset++, "type");
1369 if (console->constype == CONSTYPE_XENCONSOLED)
1370 flexarray_set(front, foffset++, "xenconsoled");
1371 else
1372 flexarray_set(front, foffset++, "ioemu");
1374 libxl_device_generic_add(ctx, &device,
1375 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1376 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1377 flexarray_free(back);
1378 flexarray_free(front);
1380 return 0;
1383 /******************************************************************************/
1384 int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
1386 flexarray_t *front;
1387 flexarray_t *back;
1388 unsigned int boffset = 0;
1389 unsigned int foffset = 0;
1390 libxl_device device;
1392 front = flexarray_make(16, 1);
1393 if (!front)
1394 return ERROR_NOMEM;
1395 back = flexarray_make(16, 1);
1396 if (!back)
1397 return ERROR_NOMEM;
1399 device.backend_devid = vkb->devid;
1400 device.backend_domid = vkb->backend_domid;
1401 device.backend_kind = DEVICE_VKBD;
1402 device.devid = vkb->devid;
1403 device.domid = vkb->domid;
1404 device.kind = DEVICE_VKBD;
1406 flexarray_set(back, boffset++, "frontend-id");
1407 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vkb->domid));
1408 flexarray_set(back, boffset++, "online");
1409 flexarray_set(back, boffset++, "1");
1410 flexarray_set(back, boffset++, "state");
1411 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1412 flexarray_set(back, boffset++, "domain");
1413 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
1415 flexarray_set(front, foffset++, "backend-id");
1416 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vkb->backend_domid));
1417 flexarray_set(front, foffset++, "state");
1418 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1420 libxl_device_generic_add(ctx, &device,
1421 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1422 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1423 flexarray_free(back);
1424 flexarray_free(front);
1426 return 0;
1429 int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
1431 return ERROR_NI;
1434 int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
1436 return ERROR_NI;
1439 libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
1441 char *be_path_tap, *be_path_vbd;
1442 libxl_device_disk *disks = NULL;
1443 char **l = NULL;
1444 unsigned int numl;
1445 int num_disks = 0, i;
1446 char *type;
1448 be_path_vbd = libxl_sprintf(ctx, "%s/backend/vbd/%d", libxl_xs_get_dompath(ctx, 0), domid);
1449 be_path_tap = libxl_sprintf(ctx, "%s/backend/tap/%d", libxl_xs_get_dompath(ctx, 0), domid);
1451 l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
1452 if (l) {
1453 num_disks += numl;
1454 disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
1455 for (i = 0; i < numl; i++) {
1456 disks[i].backend_domid = 0;
1457 disks[i].domid = domid;
1458 disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_vbd, l[i]));
1459 libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, l[i])), &(disks[i].phystype));
1460 disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_vbd, l[i]));
1461 disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, l[i])));
1462 if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_vbd, l[i])), "w"))
1463 disks[i].readwrite = 1;
1464 else
1465 disks[i].readwrite = 0;
1466 type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
1467 disks[i].is_cdrom = !strcmp(type, "cdrom");
1469 free(l);
1471 l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
1472 if (l) {
1473 num_disks += numl;
1474 disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
1475 for (i = 0; i < numl; i++) {
1476 disks[i].backend_domid = 0;
1477 disks[i].domid = domid;
1478 disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_tap, l[i]));
1479 libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_tap, l[i])), &(disks[i].phystype));
1480 disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_tap, l[i]));
1481 disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, l[i])));
1482 if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_tap, l[i])), "w"))
1483 disks[i].readwrite = 1;
1484 else
1485 disks[i].readwrite = 0;
1486 type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
1487 disks[i].is_cdrom = !strcmp(type, "cdrom");
1489 free(l);
1491 *num = num_disks;
1492 return disks;
1495 int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
1497 int num, i;
1498 uint32_t stubdomid;
1499 libxl_device_disk *disks;
1501 if (!disk->physpath) {
1502 disk->physpath = "";
1503 disk->phystype = PHYSTYPE_PHY;
1505 disks = libxl_device_disk_list(ctx, domid, &num);
1506 for (i = 0; i < num; i++) {
1507 if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
1508 /* found */
1509 break;
1511 if (i == num) {
1512 XL_LOG(ctx, XL_LOG_ERROR, "Virtual device not found");
1513 return -1;
1515 libxl_device_disk_del(ctx, disks + i, 1);
1516 libxl_device_disk_add(ctx, domid, disk);
1517 stubdomid = libxl_get_stubdom_id(ctx, domid);
1518 if (stubdomid) {
1519 disks[i].domid = stubdomid;
1520 libxl_device_disk_del(ctx, disks + i, 1);
1521 disk->domid = stubdomid;
1522 libxl_device_disk_add(ctx, stubdomid, disk);
1523 disk->domid = domid;
1525 return 0;
1528 /******************************************************************************/
1529 static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
1530 libxl_device_vfb *vfb,
1531 int num_console,
1532 libxl_device_console *console,
1533 libxl_device_model_info *info) {
1534 int i = 0, j = 0, num = 0;
1535 memset(info, 0x00, sizeof(libxl_device_model_info));
1537 info->vnc = vfb->vnc;
1538 if (vfb->vnclisten)
1539 info->vnclisten = libxl_sprintf(ctx, "%s", vfb->vnclisten);
1540 info->vncdisplay = vfb->vncdisplay;
1541 info->vncunused = vfb->vncunused;
1542 if (vfb->keymap)
1543 info->keymap = libxl_sprintf(ctx, "%s", vfb->keymap);
1544 info->sdl = vfb->sdl;
1545 info->opengl = vfb->opengl;
1546 for (i = 0; i < num_console; i++) {
1547 if (console->constype == CONSTYPE_IOEMU)
1548 num++;
1550 if (num > 0) {
1551 uint32_t guest_domid = libxl_is_stubdom(ctx, vfb->domid);
1552 if (guest_domid) {
1553 char *filename;
1554 char *name = libxl_sprintf(ctx, "qemu-dm-%s", libxl_domid_to_name(ctx, guest_domid));
1555 libxl_create_logfile(ctx, name, &filename);
1556 info->serial = libxl_sprintf(ctx, "file:%s", filename);
1557 free(filename);
1558 } else {
1559 info->serial = "pty";
1561 num--;
1563 if (num > 0) {
1564 info->extra = (char **) libxl_calloc(ctx, num * 2 + 1, sizeof(char *));
1565 for (j = 0; j < num * 2; j = j + 2) {
1566 info->extra[j] = "-serial";
1567 info->extra[j + 1] = "pty";
1569 info->extra[j] = NULL;
1571 info->domid = vfb->domid;
1572 info->dom_name = libxl_domid_to_name(ctx, vfb->domid);
1573 info->device_model = "/usr/lib/xen/bin/qemu-dm";
1574 info->type = XENPV;
1575 return 0;
1578 int libxl_create_xenpv_qemu(struct libxl_ctx *ctx, libxl_device_vfb *vfb,
1579 int num_console, libxl_device_console *console,
1580 struct libxl_device_model_starting **starting_r)
1582 libxl_device_model_info info;
1584 libxl_build_xenpv_qemu_args(ctx, vfb, num_console, console, &info);
1585 libxl_create_device_model(ctx, &info, NULL, 0, NULL, 0, starting_r);
1586 return 0;
1589 int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
1591 flexarray_t *front;
1592 flexarray_t *back;
1593 unsigned int boffset = 0;
1594 unsigned int foffset = 0;
1595 libxl_device device;
1597 front = flexarray_make(16, 1);
1598 if (!front)
1599 return ERROR_NOMEM;
1600 back = flexarray_make(16, 1);
1601 if (!back)
1602 return ERROR_NOMEM;
1604 device.backend_devid = vfb->devid;
1605 device.backend_domid = vfb->backend_domid;
1606 device.backend_kind = DEVICE_VFB;
1607 device.devid = vfb->devid;
1608 device.domid = vfb->domid;
1609 device.kind = DEVICE_VFB;
1611 flexarray_set(back, boffset++, "frontend-id");
1612 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->domid));
1613 flexarray_set(back, boffset++, "online");
1614 flexarray_set(back, boffset++, "1");
1615 flexarray_set(back, boffset++, "state");
1616 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1617 flexarray_set(back, boffset++, "domain");
1618 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
1619 flexarray_set(back, boffset++, "vnc");
1620 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vnc));
1621 flexarray_set(back, boffset++, "vnclisten");
1622 flexarray_set(back, boffset++, vfb->vnclisten);
1623 flexarray_set(back, boffset++, "vncdisplay");
1624 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncdisplay));
1625 flexarray_set(back, boffset++, "vncunused");
1626 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncunused));
1627 flexarray_set(back, boffset++, "sdl");
1628 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->sdl));
1629 flexarray_set(back, boffset++, "opengl");
1630 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->opengl));
1631 if (vfb->xauthority) {
1632 flexarray_set(back, boffset++, "xauthority");
1633 flexarray_set(back, boffset++, vfb->xauthority);
1635 if (vfb->display) {
1636 flexarray_set(back, boffset++, "display");
1637 flexarray_set(back, boffset++, vfb->display);
1640 flexarray_set(front, foffset++, "backend-id");
1641 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vfb->backend_domid));
1642 flexarray_set(front, foffset++, "state");
1643 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1645 libxl_device_generic_add(ctx, &device,
1646 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1647 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1648 flexarray_free(front);
1649 flexarray_free(back);
1651 return 0;
1654 int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
1656 return ERROR_NI;
1659 int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
1661 return ERROR_NI;
1664 /******************************************************************************/
1666 int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
1667 unsigned int bus, unsigned int dev,
1668 unsigned int func, unsigned int vdevfn)
1670 pcidev->domain = domain;
1671 pcidev->bus = bus;
1672 pcidev->dev = dev;
1673 pcidev->func = func;
1674 pcidev->vdevfn = vdevfn;
1675 return 0;
1678 static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
1680 flexarray_t *front;
1681 flexarray_t *back;
1682 unsigned int boffset = 0;
1683 unsigned int foffset = 0;
1684 libxl_device device;
1685 int i;
1687 front = flexarray_make(16, 1);
1688 if (!front)
1689 return ERROR_NOMEM;
1690 back = flexarray_make(16, 1);
1691 if (!back)
1692 return ERROR_NOMEM;
1694 XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend");
1696 /* add pci device */
1697 device.backend_devid = 0;
1698 device.backend_domid = 0;
1699 device.backend_kind = DEVICE_PCI;
1700 device.devid = 0;
1701 device.domid = domid;
1702 device.kind = DEVICE_PCI;
1704 flexarray_set(back, boffset++, "frontend-id");
1705 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
1706 flexarray_set(back, boffset++, "online");
1707 flexarray_set(back, boffset++, "1");
1708 flexarray_set(back, boffset++, "state");
1709 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1710 flexarray_set(back, boffset++, "domain");
1711 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
1712 for (i = 0; i < num; i++) {
1713 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
1714 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1715 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
1716 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1717 if (pcidev->vdevfn) {
1718 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
1719 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
1721 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
1722 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
1723 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
1724 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1726 flexarray_set(back, boffset++, "num_devs");
1727 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
1729 flexarray_set(front, foffset++, "backend-id");
1730 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
1731 flexarray_set(front, foffset++, "state");
1732 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1734 libxl_device_generic_add(ctx, &device,
1735 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1736 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1738 flexarray_free(back);
1739 flexarray_free(front);
1740 return 0;
1743 static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1745 flexarray_t *back;
1746 char *num_devs, *be_path;
1747 int num = 0;
1748 unsigned int boffset = 0;
1749 xs_transaction_t t;
1751 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
1752 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
1753 if (!num_devs)
1754 return libxl_create_pci_backend(ctx, domid, pcidev, 1);
1756 if (!is_hvm(ctx, domid)) {
1757 if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
1758 return -1;
1761 back = flexarray_make(16, 1);
1762 if (!back)
1763 return ERROR_NOMEM;
1765 XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore");
1766 num = atoi(num_devs);
1767 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
1768 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1769 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
1770 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1771 if (pcidev->vdevfn) {
1772 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
1773 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
1775 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
1776 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
1777 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
1778 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1779 flexarray_set(back, boffset++, "num_devs");
1780 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
1781 flexarray_set(back, boffset++, "state");
1782 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
1784 retry_transaction:
1785 t = xs_transaction_start(ctx->xsh);
1786 libxl_xs_writev(ctx, t, be_path,
1787 libxl_xs_kvs_of_flexarray(ctx, back, boffset));
1788 if (!xs_transaction_end(ctx->xsh, t, 0))
1789 if (errno == EAGAIN)
1790 goto retry_transaction;
1792 flexarray_free(back);
1793 return 0;
1796 static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1798 char *be_path, *num_devs_path, *num_devs, *xsdev, *tmp, *tmppath;
1799 int num, i, j;
1800 xs_transaction_t t;
1801 unsigned int domain = 0, bus = 0, dev = 0, func = 0;
1803 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
1804 num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
1805 num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
1806 if (!num_devs)
1807 return -1;
1808 num = atoi(num_devs);
1810 if (!is_hvm(ctx, domid)) {
1811 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
1812 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready", be_path);
1813 return -1;
1817 for (i = 0; i < num; i++) {
1818 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
1819 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
1820 if (domain == pcidev->domain && bus == pcidev->bus &&
1821 pcidev->dev == dev && pcidev->func == func) {
1822 break;
1825 if (i == num) {
1826 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore");
1827 return -1;
1830 retry_transaction:
1831 t = xs_transaction_start(ctx->xsh);
1832 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "5", strlen("5"));
1833 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
1834 if (!xs_transaction_end(ctx->xsh, t, 0))
1835 if (errno == EAGAIN)
1836 goto retry_transaction;
1838 if (!is_hvm(ctx, domid)) {
1839 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
1840 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready", be_path);
1841 return -1;
1845 retry_transaction2:
1846 t = xs_transaction_start(ctx->xsh);
1847 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i));
1848 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/key-%d", be_path, i));
1849 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
1850 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdev-%d", be_path, i));
1851 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
1852 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
1853 libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
1854 for (j = i + 1; j < num; j++) {
1855 tmppath = libxl_sprintf(ctx, "%s/state-%d", be_path, j);
1856 tmp = libxl_xs_read(ctx, t, tmppath);
1857 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, j - 1), tmp, strlen(tmp));
1858 xs_rm(ctx->xsh, t, tmppath);
1859 tmppath = libxl_sprintf(ctx, "%s/dev-%d", be_path, j);
1860 tmp = libxl_xs_read(ctx, t, tmppath);
1861 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/dev-%d", be_path, j - 1), tmp, strlen(tmp));
1862 xs_rm(ctx->xsh, t, tmppath);
1863 tmppath = libxl_sprintf(ctx, "%s/key-%d", be_path, j);
1864 tmp = libxl_xs_read(ctx, t, tmppath);
1865 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/key-%d", be_path, j - 1), tmp, strlen(tmp));
1866 xs_rm(ctx->xsh, t, tmppath);
1867 tmppath = libxl_sprintf(ctx, "%s/vdev-%d", be_path, j);
1868 tmp = libxl_xs_read(ctx, t, tmppath);
1869 if (tmp) {
1870 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdev-%d", be_path, j - 1), tmp, strlen(tmp));
1871 xs_rm(ctx->xsh, t, tmppath);
1873 tmppath = libxl_sprintf(ctx, "%s/opts-%d", be_path, j);
1874 tmp = libxl_xs_read(ctx, t, tmppath);
1875 if (tmp) {
1876 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/opts-%d", be_path, j - 1), tmp, strlen(tmp));
1877 xs_rm(ctx->xsh, t, tmppath);
1879 tmppath = libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, j);
1880 tmp = libxl_xs_read(ctx, t, tmppath);
1881 if (tmp) {
1882 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, j - 1), tmp, strlen(tmp));
1883 xs_rm(ctx->xsh, t, tmppath);
1886 if (!xs_transaction_end(ctx->xsh, t, 0))
1887 if (errno == EAGAIN)
1888 goto retry_transaction2;
1890 if (num == 1) {
1891 char *fe_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/frontend", be_path));
1892 libxl_device_destroy(ctx, be_path, 1);
1893 xs_rm(ctx->xsh, XBT_NULL, be_path);
1894 xs_rm(ctx->xsh, XBT_NULL, fe_path);
1895 return 0;
1898 return 0;
1901 int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1903 char *path;
1904 char *state, *vdevfn;
1905 int rc, hvm;
1906 int stubdomid = 0;
1908 /* TODO: check if the device can be assigned */
1910 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
1912 stubdomid = libxl_get_stubdom_id(ctx, domid);
1913 if (stubdomid != 0) {
1914 libxl_device_pci pcidev_s = *pcidev;
1915 libxl_device_pci_add(ctx, stubdomid, &pcidev_s);
1918 hvm = is_hvm(ctx, domid);
1919 if (hvm) {
1920 if (libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL) < 0) {
1921 return -1;
1923 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
1924 state = libxl_xs_read(ctx, XBT_NULL, path);
1925 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
1926 if (pcidev->vdevfn)
1927 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
1928 pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
1929 else
1930 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
1931 pcidev->bus, pcidev->dev, pcidev->func);
1932 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid);
1933 xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
1934 if (libxl_wait_for_device_model(ctx, domid, "pci-inserted", NULL, NULL) < 0)
1935 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
1936 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
1937 vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
1938 sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
1939 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
1940 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
1941 } else {
1942 char *sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain,
1943 pcidev->bus, pcidev->dev, pcidev->func);
1944 FILE *f = fopen(sysfs_path, "r");
1945 unsigned int start = 0, end = 0, flags = 0, size = 0;
1946 int irq = 0;
1947 int i;
1949 if (f == NULL) {
1950 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
1951 return -1;
1953 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
1954 fscanf(f, "0x%x 0x%x 0x%x", &start, &end, &flags);
1955 size = end - start + 1;
1956 if (start) {
1957 if (flags & PCI_BAR_IO) {
1958 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
1959 if (rc < 0)
1960 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_ioport_permission error 0x%x/0x%x", start, size);
1961 } else {
1962 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
1963 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
1964 if (rc < 0)
1965 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_iomem_permission error 0x%x/0x%x", start, size);
1969 fclose(f);
1970 sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/irq", pcidev->domain,
1971 pcidev->bus, pcidev->dev, pcidev->func);
1972 f = fopen(sysfs_path, "r");
1973 if (f == NULL) {
1974 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
1975 goto out;
1977 fscanf(f, "%u", &irq);
1978 if (irq) {
1979 rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
1980 if (rc < 0) {
1981 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_physdev_map_pirq irq=%d", irq);
1983 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
1984 if (rc < 0) {
1985 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_irq_permission irq=%d", irq);
1988 fclose(f);
1990 out:
1991 if (!libxl_is_stubdom(ctx, domid)) {
1992 rc = xc_assign_device(ctx->xch, domid, pcidev->value);
1993 if (rc < 0)
1994 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_assign_device failed");
1997 libxl_device_pci_add_xenstore(ctx, domid, pcidev);
1998 return 0;
2001 int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
2003 char *path;
2004 char *state;
2005 int hvm, rc;
2006 int stubdomid = 0;
2008 /* TODO: check if the device can be detached */
2009 libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
2011 hvm = is_hvm(ctx, domid);
2012 if (hvm) {
2013 if (libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL) < 0) {
2014 return -1;
2016 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
2017 state = libxl_xs_read(ctx, XBT_NULL, path);
2018 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
2019 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
2020 pcidev->bus, pcidev->dev, pcidev->func);
2021 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid);
2022 xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
2023 if (libxl_wait_for_device_model(ctx, domid, "pci-removed", NULL, NULL) < 0) {
2024 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
2025 return -1;
2027 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
2028 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
2029 } else {
2030 char *sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain,
2031 pcidev->bus, pcidev->dev, pcidev->func);
2032 FILE *f = fopen(sysfs_path, "r");
2033 unsigned int start = 0, end = 0, flags = 0, size = 0;
2034 int irq = 0;
2035 int i;
2037 if (f == NULL) {
2038 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
2039 goto skip1;
2041 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
2042 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
2043 size = end - start + 1;
2044 if (start) {
2045 if (flags & PCI_BAR_IO) {
2046 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
2047 if (rc < 0)
2048 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_ioport_permission error 0x%x/0x%x", start, size);
2049 } else {
2050 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
2051 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
2052 if (rc < 0)
2053 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_iomem_permission error 0x%x/0x%x", start, size);
2057 fclose(f);
2058 skip1:
2059 sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/irq", pcidev->domain,
2060 pcidev->bus, pcidev->dev, pcidev->func);
2061 f = fopen(sysfs_path, "r");
2062 if (f == NULL) {
2063 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
2064 goto out;
2066 fscanf(f, "%u", &irq);
2067 if (irq) {
2068 rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
2069 if (rc < 0) {
2070 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_physdev_map_pirq irq=%d", irq);
2072 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
2073 if (rc < 0) {
2074 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_irq_permission irq=%d", irq);
2077 fclose(f);
2079 out:
2080 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
2082 if (!libxl_is_stubdom(ctx, domid)) {
2083 rc = xc_deassign_device(ctx->xch, domid, pcidev->value);
2084 if (rc < 0)
2085 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_deassign_device failed");
2088 stubdomid = libxl_get_stubdom_id(ctx, domid);
2089 if (stubdomid != 0) {
2090 libxl_device_pci pcidev_s = *pcidev;
2091 libxl_device_pci_remove(ctx, stubdomid, &pcidev_s);
2094 return 0;
2097 libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
2099 char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
2100 int n, i;
2101 unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
2102 libxl_device_pci *pcidevs;
2104 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
2105 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
2106 if (!num_devs) {
2107 *num = 0;
2108 return NULL;
2110 n = atoi(num_devs);
2111 pcidevs = calloc(n, sizeof(libxl_device_pci));
2112 *num = n;
2114 for (i = 0; i < n; i++) {
2115 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
2116 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
2117 xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
2118 if (xsvdevfn)
2119 vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
2120 libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
2121 xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
2122 if (xsopts) {
2123 char *saveptr;
2124 char *p = strtok_r(xsopts, ",=", &saveptr);
2125 do {
2126 while (*p == ' ')
2127 p++;
2128 if (!strcmp(p, "msitranslate")) {
2129 p = strtok_r(NULL, ",=", &saveptr);
2130 pcidevs[i].msitranslate = atoi(p);
2131 } else if (!strcmp(p, "power_mgmt")) {
2132 p = strtok_r(NULL, ",=", &saveptr);
2133 pcidevs[i].power_mgmt = atoi(p);
2135 } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
2138 return pcidevs;
2141 int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
2143 libxl_device_pci *pcidevs;
2144 int num, i;
2146 pcidevs = libxl_device_pci_list(ctx, domid, &num);
2147 for (i = 0; i < num; i++) {
2148 if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
2149 return -1;
2151 free(pcidevs);
2152 return 0;
2155 int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t target_memkb)
2157 int rc = 0;
2158 uint32_t videoram;
2159 char *videoram_s = NULL;
2160 char *dompath = libxl_xs_get_dompath(ctx, domid);
2162 videoram_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/videoram", dompath));
2163 if (!videoram_s)
2164 return -1;
2165 videoram = atoi(videoram_s);
2167 libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", dompath), "%lu", target_memkb);
2168 rc = xc_domain_setmaxmem(ctx->xch, domid, target_memkb + LIBXL_MAXMEM_CONSTANT);
2169 if (rc != 0)
2170 return rc;
2171 rc = xc_domain_memory_set_pod_target(ctx->xch, domid, (target_memkb - videoram) / 4, NULL, NULL, NULL);
2172 return rc;