aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 1 | #include <signal.h> |
Paolo Bonzini | 0d09e41 | 2013-02-05 17:06:20 +0100 | [diff] [blame] | 2 | #include "hw/xen/xen_backend.h" |
Paolo Bonzini | 47b43a1 | 2013-03-18 17:36:02 +0100 | [diff] [blame] | 3 | #include "xen_domainbuild.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 4 | #include "qemu/timer.h" |
| 5 | #include "qemu/log.h" |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 6 | |
| 7 | #include <xenguest.h> |
| 8 | |
| 9 | static int xenstore_domain_mkdir(char *path) |
| 10 | { |
| 11 | struct xs_permissions perms_ro[] = {{ |
| 12 | .id = 0, /* set owner: dom0 */ |
| 13 | },{ |
| 14 | .id = xen_domid, |
| 15 | .perms = XS_PERM_READ, |
| 16 | }}; |
| 17 | struct xs_permissions perms_rw[] = {{ |
| 18 | .id = 0, /* set owner: dom0 */ |
| 19 | },{ |
| 20 | .id = xen_domid, |
| 21 | .perms = XS_PERM_READ | XS_PERM_WRITE, |
| 22 | }}; |
| 23 | const char *writable[] = { "device", "control", "error", NULL }; |
| 24 | char subpath[256]; |
| 25 | int i; |
| 26 | |
| 27 | if (!xs_mkdir(xenstore, 0, path)) { |
| 28 | fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path); |
| 29 | return -1; |
| 30 | } |
| 31 | if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) { |
| 32 | fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); |
| 33 | return -1; |
| 34 | } |
| 35 | |
| 36 | for (i = 0; writable[i]; i++) { |
| 37 | snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]); |
| 38 | if (!xs_mkdir(xenstore, 0, subpath)) { |
| 39 | fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath); |
| 40 | return -1; |
| 41 | } |
| 42 | if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) { |
| 43 | fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__); |
| 44 | return -1; |
| 45 | } |
| 46 | } |
| 47 | return 0; |
| 48 | } |
| 49 | |
| 50 | int xenstore_domain_init1(const char *kernel, const char *ramdisk, |
| 51 | const char *cmdline) |
| 52 | { |
| 53 | char *dom, uuid_string[42], vm[256], path[256]; |
| 54 | int i; |
| 55 | |
| 56 | snprintf(uuid_string, sizeof(uuid_string), UUID_FMT, |
| 57 | qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], |
| 58 | qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], |
| 59 | qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], |
| 60 | qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); |
| 61 | dom = xs_get_domain_path(xenstore, xen_domid); |
| 62 | snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); |
| 63 | |
| 64 | xenstore_domain_mkdir(dom); |
| 65 | |
| 66 | xenstore_write_str(vm, "image/ostype", "linux"); |
| 67 | if (kernel) |
| 68 | xenstore_write_str(vm, "image/kernel", kernel); |
| 69 | if (ramdisk) |
| 70 | xenstore_write_str(vm, "image/ramdisk", ramdisk); |
| 71 | if (cmdline) |
| 72 | xenstore_write_str(vm, "image/cmdline", cmdline); |
| 73 | |
| 74 | /* name + id */ |
| 75 | xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name"); |
| 76 | xenstore_write_str(vm, "uuid", uuid_string); |
| 77 | xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name"); |
| 78 | xenstore_write_int(dom, "domid", xen_domid); |
| 79 | xenstore_write_str(dom, "vm", vm); |
| 80 | |
| 81 | /* memory */ |
| 82 | xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB |
| 83 | xenstore_write_int(vm, "memory", ram_size >> 20); // MB |
| 84 | xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB |
| 85 | |
| 86 | /* cpus */ |
| 87 | for (i = 0; i < smp_cpus; i++) { |
| 88 | snprintf(path, sizeof(path), "cpu/%d/availability",i); |
| 89 | xenstore_write_str(dom, path, "online"); |
| 90 | } |
| 91 | xenstore_write_int(vm, "vcpu_avail", smp_cpus); |
| 92 | xenstore_write_int(vm, "vcpus", smp_cpus); |
| 93 | |
| 94 | /* vnc password */ |
| 95 | xenstore_write_str(vm, "vncpassword", "" /* FIXME */); |
| 96 | |
| 97 | free(dom); |
| 98 | return 0; |
| 99 | } |
| 100 | |
| 101 | int xenstore_domain_init2(int xenstore_port, int xenstore_mfn, |
| 102 | int console_port, int console_mfn) |
| 103 | { |
| 104 | char *dom; |
| 105 | |
| 106 | dom = xs_get_domain_path(xenstore, xen_domid); |
| 107 | |
| 108 | /* signal new domain */ |
| 109 | xs_introduce_domain(xenstore, |
| 110 | xen_domid, |
| 111 | xenstore_mfn, |
| 112 | xenstore_port); |
| 113 | |
| 114 | /* xenstore */ |
| 115 | xenstore_write_int(dom, "store/ring-ref", xenstore_mfn); |
| 116 | xenstore_write_int(dom, "store/port", xenstore_port); |
| 117 | |
| 118 | /* console */ |
| 119 | xenstore_write_str(dom, "console/type", "ioemu"); |
| 120 | xenstore_write_int(dom, "console/limit", 128 * 1024); |
| 121 | xenstore_write_int(dom, "console/ring-ref", console_mfn); |
| 122 | xenstore_write_int(dom, "console/port", console_port); |
| 123 | xen_config_dev_console(0); |
| 124 | |
| 125 | free(dom); |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | /* ------------------------------------------------------------- */ |
| 130 | |
| 131 | static QEMUTimer *xen_poll; |
| 132 | |
| 133 | /* check domain state once per second */ |
| 134 | static void xen_domain_poll(void *opaque) |
| 135 | { |
| 136 | struct xc_dominfo info; |
| 137 | int rc; |
| 138 | |
| 139 | rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info); |
blueswir1 | fc1f79f | 2009-04-23 18:29:47 +0000 | [diff] [blame] | 140 | if ((rc != 1) || (info.domid != xen_domid)) { |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 141 | qemu_log("xen: domain %d is gone\n", xen_domid); |
| 142 | goto quit; |
| 143 | } |
| 144 | if (info.dying) { |
| 145 | qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid, |
| 146 | info.crashed ? "crashed" : "", |
| 147 | info.shutdown ? "shutdown" : ""); |
| 148 | goto quit; |
| 149 | } |
| 150 | |
Paolo Bonzini | 7bd427d | 2011-03-11 16:47:48 +0100 | [diff] [blame] | 151 | qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 152 | return; |
| 153 | |
| 154 | quit: |
| 155 | qemu_system_shutdown_request(); |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 156 | } |
| 157 | |
Juan Quintela | acdc3f0 | 2010-01-20 00:56:21 +0100 | [diff] [blame] | 158 | static int xen_domain_watcher(void) |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 159 | { |
| 160 | int qemu_running = 1; |
| 161 | int fd[2], i, n, rc; |
| 162 | char byte; |
| 163 | |
Juan Quintela | acdc3f0 | 2010-01-20 00:56:21 +0100 | [diff] [blame] | 164 | if (pipe(fd) != 0) { |
| 165 | qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno)); |
| 166 | return -1; |
| 167 | } |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 168 | if (fork() != 0) |
Juan Quintela | acdc3f0 | 2010-01-20 00:56:21 +0100 | [diff] [blame] | 169 | return 0; /* not child */ |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 170 | |
| 171 | /* close all file handles, except stdio/out/err, |
| 172 | * our watch pipe and the xen interface handle */ |
| 173 | n = getdtablesize(); |
| 174 | for (i = 3; i < n; i++) { |
| 175 | if (i == fd[0]) |
| 176 | continue; |
Anthony PERARD | d5b93dd | 2011-02-25 16:20:34 +0000 | [diff] [blame] | 177 | if (i == xc_fd(xen_xc)) { |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 178 | continue; |
Anthony PERARD | d5b93dd | 2011-02-25 16:20:34 +0000 | [diff] [blame] | 179 | } |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 180 | close(i); |
| 181 | } |
| 182 | |
| 183 | /* ignore term signals */ |
| 184 | signal(SIGINT, SIG_IGN); |
| 185 | signal(SIGTERM, SIG_IGN); |
| 186 | |
| 187 | /* wait for qemu exiting */ |
| 188 | while (qemu_running) { |
| 189 | rc = read(fd[0], &byte, 1); |
| 190 | switch (rc) { |
| 191 | case -1: |
blueswir1 | fc1f79f | 2009-04-23 18:29:47 +0000 | [diff] [blame] | 192 | if (errno == EINTR) |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 193 | continue; |
| 194 | qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno)); |
| 195 | qemu_running = 0; |
| 196 | break; |
| 197 | case 0: |
| 198 | /* EOF -> qemu exited */ |
| 199 | qemu_running = 0; |
| 200 | break; |
| 201 | default: |
| 202 | qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__); |
| 203 | break; |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /* cleanup */ |
| 208 | qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid); |
| 209 | xc_domain_destroy(xen_xc, xen_domid); |
| 210 | _exit(0); |
| 211 | } |
| 212 | |
| 213 | /* normal cleanup */ |
Anthony Liguori | 2869548 | 2010-03-21 14:13:02 -0500 | [diff] [blame] | 214 | static void xen_domain_cleanup(void) |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 215 | { |
| 216 | char *dom; |
| 217 | |
| 218 | dom = xs_get_domain_path(xenstore, xen_domid); |
| 219 | if (dom) { |
| 220 | xs_rm(xenstore, 0, dom); |
| 221 | free(dom); |
| 222 | } |
| 223 | xs_release_domain(xenstore, xen_domid); |
| 224 | } |
| 225 | |
| 226 | int xen_domain_build_pv(const char *kernel, const char *ramdisk, |
| 227 | const char *cmdline) |
| 228 | { |
| 229 | uint32_t ssidref = 0; |
| 230 | uint32_t flags = 0; |
| 231 | xen_domain_handle_t uuid; |
| 232 | unsigned int xenstore_port = 0, console_port = 0; |
| 233 | unsigned long xenstore_mfn = 0, console_mfn = 0; |
| 234 | int rc; |
| 235 | |
| 236 | memcpy(uuid, qemu_uuid, sizeof(uuid)); |
| 237 | rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); |
| 238 | if (rc < 0) { |
| 239 | fprintf(stderr, "xen: xc_domain_create() failed\n"); |
| 240 | goto err; |
| 241 | } |
| 242 | qemu_log("xen: created domain %d\n", xen_domid); |
Anthony Liguori | 2869548 | 2010-03-21 14:13:02 -0500 | [diff] [blame] | 243 | atexit(xen_domain_cleanup); |
Juan Quintela | acdc3f0 | 2010-01-20 00:56:21 +0100 | [diff] [blame] | 244 | if (xen_domain_watcher() == -1) { |
| 245 | goto err; |
| 246 | } |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 247 | |
| 248 | xenstore_domain_init1(kernel, ramdisk, cmdline); |
| 249 | |
| 250 | rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus); |
| 251 | if (rc < 0) { |
| 252 | fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n"); |
| 253 | goto err; |
| 254 | } |
| 255 | |
| 256 | #if 0 |
| 257 | rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256); |
| 258 | if (rc < 0) { |
| 259 | fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n"); |
| 260 | goto err; |
| 261 | } |
| 262 | #endif |
| 263 | |
| 264 | rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10); |
| 265 | if (rc < 0) { |
| 266 | fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n"); |
| 267 | goto err; |
| 268 | } |
| 269 | |
| 270 | xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); |
| 271 | console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); |
| 272 | |
| 273 | rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20, |
| 274 | kernel, ramdisk, cmdline, |
| 275 | 0, flags, |
| 276 | xenstore_port, &xenstore_mfn, |
| 277 | console_port, &console_mfn); |
| 278 | if (rc < 0) { |
| 279 | fprintf(stderr, "xen: xc_linux_build() failed\n"); |
| 280 | goto err; |
| 281 | } |
| 282 | |
| 283 | xenstore_domain_init2(xenstore_port, xenstore_mfn, |
| 284 | console_port, console_mfn); |
| 285 | |
| 286 | qemu_log("xen: unpausing domain %d\n", xen_domid); |
| 287 | rc = xc_domain_unpause(xen_xc, xen_domid); |
| 288 | if (rc < 0) { |
| 289 | fprintf(stderr, "xen: xc_domain_unpause() failed\n"); |
| 290 | goto err; |
| 291 | } |
| 292 | |
Paolo Bonzini | 7bd427d | 2011-03-11 16:47:48 +0100 | [diff] [blame] | 293 | xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL); |
| 294 | qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000); |
aliguori | 9306acb | 2009-04-22 15:19:44 +0000 | [diff] [blame] | 295 | return 0; |
| 296 | |
| 297 | err: |
| 298 | return -1; |
| 299 | } |