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