keir@20462: /* keir@20462: * Copyright (C) 2009 Citrix Ltd. keir@20462: * Author Vincent Hanquez keir@20462: * Author Stefano Stabellini keir@20462: * keir@20462: * This program is free software; you can redistribute it and/or modify keir@20462: * it under the terms of the GNU Lesser General Public License as published keir@20462: * by the Free Software Foundation; version 2.1 only. with the special keir@20462: * exception on linking described in file LICENSE. keir@20462: * keir@20462: * This program is distributed in the hope that it will be useful, keir@20462: * but WITHOUT ANY WARRANTY; without even the implied warranty of keir@20462: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the keir@20462: * GNU Lesser General Public License for more details. keir@20462: */ keir@20462: keir@20462: #include keir@20462: #include keir@20462: #include keir@20462: #include keir@20462: #include keir@20462: #include keir@20462: #include keir@20462: #include keir@20468: #include /* for write, unlink and close */ keir@20462: #include "libxl.h" keir@20462: #include "libxl_utils.h" keir@20462: #include "libxl_internal.h" keir@20462: #include "flexarray.h" keir@20462: keir@20462: int libxl_ctx_init(struct libxl_ctx *ctx) keir@20462: { keir@20462: memset(ctx, 0, sizeof(struct libxl_ctx)); keir@20462: ctx->alloc_maxsize = 256; keir@20462: ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *)); keir@20462: if (!ctx->alloc_ptrs) keir@20462: return ERROR_NOMEM; keir@20462: keir@20462: ctx->xch = xc_interface_open(); keir@20462: ctx->xsh = xs_daemon_open(); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_ctx_free(struct libxl_ctx *ctx) keir@20462: { keir@20462: libxl_free_all(ctx); keir@20462: free(ctx->alloc_ptrs); keir@20462: ctx->alloc_ptrs = NULL; keir@20462: xc_interface_close(ctx->xch); keir@20462: xs_daemon_close(ctx->xsh); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data) keir@20462: { keir@20462: ctx->log_callback = log_callback; keir@20462: ctx->log_userdata = log_data; keir@20462: return 0; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20462: keir@20462: int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, keir@20462: uint32_t *domid) keir@20462: { keir@20462: int flags, ret, i; keir@20468: char *uuid_string; keir@20462: char *rw_paths[] = { "device" }; keir@20462: char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers", keir@20462: "control", "attr", "data", "messages" }; keir@20462: char *dom_path, *vm_path, *vss_path; keir@20462: struct xs_permissions roperm[2]; keir@20462: struct xs_permissions rwperm[1]; keir@20462: xs_transaction_t t; keir@20468: xen_domain_handle_t handle; keir@20462: keir@20468: uuid_string = libxl_uuid_to_string(ctx, info->uuid); keir@20462: if (!uuid_string) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "missing uuid"); keir@20462: return ERROR_FAIL; keir@20462: } keir@20462: keir@20462: flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0; keir@20462: flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0; keir@20462: *domid = 0; keir@20462: keir@20468: /* XXX handle has to be initialised here. keir@20468: * info->uuid != xen_domain_handle_t keir@20468: * See: keir@20468: * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt keir@20468: * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm keir@20468: * keir@20468: * A DCE 1.1 compatible source representation of UUIDs. keir@20468: * keir@20468: * struct uuid { keir@20468: * uint32_t time_low; keir@20468: * uint16_t time_mid; keir@20468: * uint16_t time_hi_and_version; keir@20468: * uint8_t clock_seq_hi_and_reserved; keir@20468: * uint8_t clock_seq_low; keir@20468: * uint8_t node[_UUID_NODE_LEN]; keir@20468: * }; keir@20468: */ keir@20468: keir@20468: ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid); keir@20462: if (ret < 0) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "domain creation fail: %d", ret); keir@20462: return ERROR_FAIL; keir@20462: } keir@20462: keir@20462: dom_path = libxl_xs_get_dompath(ctx, *domid); keir@20462: vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string); keir@20462: vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string); keir@20462: if (!dom_path || !vm_path || !vss_path) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths"); keir@20462: return ERROR_FAIL; keir@20462: } keir@20462: keir@20462: roperm[0].id = 0; keir@20462: roperm[0].perms = XS_PERM_NONE; keir@20462: roperm[1].id = *domid; keir@20462: roperm[1].perms = XS_PERM_READ; keir@20462: rwperm[0].id = *domid; keir@20462: rwperm[0].perms = XS_PERM_NONE; keir@20462: keir@20462: retry_transaction: keir@20462: t = xs_transaction_start(ctx->xsh); keir@20462: xs_rm(ctx->xsh, t, dom_path); keir@20462: xs_mkdir(ctx->xsh, t, dom_path); keir@20462: xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm)); keir@20462: keir@20462: xs_rm(ctx->xsh, t, vm_path); keir@20462: xs_mkdir(ctx->xsh, t, vm_path); keir@20462: xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm)); keir@20462: keir@20462: xs_rm(ctx->xsh, t, vss_path); keir@20462: xs_mkdir(ctx->xsh, t, vss_path); keir@20462: xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm)); keir@20462: keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path)); keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path)); keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name)); keir@20462: keir@20462: for (i = 0; i < ARRAY_SIZE(rw_paths); i++) { keir@20462: char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]); keir@20462: xs_mkdir(ctx->xsh, t, path); keir@20462: xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm)); keir@20462: libxl_free(ctx, path); keir@20462: } keir@20462: for (i = 0; i < ARRAY_SIZE(ro_paths); i++) { keir@20462: char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]); keir@20462: xs_mkdir(ctx->xsh, t, path); keir@20462: xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm)); keir@20462: libxl_free(ctx, path); keir@20462: } keir@20462: keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name)); keir@20482: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/image/ostype", vm_path), "hvm", strlen("hvm")); keir@20462: keir@20462: libxl_xs_writev(ctx, t, dom_path, info->xsdata); keir@20462: libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata); keir@20462: keir@20462: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1); keir@20462: keir@20462: if (!xs_transaction_end(ctx->xsh, t, 0)) keir@20462: if (errno == EAGAIN) keir@20462: goto retry_transaction; keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid) keir@20462: { keir@20462: libxl_domain_build_state state; keir@20462: char **vments = NULL, **localents = NULL; keir@20462: keir@20462: memset(&state, '\0', sizeof(state)); keir@20462: keir@20462: build_pre(ctx, domid, info, &state); keir@20462: if (info->hvm) { keir@20462: build_hvm(ctx, domid, info, &state); keir@20462: vments = libxl_calloc(ctx, 4, sizeof(char *)); keir@20462: vments[0] = libxl_sprintf(ctx, "rtc/timeoffset"); keir@20462: vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : ""); keir@20462: } else { keir@20462: build_pv(ctx, domid, info, &state); keir@20462: } keir@20462: build_post(ctx, domid, info, &state, vments, localents); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info, keir@20462: uint32_t domid, int fd) keir@20462: { keir@20462: libxl_domain_build_state state; keir@20462: char **vments = NULL, **localents = NULL; keir@20462: keir@20462: memset(&state, '\0', sizeof(state)); keir@20462: keir@20462: build_pre(ctx, domid, info, &state); keir@20462: restore_common(ctx, domid, info, &state, fd); keir@20462: if (info->hvm) { keir@20462: vments = libxl_calloc(ctx, 4, sizeof(char *)); keir@20462: vments[0] = libxl_sprintf(ctx, "rtc/timeoffset"); keir@20462: vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : ""); keir@20462: } else { keir@20462: localents = libxl_calloc(ctx, 4 * 2, sizeof(char *)); keir@20462: localents[0] = libxl_sprintf(ctx, "serial/0/limit"); keir@20462: localents[1] = libxl_sprintf(ctx, "%d", 65536); keir@20462: localents[2] = libxl_sprintf(ctx, "console/port"); keir@20462: localents[3] = libxl_sprintf(ctx, "%d", state.console_port); keir@20462: localents[4] = libxl_sprintf(ctx, "console/ring-ref"); keir@20462: localents[5] = libxl_sprintf(ctx, "%ld", state.console_mfn); keir@20462: } keir@20462: build_post(ctx, domid, info, &state, vments, localents); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain) keir@20462: { keir@20462: struct libxl_dominfo *ptr; keir@20462: int index, i, ret, first_domain; keir@20462: xc_domaininfo_t info[16]; keir@20462: int size = 16; keir@20462: keir@20462: first_domain = 1; keir@20462: index = 0; keir@20462: ptr = libxl_calloc(ctx, size, sizeof(struct libxl_dominfo)); keir@20462: if (!ptr) keir@20462: return NULL; keir@20462: redo: keir@20462: ret = xc_domain_getinfolist(ctx->xch, first_domain, 16, info); keir@20462: for (i = 0; i < ret; i++) { keir@20462: if (index == size) { keir@20462: struct libxl_dominfo *ptr2; keir@20462: keir@20462: ptr2 = libxl_calloc(ctx, size * 2, sizeof(struct libxl_dominfo)); keir@20462: if (!ptr2) { keir@20462: libxl_free(ctx, ptr); keir@20462: return NULL; keir@20462: } keir@20462: memcpy(ptr2, ptr, sizeof(struct libxl_dominfo) * size); keir@20462: libxl_free(ctx, ptr); keir@20462: ptr = ptr2; keir@20462: size *= 2; keir@20462: } keir@20462: memcpy(ptr[index].uuid, info[i].handle, 16 * sizeof(uint8_t)); keir@20462: ptr[index].domid = info[i].domain; keir@20462: first_domain = info[i].domain + 1; keir@20462: index++; keir@20462: } keir@20462: if (ret == 16) keir@20462: goto redo; keir@20462: *nb_domain = index; keir@20462: return ptr; keir@20462: } keir@20462: keir@20462: xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain) keir@20462: { keir@20462: int index, first_domain; keir@20462: xc_dominfo_t *info; keir@20462: int size = 1024; keir@20462: keir@20462: first_domain = 0; keir@20462: index = 0; keir@20462: info = (xc_dominfo_t *) libxl_calloc(ctx, size, sizeof(xc_dominfo_t)); keir@20462: if (!info) { keir@20462: *nb_domain = 0; keir@20462: return NULL; keir@20462: } keir@20462: *nb_domain = xc_domain_getinfo(ctx->xch, first_domain, 1024, info); keir@20462: return info; keir@20462: } keir@20462: keir@20462: int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info, keir@20462: uint32_t domid, int fd) keir@20462: { keir@20462: int hvm = 1; keir@20462: int live = 0; keir@20462: int debug = 0; keir@20462: char savesig[] = "XenSavedDomain\n"; keir@20462: keir@20462: write(fd, savesig, strlen(savesig)); keir@20462: keir@20462: core_suspend(ctx, domid, fd, hvm, live, debug); keir@20462: keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: xc_domain_pause(ctx->xch, domid); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: xc_domain_unpause(ctx->xch, domid); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: static char *req_table[] = { keir@20462: [0] = "poweroff", keir@20462: [1] = "reboot", keir@20462: [2] = "suspend", keir@20462: [3] = "crash", keir@20462: [4] = "halt", keir@20462: }; keir@20462: keir@20462: int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req) keir@20462: { keir@20462: char *shutdown_path; keir@20462: char *dom_path; keir@20462: keir@20462: if (req > ARRAY_SIZE(req_table)) keir@20462: return ERROR_INVAL; keir@20462: keir@20462: dom_path = libxl_xs_get_dompath(ctx, domid); keir@20462: shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path); keir@20462: keir@20462: xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req])); keir@20462: if (/* hvm */ 0) { keir@20462: unsigned long acpi_s_state = 0; keir@20462: unsigned long pvdriver = 0; keir@20462: xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state); keir@20462: xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver); keir@20462: if (!pvdriver && acpi_s_state != 0) keir@20462: xc_domain_shutdown(ctx->xch, domid, req); keir@20462: } keir@20462: return 0; keir@20462: } keir@20462: keir@20462: static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: char *pid; keir@20462: int ret; keir@20462: keir@20462: pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid)); keir@20462: if (!pid) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find device model's pid\n"); keir@20462: return -1; keir@20462: } keir@20462: xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid)); keir@20462: keir@20462: ret = kill(atoi(pid), SIGHUP); keir@20462: if (ret < 0 && errno == ESRCH) { keir@20462: XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited\n"); keir@20462: ret = 0; keir@20462: } else if (ret == 0) { keir@20462: XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled\n"); keir@20462: ret = 0; keir@20462: } else { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "kill %d returned %d errno=%d\n", atoi(pid), ret, errno); keir@20462: } keir@20462: return ret; keir@20462: } keir@20462: keir@20462: int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force) keir@20462: { keir@20462: char *dom_path, vm_path[41]; keir@20468: xen_uuid_t *uuid; keir@20462: keir@20462: dom_path = libxl_xs_get_dompath(ctx, domid); keir@20462: if (!dom_path) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "dompath doesn't exist for %d\n", domid); keir@20462: return -1; keir@20462: } keir@20462: if (libxl_domid_to_uuid(ctx, &uuid, domid) < 0) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid); keir@20462: return -1; keir@20462: } keir@20482: if (libxl_device_pci_shutdown(ctx, domid) < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d\n", domid); keir@20462: xs_write(ctx->xsh, XBT_NULL, keir@20462: libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), keir@20462: "shutdown", strlen("shutdown")); keir@20462: if (xc_domain_pause(ctx->xch, domid) < 0) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid); keir@20462: return -1; keir@20462: } keir@20462: if (xc_domain_destroy(ctx->xch, domid) < 0) { keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid); keir@20462: return -1; keir@20462: } keir@20462: if (libxl_devices_destroy(ctx, domid, force) < 0) keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d\n", domid); keir@20462: if (libxl_destroy_device_model(ctx, domid) < 0) keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d\n", domid); keir@20462: if (!xs_rm(ctx->xsh, XBT_NULL, dom_path)) keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", dom_path); keir@20468: snprintf(vm_path, sizeof(vm_path), "/vm/%s", libxl_uuid_to_string(ctx, uuid)); keir@20462: if (!xs_rm(ctx->xsh, XBT_NULL, vm_path)) keir@20462: XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", vm_path); keir@20462: return 0; keir@20462: } keir@20462: keir@20462: static char ** libxl_build_device_model_args(struct libxl_ctx *ctx, keir@20462: libxl_device_model_info *info, keir@20462: libxl_device_nic *vifs, keir@20462: int num_vifs) keir@20462: { keir@20462: int num = 0, i; keir@20462: flexarray_t *dm_args; keir@20462: dm_args = flexarray_make(16, 1); keir@20462: if (!dm_args) keir@20462: return NULL; keir@20462: keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "qemu-dm")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-d")); keir@20462: keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid)); keir@20462: keir@20462: if (info->dom_name) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-domain-name")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->dom_name)); keir@20462: } keir@20462: if (info->videoram) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-videoram")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram)); keir@20462: } keir@20462: if (info->stdvga) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-std-vga")); keir@20462: } keir@20462: if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vnc")); keir@20462: if (info->vncdisplay) { keir@20462: if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay)); keir@20462: } else { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay)); keir@20462: } keir@20462: } else if (info->vnclisten) { keir@20462: if (strchr(info->vnclisten, ':') != NULL) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->vnclisten)); keir@20462: } else { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten)); keir@20462: } keir@20462: } else { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:0")); keir@20462: } keir@20462: if (info->vncunused) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vncunused")); keir@20462: } keir@20462: } keir@20462: if (info->sdl || info->opengl) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-sdl")); keir@20462: if (info->opengl) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-disable-opengl")); keir@20462: } keir@20462: } keir@20462: if (info->keymap) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-k")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->keymap)); keir@20462: } keir@20462: if (info->nographic && (!info->sdl && !info->vnc)) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-nographic")); keir@20462: } keir@20462: if (info->serial) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-serial")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->serial)); keir@20462: } keir@20462: if (info->boot) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-boot")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->boot)); keir@20462: } keir@20462: if (info->usb) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usb")); keir@20462: if (info->usbdevice) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usbdevice")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->usbdevice)); keir@20462: } keir@20462: } keir@20462: if (info->apic) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-acpi")); keir@20462: } keir@20462: if (info->extra) { keir@20462: int i = 0; keir@20462: while (info->extra[i] != NULL) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->extra[i])); keir@20462: } keir@20462: } keir@20462: for (i = 0; i < num_vifs; i++) { keir@20462: if (vifs[i].nictype == NICTYPE_IOEMU) { keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s", keir@20462: vifs[i].devid, vifs[i].smac, vifs[i].model)); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s", keir@20462: vifs[i].devid, vifs[i].ifname, vifs[i].bridge)); keir@20462: } keir@20462: } keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-M")); keir@20462: flexarray_set(dm_args, num++, libxl_sprintf(ctx, "xenfv")); keir@20462: flexarray_set(dm_args, num++, NULL); keir@20462: keir@20462: return (char **) flexarray_contents(dm_args); keir@20462: } keir@20462: keir@20462: int libxl_create_device_model(struct libxl_ctx *ctx, keir@20462: libxl_device_model_info *info, keir@20462: libxl_device_nic *vifs, int num_vifs) keir@20462: { keir@20462: char *dom_path, *path, *logfile, *logfile_new; keir@20462: char *kvs[3]; keir@20462: struct stat stat_buf; keir@20462: int logfile_w, null, pid; keir@20462: int i; keir@20462: char **args; keir@20462: keir@20462: args = libxl_build_device_model_args(ctx, info, vifs, num_vifs); keir@20462: if (!args) keir@20462: return ERROR_FAIL; keir@20462: keir@20462: dom_path = libxl_xs_get_dompath(ctx, info->domid); keir@20462: keir@20462: path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid); keir@20462: xs_mkdir(ctx->xsh, XBT_NULL, path); keir@20462: keir@20462: logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name); keir@20462: if (stat(logfile, &stat_buf) == 0) { keir@20462: /* file exists, rotate */ keir@20462: logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.10", info->dom_name); keir@20462: unlink(logfile); keir@20462: for (i = 9; i > 0; i--) { keir@20462: logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i); keir@20462: logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i + 1); keir@20462: rename(logfile, logfile_new); keir@20462: } keir@20462: logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name); keir@20462: logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.1", info->dom_name); keir@20462: rename(logfile, logfile_new); keir@20462: } keir@20462: logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name); keir@20467: logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644); keir@20462: null = open("/dev/null", O_RDONLY); keir@20462: pid = libxl_exec(ctx, null, logfile_w, logfile_w, info->device_model, args); keir@20462: close(null); keir@20462: close(logfile_w); keir@20462: keir@20462: kvs[0] = libxl_sprintf(ctx, "image/device-model-pid"); keir@20462: kvs[1] = libxl_sprintf(ctx, "%d", pid); keir@20462: kvs[2] = NULL; keir@20462: libxl_xs_writev(ctx, XBT_NULL, dom_path, kvs); keir@20462: keir@20462: return 0; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20462: int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) keir@20462: { keir@20462: flexarray_t *front; keir@20462: flexarray_t *back; keir@20462: char *backend_type; keir@20462: unsigned int boffset = 0; keir@20462: unsigned int foffset = 0; keir@20462: int devid; keir@20462: libxl_device device; keir@20462: keir@20462: front = flexarray_make(16, 1); keir@20462: if (!front) keir@20462: return ERROR_NOMEM; keir@20462: back = flexarray_make(16, 1); keir@20462: if (!back) /* leaks front if error */ keir@20462: return ERROR_NOMEM; keir@20462: keir@20462: backend_type = device_disk_backend_type_of_phystype(disk->phystype); keir@20462: devid = device_disk_dev_number(disk->virtpath); keir@20462: keir@20462: device.backend_devid = devid; keir@20462: device.backend_domid = disk->backend_domid; keir@20462: device.devid = devid; keir@20462: device.domid = disk->domid; keir@20462: device.kind = DEVICE_VBD; keir@20462: keir@20462: switch (disk->phystype) { keir@20462: case PHYSTYPE_FILE: keir@20462: return ERROR_NI; /* FIXME */ keir@20462: break; keir@20462: case PHYSTYPE_PHY: { keir@20462: int major, minor; keir@20462: keir@20462: device_disk_major_minor(disk->virtpath, &major, &minor); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "physical-device")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor)); keir@20462: keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "params")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->physpath)); keir@20462: keir@20462: device.backend_kind = DEVICE_VBD; keir@20462: break; keir@20462: } keir@20462: case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD: keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "params")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s", keir@20462: device_disk_string_of_phystype(disk->phystype), disk->physpath)); keir@20462: keir@20462: device.backend_kind = DEVICE_TAP; keir@20462: break; keir@20462: } keir@20462: keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "online")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "1")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "removable")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->virtpath)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "type")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", backend_type)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "mode")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", (disk->readwrite) ? "w" : "r")); keir@20462: keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "state")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "virtual-device")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "device-type")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%s", (disk->is_cdrom) ? "cdrom" : "disk")); keir@20462: keir@20462: if (0 /* protocol != native*/) { keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */ keir@20462: } keir@20462: keir@20462: libxl_device_generic_add(ctx, &device, keir@20462: libxl_xs_kvs_of_flexarray(ctx, back, boffset), keir@20462: libxl_xs_kvs_of_flexarray(ctx, front, foffset)); keir@20462: /* leaks both flexarray here */ keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_disk_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20462: int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) keir@20462: { keir@20462: flexarray_t *front; keir@20462: flexarray_t *back; keir@20462: unsigned int boffset = 0; keir@20462: unsigned int foffset = 0; keir@20462: libxl_device device; keir@20462: keir@20462: front = flexarray_make(16, 1); keir@20462: if (!front) keir@20462: return ERROR_NOMEM; keir@20462: back = flexarray_make(16, 1); keir@20462: if (!back) keir@20462: return ERROR_NOMEM; keir@20462: keir@20462: device.backend_devid = nic->devid; keir@20462: device.backend_domid = nic->backend_domid; keir@20462: device.backend_kind = DEVICE_VIF; keir@20462: device.devid = nic->devid; keir@20462: device.domid = nic->domid; keir@20462: device.kind = DEVICE_VIF; keir@20462: keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "online")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "1")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "script")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->script)); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "mac")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x", keir@20462: nic->mac[0], nic->mac[1], nic->mac[2], keir@20462: nic->mac[3], nic->mac[4], nic->mac[5])); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "handle")); keir@20462: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid)); keir@20462: keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "state")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "handle")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid)); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "mac")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x", keir@20462: nic->mac[0], nic->mac[1], nic->mac[2], keir@20462: nic->mac[3], nic->mac[4], nic->mac[5])); keir@20462: if (0 /* protocol != native*/) { keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol")); keir@20462: flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */ keir@20462: } keir@20462: keir@20462: libxl_device_generic_add(ctx, &device, keir@20462: libxl_xs_kvs_of_flexarray(ctx, back, boffset), keir@20462: libxl_xs_kvs_of_flexarray(ctx, front, foffset)); keir@20462: keir@20462: /* FIXME: wait for plug */ keir@20462: return 0; keir@20462: } keir@20462: keir@20462: int libxl_device_nic_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_nic_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20462: int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20462: int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20462: { keir@20462: return ERROR_NI; keir@20462: } keir@20462: keir@20462: /******************************************************************************/ keir@20482: keir@20482: int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain, keir@20482: unsigned int bus, unsigned int dev, keir@20482: unsigned int func, unsigned int vdevfn) keir@20482: { keir@20482: pcidev->domain = domain; keir@20482: pcidev->bus = bus; keir@20482: pcidev->dev = dev; keir@20482: pcidev->func = func; keir@20482: pcidev->vdevfn = vdevfn; keir@20482: return 0; keir@20482: } keir@20482: keir@20482: static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num) keir@20482: { keir@20482: flexarray_t *front; keir@20482: flexarray_t *back; keir@20482: unsigned int boffset = 0; keir@20482: unsigned int foffset = 0; keir@20482: libxl_device device; keir@20482: int i; keir@20482: keir@20482: front = flexarray_make(16, 1); keir@20482: if (!front) keir@20482: return ERROR_NOMEM; keir@20482: back = flexarray_make(16, 1); keir@20482: if (!back) keir@20482: return ERROR_NOMEM; keir@20482: keir@20482: XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend\n"); keir@20482: keir@20482: /* add pci device */ keir@20482: device.backend_devid = 0; keir@20482: device.backend_domid = 0; keir@20482: device.backend_kind = DEVICE_PCI; keir@20482: device.devid = 0; keir@20482: device.domid = domid; keir@20482: device.kind = DEVICE_PCI; keir@20482: keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "online")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "1")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "domain")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", libxl_domid_to_name(ctx, domid))); keir@20482: for (i = 0; i < num; i++) { keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func)); keir@20482: if (pcidev->vdevfn) { keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn)); keir@20482: } keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1)); keir@20482: } keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num)); keir@20482: keir@20482: flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id")); keir@20482: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0)); keir@20482: flexarray_set(front, foffset++, libxl_sprintf(ctx, "state")); keir@20482: flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1)); keir@20482: keir@20482: libxl_device_generic_add(ctx, &device, keir@20482: libxl_xs_kvs_of_flexarray(ctx, back, boffset), keir@20482: libxl_xs_kvs_of_flexarray(ctx, front, foffset)); keir@20482: keir@20482: flexarray_free(back); keir@20482: flexarray_free(front); keir@20482: return 0; keir@20482: } keir@20482: keir@20482: static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) keir@20462: { keir@20482: flexarray_t *back; keir@20482: char *num_devs, *be_path; keir@20482: int num = 0; keir@20482: unsigned int boffset = 0; keir@20482: xs_transaction_t t; keir@20482: keir@20482: be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid); keir@20482: num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path)); keir@20482: if (!num_devs) keir@20482: return libxl_create_pci_backend(ctx, domid, pcidev, 1); keir@20482: keir@20482: if (!is_hvm(ctx, domid)) { keir@20482: if (libxl_wait_for_backend(ctx, be_path, "4") < 0) keir@20482: return -1; keir@20482: } keir@20482: keir@20482: back = flexarray_make(16, 1); keir@20482: if (!back) keir@20482: return ERROR_NOMEM; keir@20482: keir@20482: XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore\n"); keir@20482: num = atoi(num_devs); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func)); keir@20482: if (pcidev->vdevfn) { keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn)); keir@20482: } keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "num_devs")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1)); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "state")); keir@20482: flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7)); keir@20482: keir@20482: retry_transaction: keir@20482: t = xs_transaction_start(ctx->xsh); keir@20482: libxl_xs_writev(ctx, t, be_path, keir@20482: libxl_xs_kvs_of_flexarray(ctx, back, boffset)); keir@20482: if (!xs_transaction_end(ctx->xsh, t, 0)) keir@20482: if (errno == EAGAIN) keir@20482: goto retry_transaction; keir@20482: keir@20482: flexarray_free(back); keir@20482: return 0; keir@20482: } keir@20482: keir@20482: static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) keir@20482: { keir@20482: char *be_path, *num_devs_path, *num_devs, *xsdev; keir@20482: int num, i; keir@20482: xs_transaction_t t; keir@20482: unsigned int domain = 0, bus = 0, dev = 0, func = 0; keir@20482: keir@20482: be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid); keir@20482: num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path); keir@20482: num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path); keir@20482: if (!num_devs) keir@20482: return -1; keir@20482: num = atoi(num_devs); keir@20482: if (num == 1) { keir@20482: libxl_device_destroy(ctx, be_path, 1); keir@20482: xs_rm(ctx->xsh, XBT_NULL, be_path); keir@20482: return 0; keir@20482: } keir@20482: keir@20482: if (!is_hvm(ctx, domid)) { keir@20482: if (libxl_wait_for_backend(ctx, be_path, "4") < 0) { keir@20482: XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready\n"); keir@20482: return -1; keir@20482: } keir@20482: } keir@20482: keir@20482: for (i = 0; i < num; i++) { keir@20482: xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i)); keir@20482: sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func); keir@20482: if (domain == pcidev->domain && bus == pcidev->bus && keir@20482: pcidev->dev == dev && pcidev->func == func) { keir@20482: break; keir@20482: } keir@20482: } keir@20482: if (i == num) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore\n"); keir@20482: return -1; keir@20482: } keir@20482: keir@20482: retry_transaction: keir@20482: t = xs_transaction_start(ctx->xsh); keir@20482: libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1); keir@20482: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "6", strlen("6")); keir@20482: xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7")); keir@20482: if (!xs_transaction_end(ctx->xsh, t, 0)) keir@20482: if (errno == EAGAIN) keir@20482: goto retry_transaction; keir@20482: return 0; keir@20462: } keir@20462: keir@20482: int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) keir@20462: { keir@20482: char path[50]; keir@20482: char *state, *vdevfn; keir@20482: int rc, hvm; keir@20482: keir@20482: /* TODO: check if the device can be assigned */ keir@20482: keir@20482: libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); keir@20482: keir@20482: hvm = is_hvm(ctx, domid); keir@20482: if (hvm) { keir@20482: if (libxl_wait_for_device_model(ctx, domid, "running") < 0) { keir@20482: return -1; keir@20482: } keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid); keir@20482: state = libxl_xs_read(ctx, XBT_NULL, path); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid); keir@20482: if (pcidev->vdevfn) keir@20482: libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn); keir@20482: else keir@20482: libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid); keir@20482: xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins")); keir@20482: if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n"); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid); keir@20482: vdevfn = libxl_xs_read(ctx, XBT_NULL, path); keir@20482: sscanf(vdevfn + 2, "%x", &pcidev->vdevfn); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid); keir@20482: xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state)); keir@20482: } else { keir@20482: char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: FILE *f = fopen(sysfs_path, "r"); keir@20482: unsigned int start = 0, end = 0, flags = 0, size = 0; keir@20482: int irq = 0; keir@20482: int i; keir@20482: keir@20482: if (f == NULL) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path); keir@20482: return -1; keir@20482: } keir@20482: for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) { keir@20482: fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags); keir@20482: size = end - start + 1; keir@20482: if (start) { keir@20482: if (flags & PCI_BAR_IO) { keir@20482: rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1); keir@20482: if (rc < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc); keir@20482: } else { keir@20482: rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT, keir@20482: (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1); keir@20482: if (rc < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc); keir@20482: } keir@20482: } keir@20482: } keir@20482: fclose(f); keir@20482: sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: f = fopen(sysfs_path, "r"); keir@20482: if (f == NULL) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path); keir@20482: goto out; keir@20482: } keir@20482: fscanf(f, "%u", &irq); keir@20482: if (irq) { keir@20482: rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq); keir@20482: if (rc < 0) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc); keir@20482: } keir@20482: rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1); keir@20482: if (rc < 0) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc); keir@20482: } keir@20482: } keir@20482: fclose(f); keir@20482: } keir@20482: out: keir@20482: if ((rc = xc_assign_device(ctx->xch, domid, pcidev->value)) < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_assign_device error %d\n", rc); keir@20482: keir@20482: libxl_device_pci_add_xenstore(ctx, domid, pcidev); keir@20482: return 0; keir@20462: } keir@20462: keir@20482: int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev) keir@20462: { keir@20482: char path[50]; keir@20482: char *state; keir@20482: int hvm, rc; keir@20482: keir@20482: /* TODO: check if the device can be detached */ keir@20482: keir@20482: hvm = is_hvm(ctx, domid); keir@20482: if (hvm) { keir@20482: if (libxl_wait_for_device_model(ctx, domid, "running") < 0) { keir@20482: return -1; keir@20482: } keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid); keir@20482: state = libxl_xs_read(ctx, XBT_NULL, path); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/parameter", domid); keir@20482: libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/command", domid); keir@20482: xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem")); keir@20482: if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time\n"); keir@20482: return -1; keir@20482: } keir@20482: snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", domid); keir@20482: xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state)); keir@20482: } else { keir@20482: char *sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/resource", pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: FILE *f = fopen(sysfs_path, "r"); keir@20482: unsigned int start = 0, end = 0, flags = 0, size = 0; keir@20482: int irq = 0; keir@20482: int i; keir@20482: keir@20482: if (f == NULL) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path); keir@20482: goto skip1; keir@20482: } keir@20482: for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) { keir@20482: fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags); keir@20482: size = end - start + 1; keir@20482: if (start) { keir@20482: if (flags & PCI_BAR_IO) { keir@20482: rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0); keir@20482: if (rc < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_ioport_permission error 0x%x/0x%x: %d\n", start, size, rc); keir@20482: } else { keir@20482: rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT, keir@20482: (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0); keir@20482: if (rc < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_iomem_permission error 0x%x/0x%x: %d\n", start, size, rc); keir@20482: } keir@20482: } keir@20482: } keir@20482: fclose(f); keir@20482: skip1: keir@20482: sysfs_path = libxl_sprintf(ctx, "SYSFS_PCI_DEV/"PCI_BDF"/irq", pcidev->domain, keir@20482: pcidev->bus, pcidev->dev, pcidev->func); keir@20482: f = fopen(sysfs_path, "r"); keir@20482: if (f == NULL) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Couldn't open %s\n", sysfs_path); keir@20482: goto out; keir@20482: } keir@20482: fscanf(f, "%u", &irq); keir@20482: if (irq) { keir@20482: rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq); keir@20482: if (rc < 0) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_physdev_map_pirq irq=%d: %d\n", irq, rc); keir@20482: } keir@20482: rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0); keir@20482: if (rc < 0) { keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_domain_irq_permission irq=%d: %d\n", irq, rc); keir@20482: } keir@20482: } keir@20482: fclose(f); keir@20482: } keir@20482: out: keir@20482: libxl_device_pci_remove_xenstore(ctx, domid, pcidev); keir@20482: keir@20482: libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func); keir@20482: keir@20482: if ((rc = xc_deassign_device(ctx->xch, domid, pcidev->value)) < 0) keir@20482: XL_LOG(ctx, XL_LOG_ERROR, "Error: xc_deassign_device error %d\n", rc); keir@20482: return 0; keir@20462: } keir@20482: keir@20482: libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num) keir@20482: { keir@20482: char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts; keir@20482: int n, i; keir@20482: unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0; keir@20482: libxl_device_pci *pcidevs; keir@20482: keir@20482: be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", xs_get_domain_path(ctx->xsh, 0), domid); keir@20482: num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path)); keir@20482: if (!num_devs) { keir@20482: *num = 0; keir@20482: return NULL; keir@20482: } keir@20482: n = atoi(num_devs); keir@20482: pcidevs = (libxl_device_pci *) libxl_calloc(ctx, n, sizeof(libxl_device_pci)); keir@20482: *num = n; keir@20482: keir@20482: for (i = 0; i < n; i++) { keir@20482: xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i)); keir@20482: sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func); keir@20482: xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i)); keir@20482: if (xsvdevfn) keir@20482: vdevfn = strtol(xsvdevfn, (char **) NULL, 16); keir@20482: libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn); keir@20482: xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i)); keir@20482: if (xsopts) { keir@20482: char *saveptr; keir@20482: char *p = strtok_r(xsopts, ",=", &saveptr); keir@20482: do { keir@20482: while (*p == ' ') keir@20482: p++; keir@20482: if (!strcmp(p, "msitranslate")) { keir@20482: p = strtok_r(NULL, ",=", &saveptr); keir@20482: pcidevs[i].msitranslate = atoi(p); keir@20482: } else if (!strcmp(p, "power_mgmt")) { keir@20482: p = strtok_r(NULL, ",=", &saveptr); keir@20482: pcidevs[i].power_mgmt = atoi(p); keir@20482: } keir@20482: } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL); keir@20482: } keir@20482: } keir@20482: return pcidevs; keir@20482: } keir@20482: keir@20482: int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid) keir@20482: { keir@20482: libxl_device_pci *pcidevs; keir@20482: int num, i; keir@20482: keir@20482: pcidevs = libxl_device_pci_list(ctx, domid, &num); keir@20482: for (i = 0; i < num; i++) { keir@20482: if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0) keir@20482: return -1; keir@20482: } keir@20482: return 0; keir@20482: } keir@20482: