debuggers.hg

view tools/libxl/libxl.c @ 20509:014579af0350

libxenlight: implement support for pv guests

This patch makes pv guest work correctly with libxenlight. It also
implements support for vfb and vkbd, starting qemu in xenpv mode. Both
xenconsole and qemu are supported as console backends.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Nov 23 06:54:03 2009 +0000 (2009-11-23)
parents 8a1d2e35edfa
children b72f27350703
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 <stdint.h>
27 #include <inttypes.h>
28 #include "libxl.h"
29 #include "libxl_utils.h"
30 #include "libxl_internal.h"
31 #include "flexarray.h"
33 int libxl_ctx_init(struct libxl_ctx *ctx)
34 {
35 memset(ctx, 0, sizeof(struct libxl_ctx));
36 ctx->alloc_maxsize = 256;
37 ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
38 if (!ctx->alloc_ptrs)
39 return ERROR_NOMEM;
41 ctx->xch = xc_interface_open();
42 ctx->xsh = xs_daemon_open();
43 return 0;
44 }
46 int libxl_ctx_free(struct libxl_ctx *ctx)
47 {
48 libxl_free_all(ctx);
49 free(ctx->alloc_ptrs);
50 ctx->alloc_ptrs = NULL;
51 xc_interface_close(ctx->xch);
52 xs_daemon_close(ctx->xsh);
53 return 0;
54 }
56 int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data)
57 {
58 ctx->log_callback = log_callback;
59 ctx->log_userdata = log_data;
60 return 0;
61 }
63 /******************************************************************************/
65 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
66 uint32_t *domid)
67 {
68 int flags, ret, i;
69 char *uuid_string;
70 char *rw_paths[] = { "device" };
71 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
72 "control", "attr", "data", "messages" };
73 char *dom_path, *vm_path, *vss_path;
74 struct xs_permissions roperm[2];
75 struct xs_permissions rwperm[1];
76 xs_transaction_t t;
77 xen_domain_handle_t handle;
79 uuid_string = libxl_uuid_to_string(ctx, info->uuid);
80 if (!uuid_string) {
81 XL_LOG(ctx, XL_LOG_ERROR, "missing uuid");
82 return ERROR_FAIL;
83 }
85 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
86 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
87 *domid = 0;
89 /* XXX handle has to be initialised here.
90 * info->uuid != xen_domain_handle_t
91 * See:
92 * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
93 * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
94 *
95 * A DCE 1.1 compatible source representation of UUIDs.
96 *
97 * struct uuid {
98 * uint32_t time_low;
99 * uint16_t time_mid;
100 * uint16_t time_hi_and_version;
101 * uint8_t clock_seq_hi_and_reserved;
102 * uint8_t clock_seq_low;
103 * uint8_t node[_UUID_NODE_LEN];
104 * };
105 */
107 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
108 if (ret < 0) {
109 XL_LOG(ctx, XL_LOG_ERROR, "domain creation fail: %d", ret);
110 return ERROR_FAIL;
111 }
113 dom_path = libxl_xs_get_dompath(ctx, *domid);
114 vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string);
115 vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string);
116 if (!dom_path || !vm_path || !vss_path) {
117 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths");
118 return ERROR_FAIL;
119 }
121 roperm[0].id = 0;
122 roperm[0].perms = XS_PERM_NONE;
123 roperm[1].id = *domid;
124 roperm[1].perms = XS_PERM_READ;
125 rwperm[0].id = *domid;
126 rwperm[0].perms = XS_PERM_NONE;
128 retry_transaction:
129 t = xs_transaction_start(ctx->xsh);
130 xs_rm(ctx->xsh, t, dom_path);
131 xs_mkdir(ctx->xsh, t, dom_path);
132 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
134 xs_rm(ctx->xsh, t, vm_path);
135 xs_mkdir(ctx->xsh, t, vm_path);
136 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
138 xs_rm(ctx->xsh, t, vss_path);
139 xs_mkdir(ctx->xsh, t, vss_path);
140 xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm));
142 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path));
143 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path));
144 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name));
146 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
147 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
148 xs_mkdir(ctx->xsh, t, path);
149 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
150 libxl_free(ctx, path);
151 }
152 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
153 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]);
154 xs_mkdir(ctx->xsh, t, path);
155 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
156 libxl_free(ctx, path);
157 }
159 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
160 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
162 libxl_xs_writev(ctx, t, dom_path, info->xsdata);
163 libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
165 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
167 if (!xs_transaction_end(ctx->xsh, t, 0))
168 if (errno == EAGAIN)
169 goto retry_transaction;
170 return 0;
171 }
173 libxl_domain_build_state *libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid)
174 {
175 libxl_domain_build_state *state = (libxl_domain_build_state *) libxl_calloc(ctx, 1, sizeof(libxl_domain_build_state));
176 char **vments = NULL, **localents = NULL;
178 build_pre(ctx, domid, info, state);
179 if (info->hvm) {
180 build_hvm(ctx, domid, info, state);
181 vments = libxl_calloc(ctx, 5, sizeof(char *));
182 vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
183 vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
184 vments[2] = libxl_sprintf(ctx, "image/ostype");
185 vments[3] = libxl_sprintf(ctx, "hvm");
186 } else {
187 build_pv(ctx, domid, info, state);
188 vments = libxl_calloc(ctx, 9, sizeof(char *));
189 vments[0] = libxl_sprintf(ctx, "image/ostype");
190 vments[1] = libxl_sprintf(ctx, "linux");
191 vments[2] = libxl_sprintf(ctx, "image/kernel");
192 vments[3] = libxl_sprintf(ctx, info->kernel);
193 vments[4] = libxl_sprintf(ctx, "image/ramdisk");
194 vments[5] = libxl_sprintf(ctx, info->u.pv.ramdisk);
195 vments[6] = libxl_sprintf(ctx, "image/cmdline");
196 vments[7] = libxl_sprintf(ctx, info->u.pv.cmdline);
197 }
198 build_post(ctx, domid, info, state, vments, localents);
199 return state;
200 }
202 int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
203 uint32_t domid, int fd)
204 {
205 libxl_domain_build_state state;
206 char **vments = NULL, **localents = NULL;
208 memset(&state, '\0', sizeof(state));
210 build_pre(ctx, domid, info, &state);
211 restore_common(ctx, domid, info, &state, fd);
212 if (info->hvm) {
213 vments = libxl_calloc(ctx, 4, sizeof(char *));
214 vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
215 vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
216 } else {
217 localents = libxl_calloc(ctx, 4 * 2, sizeof(char *));
218 localents[0] = libxl_sprintf(ctx, "serial/0/limit");
219 localents[1] = libxl_sprintf(ctx, "%d", 65536);
220 localents[2] = libxl_sprintf(ctx, "console/port");
221 localents[3] = libxl_sprintf(ctx, "%d", state.console_port);
222 localents[4] = libxl_sprintf(ctx, "console/ring-ref");
223 localents[5] = libxl_sprintf(ctx, "%ld", state.console_mfn);
224 }
225 build_post(ctx, domid, info, &state, vments, localents);
226 return 0;
227 }
229 struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain)
230 {
231 struct libxl_dominfo *ptr;
232 int index, i, ret, first_domain;
233 xc_domaininfo_t info[16];
234 int size = 16;
236 first_domain = 1;
237 index = 0;
238 ptr = libxl_calloc(ctx, size, sizeof(struct libxl_dominfo));
239 if (!ptr)
240 return NULL;
241 redo:
242 ret = xc_domain_getinfolist(ctx->xch, first_domain, 16, info);
243 for (i = 0; i < ret; i++) {
244 if (index == size) {
245 struct libxl_dominfo *ptr2;
247 ptr2 = libxl_calloc(ctx, size * 2, sizeof(struct libxl_dominfo));
248 if (!ptr2) {
249 libxl_free(ctx, ptr);
250 return NULL;
251 }
252 memcpy(ptr2, ptr, sizeof(struct libxl_dominfo) * size);
253 libxl_free(ctx, ptr);
254 ptr = ptr2;
255 size *= 2;
256 }
257 memcpy(ptr[index].uuid, info[i].handle, 16 * sizeof(uint8_t));
258 ptr[index].domid = info[i].domain;
259 first_domain = info[i].domain + 1;
260 index++;
261 }
262 if (ret == 16)
263 goto redo;
264 *nb_domain = index;
265 return ptr;
266 }
268 xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain)
269 {
270 int index, first_domain;
271 xc_dominfo_t *info;
272 int size = 1024;
274 first_domain = 0;
275 index = 0;
276 info = (xc_dominfo_t *) libxl_calloc(ctx, size, sizeof(xc_dominfo_t));
277 if (!info) {
278 *nb_domain = 0;
279 return NULL;
280 }
281 *nb_domain = xc_domain_getinfo(ctx->xch, first_domain, 1024, info);
282 return info;
283 }
285 int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
286 uint32_t domid, int fd)
287 {
288 int hvm = 1;
289 int live = 0;
290 int debug = 0;
291 char savesig[] = "XenSavedDomain\n";
293 write(fd, savesig, strlen(savesig));
295 core_suspend(ctx, domid, fd, hvm, live, debug);
297 return 0;
298 }
300 int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid)
301 {
302 xc_domain_pause(ctx->xch, domid);
303 return 0;
304 }
306 int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid)
307 {
308 xc_domain_unpause(ctx->xch, domid);
309 return 0;
310 }
312 static char *req_table[] = {
313 [0] = "poweroff",
314 [1] = "reboot",
315 [2] = "suspend",
316 [3] = "crash",
317 [4] = "halt",
318 };
320 int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
321 {
322 char *shutdown_path;
323 char *dom_path;
325 if (req > ARRAY_SIZE(req_table))
326 return ERROR_INVAL;
328 dom_path = libxl_xs_get_dompath(ctx, domid);
329 shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path);
331 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
332 if (/* hvm */ 0) {
333 unsigned long acpi_s_state = 0;
334 unsigned long pvdriver = 0;
335 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
336 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
337 if (!pvdriver && acpi_s_state != 0)
338 xc_domain_shutdown(ctx->xch, domid, req);
339 }
340 return 0;
341 }
343 static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
344 {
345 char *pid;
346 int ret;
348 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
349 if (!pid) {
350 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find device model's pid\n");
351 return -1;
352 }
353 xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid));
355 ret = kill(atoi(pid), SIGHUP);
356 if (ret < 0 && errno == ESRCH) {
357 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited\n");
358 ret = 0;
359 } else if (ret == 0) {
360 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled\n");
361 ret = 0;
362 } else {
363 XL_LOG(ctx, XL_LOG_ERROR, "kill %d returned %d errno=%d\n", atoi(pid), ret, errno);
364 }
365 return ret;
366 }
368 int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
369 {
370 char *dom_path, vm_path[41];
371 xen_uuid_t *uuid;
373 dom_path = libxl_xs_get_dompath(ctx, domid);
374 if (!dom_path) {
375 XL_LOG(ctx, XL_LOG_ERROR, "dompath doesn't exist for %d\n", domid);
376 return -1;
377 }
378 if (libxl_domid_to_uuid(ctx, &uuid, domid) < 0) {
379 XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
380 return -1;
381 }
382 if (libxl_device_pci_shutdown(ctx, domid) < 0)
383 XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid);
384 xs_write(ctx->xsh, XBT_NULL,
385 libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
386 "shutdown", strlen("shutdown"));
387 if (xc_domain_pause(ctx->xch, domid) < 0) {
388 XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
389 return -1;
390 }
391 if (xc_domain_destroy(ctx->xch, domid) < 0) {
392 XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
393 return -1;
394 }
395 if (libxl_devices_destroy(ctx, domid, force) < 0)
396 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d\n", domid);
397 if (libxl_destroy_device_model(ctx, domid) < 0)
398 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d\n", domid);
399 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
400 XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", dom_path);
401 snprintf(vm_path, sizeof(vm_path), "/vm/%s", libxl_uuid_to_string(ctx, uuid));
402 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
403 XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", vm_path);
404 return 0;
405 }
407 static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
408 libxl_device_model_info *info,
409 libxl_device_nic *vifs,
410 int num_vifs)
411 {
412 int num = 0, i;
413 flexarray_t *dm_args;
414 dm_args = flexarray_make(16, 1);
415 if (!dm_args)
416 return NULL;
418 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "qemu-dm"));
419 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-d"));
421 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid));
423 if (info->dom_name) {
424 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-domain-name"));
425 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->dom_name));
426 }
427 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
428 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vnc"));
429 if (info->vncdisplay) {
430 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
431 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay));
432 } else {
433 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay));
434 }
435 } else if (info->vnclisten) {
436 if (strchr(info->vnclisten, ':') != NULL) {
437 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->vnclisten));
438 } else {
439 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten));
440 }
441 } else {
442 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:0"));
443 }
444 if (info->vncunused) {
445 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vncunused"));
446 }
447 }
448 if (info->sdl || info->opengl) {
449 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-sdl"));
450 if (info->opengl) {
451 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-disable-opengl"));
452 }
453 }
454 if (info->keymap) {
455 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-k"));
456 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->keymap));
457 }
458 if (info->nographic && (!info->sdl && !info->vnc)) {
459 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-nographic"));
460 }
461 if (info->serial) {
462 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-serial"));
463 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->serial));
464 }
465 if (info->type == XENFV) {
466 if (info->videoram) {
467 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-videoram"));
468 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram));
469 }
470 if (info->stdvga) {
471 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-std-vga"));
472 }
474 if (info->boot) {
475 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-boot"));
476 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->boot));
477 }
478 if (info->usb) {
479 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usb"));
480 if (info->usbdevice) {
481 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usbdevice"));
482 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->usbdevice));
483 }
484 }
485 if (info->apic) {
486 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-acpi"));
487 }
488 for (i = 0; i < num_vifs; i++) {
489 if (vifs[i].nictype == NICTYPE_IOEMU) {
490 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
491 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s",
492 vifs[i].devid, vifs[i].smac, vifs[i].model));
493 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
494 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s",
495 vifs[i].devid, vifs[i].ifname, vifs[i].bridge));
496 }
497 }
498 }
499 for (i = 0; info->extra && info->extra[i] != NULL; i++)
500 flexarray_set(dm_args, num++, info->extra[i]);
501 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-M"));
502 if (info->type == XENPV)
503 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "xenpv"));
504 else
505 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "xenfv"));
506 flexarray_set(dm_args, num++, NULL);
508 return (char **) flexarray_contents(dm_args);
509 }
511 int libxl_create_device_model(struct libxl_ctx *ctx,
512 libxl_device_model_info *info,
513 libxl_device_nic *vifs, int num_vifs)
514 {
515 char *dom_path, *path, *logfile, *logfile_new;
516 char *kvs[3];
517 struct stat stat_buf;
518 int logfile_w, null, pid;
519 int i;
520 char **args;
522 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
523 if (!args)
524 return ERROR_FAIL;
526 dom_path = libxl_xs_get_dompath(ctx, info->domid);
528 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
529 xs_mkdir(ctx->xsh, XBT_NULL, path);
531 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
532 if (stat(logfile, &stat_buf) == 0) {
533 /* file exists, rotate */
534 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.10", info->dom_name);
535 unlink(logfile);
536 for (i = 9; i > 0; i--) {
537 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i);
538 logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i + 1);
539 rename(logfile, logfile_new);
540 }
541 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
542 logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.1", info->dom_name);
543 rename(logfile, logfile_new);
544 }
545 logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
546 logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
547 null = open("/dev/null", O_RDONLY);
548 pid = libxl_exec(ctx, null, logfile_w, logfile_w, info->device_model, args);
549 close(null);
550 close(logfile_w);
552 kvs[0] = libxl_sprintf(ctx, "image/device-model-pid");
553 kvs[1] = libxl_sprintf(ctx, "%d", pid);
554 kvs[2] = NULL;
555 libxl_xs_writev(ctx, XBT_NULL, dom_path, kvs);
557 return 0;
558 }
560 /******************************************************************************/
561 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
562 {
563 flexarray_t *front;
564 flexarray_t *back;
565 char *backend_type;
566 unsigned int boffset = 0;
567 unsigned int foffset = 0;
568 int devid;
569 libxl_device device;
571 front = flexarray_make(16, 1);
572 if (!front)
573 return ERROR_NOMEM;
574 back = flexarray_make(16, 1);
575 if (!back) /* leaks front if error */
576 return ERROR_NOMEM;
578 backend_type = device_disk_backend_type_of_phystype(disk->phystype);
579 devid = device_disk_dev_number(disk->virtpath);
581 device.backend_devid = devid;
582 device.backend_domid = disk->backend_domid;
583 device.devid = devid;
584 device.domid = disk->domid;
585 device.kind = DEVICE_VBD;
587 switch (disk->phystype) {
588 case PHYSTYPE_FILE:
589 return ERROR_NI; /* FIXME */
590 break;
591 case PHYSTYPE_PHY: {
592 int major, minor;
594 device_physdisk_major_minor(disk->physpath, &major, &minor);
595 flexarray_set(back, boffset++, libxl_sprintf(ctx, "physical-device"));
596 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
598 flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
599 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->physpath));
601 device.backend_kind = DEVICE_VBD;
602 break;
603 }
604 case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD:
605 flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
606 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s",
607 device_disk_string_of_phystype(disk->phystype), disk->physpath));
609 device.backend_kind = DEVICE_TAP;
610 break;
611 }
613 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
614 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid));
615 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
616 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
617 flexarray_set(back, boffset++, libxl_sprintf(ctx, "removable"));
618 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0));
619 flexarray_set(back, boffset++, libxl_sprintf(ctx, "bootable"));
620 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
621 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
622 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
623 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev"));
624 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->virtpath));
625 flexarray_set(back, boffset++, libxl_sprintf(ctx, "type"));
626 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", backend_type));
627 flexarray_set(back, boffset++, libxl_sprintf(ctx, "mode"));
628 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", (disk->readwrite) ? "w" : "r"));
630 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
631 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid));
632 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
633 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
634 flexarray_set(front, foffset++, libxl_sprintf(ctx, "virtual-device"));
635 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid));
636 flexarray_set(front, foffset++, libxl_sprintf(ctx, "device-type"));
637 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%s", (disk->is_cdrom) ? "cdrom" : "disk"));
639 if (0 /* protocol != native*/) {
640 flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
641 flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
642 }
644 libxl_device_generic_add(ctx, &device,
645 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
646 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
647 /* leaks both flexarray here */
648 return 0;
649 }
651 int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
652 {
653 return ERROR_NI;
654 }
656 int libxl_device_disk_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
657 {
658 return ERROR_NI;
659 }
661 /******************************************************************************/
662 int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
663 {
664 flexarray_t *front;
665 flexarray_t *back;
666 unsigned int boffset = 0;
667 unsigned int foffset = 0;
668 libxl_device device;
670 front = flexarray_make(16, 1);
671 if (!front)
672 return ERROR_NOMEM;
673 back = flexarray_make(16, 1);
674 if (!back)
675 return ERROR_NOMEM;
677 device.backend_devid = nic->devid;
678 device.backend_domid = nic->backend_domid;
679 device.backend_kind = DEVICE_VIF;
680 device.devid = nic->devid;
681 device.domid = nic->domid;
682 device.kind = DEVICE_VIF;
684 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
685 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid));
686 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
687 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
688 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
689 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
690 flexarray_set(back, boffset++, libxl_sprintf(ctx, "script"));
691 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->script));
692 flexarray_set(back, boffset++, libxl_sprintf(ctx, "mac"));
693 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
694 nic->mac[0], nic->mac[1], nic->mac[2],
695 nic->mac[3], nic->mac[4], nic->mac[5]));
696 flexarray_set(back, boffset++, libxl_sprintf(ctx, "handle"));
697 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
699 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
700 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid));
701 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
702 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
703 flexarray_set(front, foffset++, libxl_sprintf(ctx, "handle"));
704 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid));
705 flexarray_set(front, foffset++, libxl_sprintf(ctx, "mac"));
706 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
707 nic->mac[0], nic->mac[1], nic->mac[2],
708 nic->mac[3], nic->mac[4], nic->mac[5]));
709 if (0 /* protocol != native*/) {
710 flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
711 flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
712 }
714 libxl_device_generic_add(ctx, &device,
715 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
716 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
718 /* FIXME: wait for plug */
719 return 0;
720 }
722 int libxl_device_nic_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
723 {
724 return ERROR_NI;
725 }
727 int libxl_device_nic_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
728 {
729 return ERROR_NI;
730 }
732 /******************************************************************************/
733 int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
734 {
735 flexarray_t *front;
736 flexarray_t *back;
737 unsigned int boffset = 0;
738 unsigned int foffset = 0;
739 libxl_device device;
741 if (console->build_state) {
742 xs_transaction_t t;
743 char **ents = (char **) libxl_calloc(ctx, 9, sizeof(char *));
744 ents[0] = libxl_sprintf(ctx, "console/port");
745 ents[1] = libxl_sprintf(ctx, "%"PRIu32, console->build_state->console_port);
746 ents[2] = libxl_sprintf(ctx, "console/ring-ref");
747 ents[3] = libxl_sprintf(ctx, "%lu", console->build_state->console_mfn);
748 ents[4] = libxl_sprintf(ctx, "console/limit");
749 ents[5] = libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT);
750 ents[6] = libxl_sprintf(ctx, "console/type");
751 if (console->constype == CONSTYPE_XENCONSOLED)
752 ents[7] = "xenconsoled";
753 else
754 ents[7] = "ioemu";
755 retry_transaction:
756 t = xs_transaction_start(ctx->xsh);
757 libxl_xs_writev(ctx, t, xs_get_domain_path(ctx->xsh, console->domid), ents);
758 if (!xs_transaction_end(ctx->xsh, t, 0))
759 if (errno == EAGAIN)
760 goto retry_transaction;
761 }
763 front = flexarray_make(16, 1);
764 if (!front)
765 return ERROR_NOMEM;
766 back = flexarray_make(16, 1);
767 if (!back)
768 return ERROR_NOMEM;
770 device.backend_devid = console->devid;
771 device.backend_domid = console->backend_domid;
772 device.backend_kind = DEVICE_CONSOLE;
773 device.devid = console->devid;
774 device.domid = console->domid;
775 device.kind = DEVICE_CONSOLE;
777 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
778 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", console->domid));
779 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
780 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
781 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
782 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
783 flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
784 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
785 flexarray_set(back, boffset++, libxl_sprintf(ctx, "protocol"));
786 flexarray_set(back, boffset++, libxl_sprintf(ctx, LIBXL_XENCONSOLE_PROTOCOL));
788 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
789 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", console->backend_domid));
790 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
791 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
792 flexarray_set(front, foffset++, libxl_sprintf(ctx, "limit"));
793 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT));
794 flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
795 flexarray_set(front, foffset++, libxl_sprintf(ctx, LIBXL_XENCONSOLE_PROTOCOL));
796 flexarray_set(front, foffset++, libxl_sprintf(ctx, "type"));
797 if (console->constype == CONSTYPE_XENCONSOLED)
798 flexarray_set(front, foffset++, libxl_sprintf(ctx, "xenconsoled"));
799 else
800 flexarray_set(front, foffset++, libxl_sprintf(ctx, "ioemu"));
802 libxl_device_generic_add(ctx, &device,
803 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
804 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
807 return 0;
808 }
810 /******************************************************************************/
811 int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
812 {
813 flexarray_t *front;
814 flexarray_t *back;
815 unsigned int boffset = 0;
816 unsigned int foffset = 0;
817 libxl_device device;
819 front = flexarray_make(16, 1);
820 if (!front)
821 return ERROR_NOMEM;
822 back = flexarray_make(16, 1);
823 if (!back)
824 return ERROR_NOMEM;
826 device.backend_devid = vkb->devid;
827 device.backend_domid = vkb->backend_domid;
828 device.backend_kind = DEVICE_VKBD;
829 device.devid = vkb->devid;
830 device.domid = vkb->domid;
831 device.kind = DEVICE_VKBD;
833 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
834 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vkb->domid));
835 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
836 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
837 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
838 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
839 flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
840 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
842 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
843 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vkb->backend_domid));
844 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
845 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
847 libxl_device_generic_add(ctx, &device,
848 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
849 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
851 return 0;
852 }
854 int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
855 {
856 return ERROR_NI;
857 }
859 int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
860 {
861 return ERROR_NI;
862 }
864 /******************************************************************************/
865 static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
866 libxl_device_vfb *vfb,
867 int num_console,
868 libxl_device_console *console,
869 libxl_device_model_info *info) {
870 int i = 0, j = 0, num = 0;
871 memset(info, 0x00, sizeof(libxl_device_model_info));
873 info->vnc = vfb->vnc;
874 if (vfb->vnclisten)
875 info->vnclisten = libxl_sprintf(ctx, "%s", vfb->vnclisten);
876 info->vncdisplay = vfb->vncdisplay;
877 info->vncunused = vfb->vncunused;
878 if (vfb->keymap)
879 info->keymap = libxl_sprintf(ctx, "%s", vfb->keymap);
880 info->sdl = vfb->sdl;
881 info->opengl = vfb->opengl;
882 for (i = 0; i < num_console; i++) {
883 if (console->constype == CONSTYPE_IOEMU)
884 num++;
885 }
886 if (num > 0) {
887 info->serial = "pty";
888 num--;
889 }
890 if (num > 0) {
891 info->extra = (char **) libxl_calloc(ctx, num * 2 + 1, sizeof(char *));
892 for (j = 0; j < num * 2; j = j + 2) {
893 info->extra[j] = "-serial";
894 info->extra[j + 1] = "pty";
895 }
896 info->extra[j] = NULL;
897 }
898 info->domid = vfb->domid;
899 info->dom_name = libxl_domid_to_name(ctx, vfb->domid);
900 info->device_model = "/usr/lib/xen/bin/qemu-dm";
901 info->type = XENPV;
902 return 0;
903 }
905 int libxl_create_xenpv_qemu(struct libxl_ctx *ctx, libxl_device_vfb *vfb,
906 int num_console, libxl_device_console *console)
907 {
908 libxl_device_model_info info;
910 libxl_build_xenpv_qemu_args(ctx, vfb, num_console, console, &info);
911 libxl_create_device_model(ctx, &info, NULL, 0);
912 return 0;
913 }
915 int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
916 {
917 flexarray_t *front;
918 flexarray_t *back;
919 unsigned int boffset = 0;
920 unsigned int foffset = 0;
921 libxl_device device;
923 front = flexarray_make(16, 1);
924 if (!front)
925 return ERROR_NOMEM;
926 back = flexarray_make(16, 1);
927 if (!back)
928 return ERROR_NOMEM;
930 device.backend_devid = vfb->devid;
931 device.backend_domid = vfb->backend_domid;
932 device.backend_kind = DEVICE_VFB;
933 device.devid = vfb->devid;
934 device.domid = vfb->domid;
935 device.kind = DEVICE_VFB;
937 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
938 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->domid));
939 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
940 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
941 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
942 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
943 flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
944 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
945 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vnc"));
946 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vnc));
947 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vnclisten"));
948 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", vfb->vnclisten));
949 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vncdisplay"));
950 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncdisplay));
951 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vncunused"));
952 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncunused));
953 flexarray_set(back, boffset++, libxl_sprintf(ctx, "sdl"));
954 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->sdl));
955 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opengl"));
956 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->opengl));
957 if (vfb->xauthority) {
958 flexarray_set(back, boffset++, libxl_sprintf(ctx, "xauthority"));
959 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", vfb->xauthority));
960 }
961 if (vfb->display) {
962 flexarray_set(back, boffset++, libxl_sprintf(ctx, "display"));
963 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", vfb->display));
964 }
966 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
967 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vfb->backend_domid));
968 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
969 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
971 libxl_device_generic_add(ctx, &device,
972 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
973 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
974 flexarray_free(front);
975 flexarray_free(back);
977 return 0;
978 }
980 int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
981 {
982 return ERROR_NI;
983 }
985 int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
986 {
987 return ERROR_NI;
988 }
990 /******************************************************************************/
992 int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
993 unsigned int bus, unsigned int dev,
994 unsigned int func, unsigned int vdevfn)
995 {
996 pcidev->domain = domain;
997 pcidev->bus = bus;
998 pcidev->dev = dev;
999 pcidev->func = func;
1000 pcidev->vdevfn = vdevfn;
1001 return 0;
1004 static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
1006 flexarray_t *front;
1007 flexarray_t *back;
1008 unsigned int boffset = 0;
1009 unsigned int foffset = 0;
1010 libxl_device device;
1011 int i;
1013 front = flexarray_make(16, 1);
1014 if (!front)
1015 return ERROR_NOMEM;
1016 back = flexarray_make(16, 1);
1017 if (!back)
1018 return ERROR_NOMEM;
1020 XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n");
1022 /* add pci device */
1023 device.backend_devid = 0;
1024 device.backend_domid = 0;
1025 device.backend_kind = DEVICE_PCI;
1026 device.devid = 0;
1027 device.domid = domid;
1028 device.kind = DEVICE_PCI;
1030 flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
1031 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
1032 flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
1033 flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
1034 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
1035 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1036 flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain"));
1037 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid)));
1038 for (i = 0; i < num; i++) {
1039 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
1040 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1041 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
1042 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1043 if (pcidev->vdevfn) {
1044 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
1045 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
1047 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
1048 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
1049 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
1050 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1052 flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
1053 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
1055 flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
1056 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
1057 flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
1058 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
1060 libxl_device_generic_add(ctx, &device,
1061 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
1062 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
1064 flexarray_free(back);
1065 flexarray_free(front);
1066 return 0;
1069 static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1071 flexarray_t *back;
1072 char *num_devs, *be_path;
1073 int num = 0;
1074 unsigned int boffset = 0;
1075 xs_transaction_t t;
1077 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
1078 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
1079 if (!num_devs)
1080 return libxl_create_pci_backend(ctx, domid, pcidev, 1);
1082 if (!is_hvm(ctx, domid)) {
1083 if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
1084 return -1;
1087 back = flexarray_make(16, 1);
1088 if (!back)
1089 return ERROR_NOMEM;
1091 XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n");
1092 num = atoi(num_devs);
1093 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
1094 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1095 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
1096 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
1097 if (pcidev->vdevfn) {
1098 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
1099 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
1101 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
1102 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
1103 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
1104 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
1105 flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs"));
1106 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
1107 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
1108 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
1110 retry_transaction:
1111 t = xs_transaction_start(ctx->xsh);
1112 libxl_xs_writev(ctx, t, be_path,
1113 libxl_xs_kvs_of_flexarray(ctx, back, boffset));
1114 if (!xs_transaction_end(ctx->xsh, t, 0))
1115 if (errno == EAGAIN)
1116 goto retry_transaction;
1118 flexarray_free(back);
1119 return 0;
1122 static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1124 char *be_path, *num_devs_path, *num_devs, *xsdev;
1125 int num, i;
1126 xs_transaction_t t;
1127 unsigned int domain = 0, bus = 0, dev = 0, func = 0;
1129 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
1130 num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
1131 num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
1132 if (!num_devs)
1133 return -1;
1134 num = atoi(num_devs);
1135 if (num == 1) {
1136 libxl_device_destroy(ctx, be_path, 1);
1137 xs_rm(ctx->xsh, XBT_NULL, be_path);
1138 return 0;
1141 if (!is_hvm(ctx, domid)) {
1142 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
1143 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n");
1144 return -1;
1148 for (i = 0; i < num; i++) {
1149 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
1150 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
1151 if (domain == pcidev->domain && bus == pcidev->bus &&
1152 pcidev->dev == dev && pcidev->func == func) {
1153 break;
1156 if (i == num) {
1157 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n");
1158 return -1;
1161 retry_transaction:
1162 t = xs_transaction_start(ctx->xsh);
1163 libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
1164 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", strlen("6"));
1165 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
1166 if (!xs_transaction_end(ctx->xsh, t, 0))
1167 if (errno == EAGAIN)
1168 goto retry_transaction;
1169 return 0;
1172 int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1174 char path[50];
1175 char *state, *vdevfn;
1176 int rc, hvm;
1178 /* TODO: check if the device can be assigned */
1180 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
1182 hvm = is_hvm(ctx, domid);
1183 if (hvm) {
1184 if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
1185 return -1;
1187 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
1188 state = libxl_xs_read(ctx, XBT_NULL, path);
1189 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
1190 if (pcidev->vdevfn)
1191 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
1192 pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
1193 else
1194 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
1195 pcidev->bus, pcidev->dev, pcidev->func);
1196 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
1197 xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
1198 if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
1199 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
1200 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
1201 vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
1202 sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
1203 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
1204 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
1205 } else {
1206 char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
1207 pcidev->bus, pcidev->dev, pcidev->func);
1208 FILE *f = fopen(sysfs_path, "r");
1209 unsigned int start = 0, end = 0, flags = 0, size = 0;
1210 int irq = 0;
1211 int i;
1213 if (f == NULL) {
1214 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
1215 return -1;
1217 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
1218 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
1219 size = end - start + 1;
1220 if (start) {
1221 if (flags & PCI_BAR_IO) {
1222 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
1223 if (rc < 0)
1224 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc);
1225 } else {
1226 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
1227 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
1228 if (rc < 0)
1229 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc);
1233 fclose(f);
1234 sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
1235 pcidev->bus, pcidev->dev, pcidev->func);
1236 f = fopen(sysfs_path, "r");
1237 if (f == NULL) {
1238 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
1239 goto out;
1241 fscanf(f, "%u", &irq);
1242 if (irq) {
1243 rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
1244 if (rc < 0) {
1245 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
1247 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
1248 if (rc < 0) {
1249 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
1252 fclose(f);
1254 out:
1255 if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0)
1256 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc);
1258 libxl_device_pci_add_xenstore(ctx, domid, pcidev);
1259 return 0;
1262 int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
1264 char path[50];
1265 char *state;
1266 int hvm, rc;
1268 /* TODO: check if the device can be detached */
1270 hvm = is_hvm(ctx, domid);
1271 if (hvm) {
1272 if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
1273 return -1;
1275 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
1276 state = libxl_xs_read(ctx, XBT_NULL, path);
1277 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid);
1278 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
1279 pcidev->bus, pcidev->dev, pcidev->func);
1280 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid);
1281 xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
1282 if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
1283 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n");
1284 return -1;
1286 snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid);
1287 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
1288 } else {
1289 char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain,
1290 pcidev->bus, pcidev->dev, pcidev->func);
1291 FILE *f = fopen(sysfs_path, "r");
1292 unsigned int start = 0, end = 0, flags = 0, size = 0;
1293 int irq = 0;
1294 int i;
1296 if (f == NULL) {
1297 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
1298 goto skip1;
1300 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
1301 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
1302 size = end - start + 1;
1303 if (start) {
1304 if (flags & PCI_BAR_IO) {
1305 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
1306 if (rc < 0)
1307 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc);
1308 } else {
1309 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
1310 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
1311 if (rc < 0)
1312 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc);
1316 fclose(f);
1317 skip1:
1318 sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain,
1319 pcidev->bus, pcidev->dev, pcidev->func);
1320 f = fopen(sysfs_path, "r");
1321 if (f == NULL) {
1322 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path);
1323 goto out;
1325 fscanf(f, "%u", &irq);
1326 if (irq) {
1327 rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
1328 if (rc < 0) {
1329 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc);
1331 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
1332 if (rc < 0) {
1333 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc);
1336 fclose(f);
1338 out:
1339 libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
1341 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
1343 if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0)
1344 XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc);
1345 return 0;
1348 libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
1350 char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
1351 int n, i;
1352 unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
1353 libxl_device_pci *pcidevs;
1355 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid);
1356 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
1357 if (!num_devs) {
1358 *num = 0;
1359 return NULL;
1361 n = atoi(num_devs);
1362 pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, sizeof(libxl_device_pci));
1363 *num = n;
1365 for (i = 0; i < n; i++) {
1366 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
1367 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
1368 xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
1369 if (xsvdevfn)
1370 vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
1371 libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
1372 xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
1373 if (xsopts) {
1374 char *saveptr;
1375 char *p = strtok_r(xsopts, ",=", &saveptr);
1376 do {
1377 while (*p == ' ')
1378 p++;
1379 if (!strcmp(p, "msitranslate")) {
1380 p = strtok_r(NULL, ",=", &saveptr);
1381 pcidevs[i].msitranslate = atoi(p);
1382 } else if (!strcmp(p, "power_mgmt")) {
1383 p = strtok_r(NULL, ",=", &saveptr);
1384 pcidevs[i].power_mgmt = atoi(p);
1386 } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
1389 return pcidevs;
1392 int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
1394 libxl_device_pci *pcidevs;
1395 int num, i;
1397 pcidevs = libxl_device_pci_list(ctx, domid, &num);
1398 for (i = 0; i < num; i++) {
1399 if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
1400 return -1;
1402 return 0;