1 /*
2  * Copyright (C) 2010      Citrix Ltd.
3  * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4  * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5  * Author Gianni Tedesco <gianni.tedesco@citrix.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published
9  * by the Free Software Foundation; version 2.1 only. with the special
10  * exception on linking described in file LICENSE.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  */
17 
18 #include "libxl_osdeps.h" /* must come before any other headers */
19 
20 #include "libxl_internal.h"
21 #include "libxl_arch.h"
22 
23 #include <xc_dom.h>
24 #include <xenguest.h>
25 #include <xen/hvm/hvm_info_table.h>
26 #include <xen/hvm/e820.h>
27 
28 #include <xen-xsm/flask/flask.h>
29 
libxl__domain_create_info_setdefault(libxl__gc * gc,libxl_domain_create_info * c_info,const libxl_physinfo * info)30 int libxl__domain_create_info_setdefault(libxl__gc *gc,
31                                          libxl_domain_create_info *c_info,
32                                          const libxl_physinfo *info)
33 {
34     if (!c_info->type) {
35         LOG(ERROR, "domain type unspecified");
36         return ERROR_INVAL;
37     }
38 
39     libxl__arch_domain_create_info_setdefault(gc, c_info);
40 
41     if (c_info->type != LIBXL_DOMAIN_TYPE_PV) {
42         if (info->cap_hap) {
43             libxl_defbool_setdefault(&c_info->hap, true);
44         } else if (info->cap_shadow) {
45             libxl_defbool_setdefault(&c_info->hap, false);
46         } else {
47             LOG(ERROR, "neither hap nor shadow paging available");
48             return ERROR_INVAL;
49         }
50 
51         libxl_defbool_setdefault(&c_info->oos, true);
52     }
53 
54     libxl_defbool_setdefault(&c_info->run_hotplug_scripts, true);
55     libxl_defbool_setdefault(&c_info->driver_domain, false);
56 
57     if (!c_info->ssidref)
58         c_info->ssidref = SECINITSID_DOMU;
59 
60     libxl_defbool_setdefault(&c_info->xend_suspend_evtchn_compat, false);
61 
62     return 0;
63 }
64 
libxl__rdm_setdefault(libxl__gc * gc,libxl_domain_build_info * b_info)65 void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
66 {
67     if (b_info->u.hvm.rdm.policy == LIBXL_RDM_RESERVE_POLICY_INVALID)
68         b_info->u.hvm.rdm.policy = LIBXL_RDM_RESERVE_POLICY_RELAXED;
69 
70     if (b_info->u.hvm.rdm_mem_boundary_memkb == LIBXL_MEMKB_DEFAULT)
71         b_info->u.hvm.rdm_mem_boundary_memkb =
72                             LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT;
73 }
74 
libxl__domain_build_info_setdefault(libxl__gc * gc,libxl_domain_build_info * b_info)75 int libxl__domain_build_info_setdefault(libxl__gc *gc,
76                                         libxl_domain_build_info *b_info)
77 {
78     int i, rc;
79 
80     if (b_info->type != LIBXL_DOMAIN_TYPE_HVM &&
81         b_info->type != LIBXL_DOMAIN_TYPE_PV &&
82         b_info->type != LIBXL_DOMAIN_TYPE_PVH) {
83         LOG(ERROR, "invalid domain type");
84         return ERROR_INVAL;
85     }
86 
87     /* Copy deprecated options to it's new position. */
88     rc = libxl__domain_build_info_copy_deprecated(CTX, b_info);
89     if (rc) {
90         LOG(ERROR, "Unable to copy deprecated fields");
91         return rc;
92     }
93 
94     libxl_defbool_setdefault(&b_info->device_model_stubdomain, false);
95 
96     if (libxl_defbool_val(b_info->device_model_stubdomain) &&
97         !b_info->device_model_ssidref)
98         b_info->device_model_ssidref = SECINITSID_DOMDM;
99 
100     if (!b_info->device_model_version) {
101         if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) {
102             if (libxl_defbool_val(b_info->device_model_stubdomain)) {
103                 b_info->device_model_version =
104                     LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
105             } else {
106                 b_info->device_model_version = libxl__default_device_model(gc);
107             }
108         } else {
109             b_info->device_model_version =
110                 LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
111         }
112         if (b_info->device_model_version
113                 == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
114             const char *dm;
115 
116             dm = libxl__domain_device_model(gc, b_info);
117             rc = access(dm, X_OK);
118             if (rc < 0) {
119                 /* qemu-xen unavailable, use qemu-xen-traditional */
120                 if (errno == ENOENT) {
121                     LOGE(INFO, "qemu-xen is unavailable"
122                          ", using qemu-xen-traditional instead");
123                     b_info->device_model_version =
124                         LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
125                 } else {
126                     LOGE(ERROR, "qemu-xen access error");
127                     return ERROR_FAIL;
128                 }
129             }
130         }
131     }
132 
133     if (b_info->blkdev_start == NULL)
134         b_info->blkdev_start = libxl__strdup(NOGC, "xvda");
135 
136     if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) {
137         if (!b_info->u.hvm.bios)
138             switch (b_info->device_model_version) {
139             case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
140                 b_info->u.hvm.bios = LIBXL_BIOS_TYPE_ROMBIOS; break;
141             case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
142                 b_info->u.hvm.bios = LIBXL_BIOS_TYPE_SEABIOS; break;
143             default:
144                 LOG(ERROR, "unknown device model version");
145                 return ERROR_INVAL;
146             }
147 
148         /* Enforce BIOS<->Device Model version relationship */
149         switch (b_info->device_model_version) {
150         case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
151             if (b_info->u.hvm.bios != LIBXL_BIOS_TYPE_ROMBIOS) {
152                 LOG(ERROR, "qemu-xen-traditional requires bios=rombios.");
153                 return ERROR_INVAL;
154             }
155             break;
156         case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
157             if (b_info->u.hvm.bios == LIBXL_BIOS_TYPE_ROMBIOS) {
158                 LOG(ERROR, "qemu-xen does not support bios=rombios.");
159                 return ERROR_INVAL;
160             }
161             break;
162         default:abort();
163         }
164 
165         /* Check HVM direct boot parameters, we should honour ->ramdisk and
166          * ->cmdline iff ->kernel is set.
167          */
168         if (!b_info->kernel && (b_info->ramdisk || b_info->cmdline)) {
169             LOG(ERROR, "direct boot parameters specified but kernel missing");
170             return ERROR_INVAL;
171         }
172     }
173 
174     if (b_info->type == LIBXL_DOMAIN_TYPE_HVM &&
175         libxl_defbool_val(b_info->device_model_stubdomain)) {
176         if (!b_info->stubdomain_kernel) {
177             switch (b_info->device_model_version) {
178                 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
179                     b_info->stubdomain_kernel =
180                         libxl__abs_path(NOGC, "ioemu-stubdom.gz", libxl__xenfirmwaredir_path());
181                     break;
182                 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
183                     b_info->stubdomain_kernel =
184                         libxl__abs_path(NOGC,
185                                 "qemu-stubdom-linux-kernel",
186                                 libxl__xenfirmwaredir_path());
187                     break;
188                 default:
189                     abort();
190             }
191         }
192         if (!b_info->stubdomain_ramdisk) {
193             switch (b_info->device_model_version) {
194                 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
195                     break;
196                 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
197                     b_info->stubdomain_ramdisk =
198                         libxl__abs_path(NOGC,
199                                 "qemu-stubdom-linux-rootfs",
200                                 libxl__xenfirmwaredir_path());
201                     break;
202                 default:
203                     abort();
204             }
205         }
206     }
207 
208     if (!b_info->max_vcpus)
209         b_info->max_vcpus = 1;
210     if (!b_info->avail_vcpus.size) {
211         if (libxl_cpu_bitmap_alloc(CTX, &b_info->avail_vcpus, 1)) {
212             LOG(ERROR, "unable to allocate avail_vcpus bitmap");
213             return ERROR_FAIL;
214         }
215         libxl_bitmap_set(&b_info->avail_vcpus, 0);
216     } else if (b_info->avail_vcpus.size > HVM_MAX_VCPUS) {
217         LOG(ERROR, "avail_vcpus bitmap contains too many VCPUS");
218         return ERROR_FAIL;
219     }
220 
221     /* In libxl internals, we want to deal with vcpu_hard_affinity only! */
222     if (b_info->cpumap.size && !b_info->num_vcpu_hard_affinity) {
223         b_info->vcpu_hard_affinity = libxl__calloc(gc, b_info->max_vcpus,
224                                                    sizeof(libxl_bitmap));
225         for (i = 0; i < b_info->max_vcpus; i++) {
226             if (libxl_cpu_bitmap_alloc(CTX, &b_info->vcpu_hard_affinity[i], 0)) {
227                 LOG(ERROR, "failed to allocate vcpu hard affinity bitmap");
228                 return ERROR_FAIL;
229             }
230             libxl_bitmap_copy(CTX, &b_info->vcpu_hard_affinity[i],
231                               &b_info->cpumap);
232         }
233         b_info->num_vcpu_hard_affinity = b_info->max_vcpus;
234     }
235 
236     libxl_defbool_setdefault(&b_info->numa_placement, true);
237 
238     if (b_info->max_memkb == LIBXL_MEMKB_DEFAULT)
239         b_info->max_memkb = 32 * 1024;
240     if (b_info->target_memkb == LIBXL_MEMKB_DEFAULT)
241         b_info->target_memkb = b_info->max_memkb;
242 
243     if (b_info->stubdomain_memkb == LIBXL_MEMKB_DEFAULT) {
244         if (libxl_defbool_val(b_info->device_model_stubdomain)) {
245             if (libxl__stubdomain_is_linux(b_info))
246                 b_info->stubdomain_memkb = LIBXL_LINUX_STUBDOM_MEM * 1024;
247             else
248                 b_info->stubdomain_memkb = 28 * 1024; // MiniOS
249         } else {
250             b_info->stubdomain_memkb = 0; // no stubdomain
251         }
252     }
253 
254     libxl_defbool_setdefault(&b_info->claim_mode, false);
255 
256     libxl_defbool_setdefault(&b_info->localtime, false);
257 
258     libxl_defbool_setdefault(&b_info->disable_migrate, false);
259 
260     for (i = 0 ; i < b_info->num_iomem; i++)
261         if (b_info->iomem[i].gfn == LIBXL_INVALID_GFN)
262             b_info->iomem[i].gfn = b_info->iomem[i].start;
263 
264     if (!b_info->event_channels)
265         b_info->event_channels = 1023;
266 
267     libxl__arch_domain_build_info_setdefault(gc, b_info);
268     libxl_defbool_setdefault(&b_info->dm_restrict, false);
269 
270     if (b_info->iommu_memkb == LIBXL_MEMKB_DEFAULT)
271         /* Normally defaulted in libxl__domain_create_info_setdefault */
272         b_info->iommu_memkb = 0;
273 
274     switch (b_info->type) {
275     case LIBXL_DOMAIN_TYPE_HVM:
276         if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
277             /* Normally defaulted in libxl__domain_create_info_setdefault */
278             b_info->shadow_memkb = 0;
279         if (b_info->u.hvm.mmio_hole_memkb == LIBXL_MEMKB_DEFAULT)
280             b_info->u.hvm.mmio_hole_memkb = 0;
281 
282         if (b_info->u.hvm.vga.kind == LIBXL_VGA_INTERFACE_TYPE_UNKNOWN) {
283             b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
284         }
285 
286         if (!b_info->u.hvm.hdtype)
287             b_info->u.hvm.hdtype = LIBXL_HDTYPE_IDE;
288 
289         switch (b_info->device_model_version) {
290         case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
291             switch (b_info->u.hvm.vga.kind) {
292             case LIBXL_VGA_INTERFACE_TYPE_NONE:
293                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
294                     b_info->video_memkb = 0;
295                 break;
296             case LIBXL_VGA_INTERFACE_TYPE_QXL:
297                 LOG(ERROR,"qemu upstream required for qxl vga");
298                 return ERROR_INVAL;
299                 break;
300             case LIBXL_VGA_INTERFACE_TYPE_STD:
301                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
302                     b_info->video_memkb = 8 * 1024;
303                 if (b_info->video_memkb < 8 * 1024) {
304                     LOG(ERROR, "videoram must be at least 8 MB for STDVGA on QEMU_XEN_TRADITIONAL");
305                     return ERROR_INVAL;
306                 }
307                 break;
308             case LIBXL_VGA_INTERFACE_TYPE_CIRRUS:
309             default:
310                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
311                     b_info->video_memkb = 4 * 1024;
312                 if (b_info->video_memkb != 4 * 1024)
313                     LOG(WARN, "ignoring videoram other than 4 MB for CIRRUS on QEMU_XEN_TRADITIONAL");
314                 break;
315             }
316             break;
317         case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
318         default:
319             switch (b_info->u.hvm.vga.kind) {
320             case LIBXL_VGA_INTERFACE_TYPE_NONE:
321                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
322                     b_info->video_memkb = 0;
323                 break;
324             case LIBXL_VGA_INTERFACE_TYPE_QXL:
325                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT) {
326                     b_info->video_memkb = (128 * 1024);
327                 } else if (b_info->video_memkb < (128 * 1024)) {
328                     LOG(ERROR,
329                         "128 Mib videoram is the minimum for qxl default");
330                     return ERROR_INVAL;
331                 }
332                 break;
333             case LIBXL_VGA_INTERFACE_TYPE_STD:
334                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
335                     b_info->video_memkb = 16 * 1024;
336                 if (b_info->video_memkb < 16 * 1024) {
337                     LOG(ERROR, "videoram must be at least 16 MB for STDVGA on QEMU_XEN");
338                     return ERROR_INVAL;
339                 }
340                 break;
341             case LIBXL_VGA_INTERFACE_TYPE_CIRRUS:
342             default:
343                 if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
344                     b_info->video_memkb = 8 * 1024;
345                 if (b_info->video_memkb < 8 * 1024) {
346                     LOG(ERROR, "videoram must be at least 8 MB for CIRRUS on QEMU_XEN");
347                     return ERROR_INVAL;
348                 }
349                 break;
350             }
351             break;
352         }
353 
354         libxl_defbool_setdefault(&b_info->u.hvm.pae,                true);
355         libxl_defbool_setdefault(&b_info->u.hvm.acpi,               true);
356         libxl_defbool_setdefault(&b_info->u.hvm.acpi_s3,            true);
357         libxl_defbool_setdefault(&b_info->u.hvm.acpi_s4,            true);
358         libxl_defbool_setdefault(&b_info->u.hvm.acpi_laptop_slate,  false);
359         libxl_defbool_setdefault(&b_info->u.hvm.nx,                 true);
360         libxl_defbool_setdefault(&b_info->u.hvm.viridian,           false);
361         libxl_defbool_setdefault(&b_info->u.hvm.hpet,               true);
362         libxl_defbool_setdefault(&b_info->u.hvm.vpt_align,          true);
363         libxl_defbool_setdefault(&b_info->u.hvm.altp2m,             false);
364         libxl_defbool_setdefault(&b_info->u.hvm.usb,                false);
365         libxl_defbool_setdefault(&b_info->u.hvm.vkb_device,         true);
366         libxl_defbool_setdefault(&b_info->u.hvm.xen_platform_pci,   true);
367 
368         libxl_defbool_setdefault(&b_info->u.hvm.spice.enable, false);
369         if (!libxl_defbool_val(b_info->u.hvm.spice.enable) &&
370             (b_info->u.hvm.spice.usbredirection > 0) ){
371             b_info->u.hvm.spice.usbredirection = 0;
372             LOG(WARN, "spice disabled, disabling usbredirection");
373         }
374 
375         if (!b_info->u.hvm.usbversion &&
376             (b_info->u.hvm.spice.usbredirection > 0) )
377             b_info->u.hvm.usbversion = 2;
378 
379         if ((b_info->u.hvm.usbversion || b_info->u.hvm.spice.usbredirection) &&
380             ( libxl_defbool_val(b_info->u.hvm.usb)
381             || b_info->u.hvm.usbdevice_list
382             || b_info->u.hvm.usbdevice) ){
383             LOG(ERROR,"usbversion and/or usbredirection cannot be "
384             "enabled with usb and/or usbdevice parameters.");
385             return ERROR_INVAL;
386         }
387 
388         if (!b_info->u.hvm.boot)
389             b_info->u.hvm.boot = libxl__strdup(NOGC, "cda");
390 
391         libxl_defbool_setdefault(&b_info->u.hvm.vnc.enable, true);
392         if (libxl_defbool_val(b_info->u.hvm.vnc.enable)) {
393             libxl_defbool_setdefault(&b_info->u.hvm.vnc.findunused, true);
394             if (!b_info->u.hvm.vnc.listen)
395                 b_info->u.hvm.vnc.listen = libxl__strdup(NOGC, "127.0.0.1");
396         }
397 
398         libxl_defbool_setdefault(&b_info->u.hvm.sdl.enable, false);
399         if (libxl_defbool_val(b_info->u.hvm.sdl.enable)) {
400             libxl_defbool_setdefault(&b_info->u.hvm.sdl.opengl, false);
401         }
402 
403         if (libxl_defbool_val(b_info->u.hvm.spice.enable)) {
404             libxl_defbool_setdefault(&b_info->u.hvm.spice.disable_ticketing,
405                                      false);
406             libxl_defbool_setdefault(&b_info->u.hvm.spice.agent_mouse, true);
407             libxl_defbool_setdefault(&b_info->u.hvm.spice.vdagent, false);
408             libxl_defbool_setdefault(&b_info->u.hvm.spice.clipboard_sharing,
409                                      false);
410         }
411 
412         libxl_defbool_setdefault(&b_info->u.hvm.nographic, false);
413 
414         libxl_defbool_setdefault(&b_info->u.hvm.gfx_passthru, false);
415 
416         libxl__rdm_setdefault(gc, b_info);
417         break;
418     case LIBXL_DOMAIN_TYPE_PV:
419         libxl_defbool_setdefault(&b_info->u.pv.e820_host, false);
420         if (b_info->video_memkb == LIBXL_MEMKB_DEFAULT)
421             b_info->video_memkb = 0;
422         if (b_info->shadow_memkb == LIBXL_MEMKB_DEFAULT)
423             /* Normally defaulted in libxl__domain_create_info_setdefault */
424             b_info->shadow_memkb = 0;
425         if (b_info->u.pv.slack_memkb == LIBXL_MEMKB_DEFAULT)
426             b_info->u.pv.slack_memkb = 0;
427         break;
428     case LIBXL_DOMAIN_TYPE_PVH:
429         libxl_defbool_setdefault(&b_info->u.pvh.pvshim, false);
430         if (libxl_defbool_val(b_info->u.pvh.pvshim)) {
431             if (!b_info->u.pvh.pvshim_path)
432                 b_info->u.pvh.pvshim_path =
433                     libxl__sprintf(NOGC, "%s/%s",
434                                    libxl__xenfirmwaredir_path(),
435                                    PVSHIM_BASENAME);
436             if (!b_info->u.pvh.pvshim_cmdline)
437                 b_info->u.pvh.pvshim_cmdline =
438                     libxl__strdup(NOGC, PVSHIM_CMDLINE);
439         }
440 
441         break;
442     default:
443         LOG(ERROR, "invalid domain type %s in create info",
444             libxl_domain_type_to_string(b_info->type));
445         return ERROR_INVAL;
446     }
447 
448     /* Configuration fields shared between PVH and HVM. */
449     if (b_info->type != LIBXL_DOMAIN_TYPE_PV) {
450         if (libxl__timer_mode_is_default(&b_info->timer_mode))
451             b_info->timer_mode = LIBXL_TIMER_MODE_NO_DELAY_FOR_MISSED_TICKS;
452 
453         libxl_defbool_setdefault(&b_info->apic,                     true);
454         libxl_defbool_setdefault(&b_info->nested_hvm,               false);
455     }
456 
457     return 0;
458 }
459 
init_console_info(libxl__gc * gc,libxl__device_console * console,int dev_num)460 static void init_console_info(libxl__gc *gc,
461                              libxl__device_console *console,
462                              int dev_num)
463 {
464     libxl__device_console_init(console);
465     console->devid = dev_num;
466     console->consback = LIBXL__CONSOLE_BACKEND_XENCONSOLED;
467     console->output = libxl__strdup(NOGC, "pty");
468     /* console->{name,connection,path} are NULL on normal consoles.
469        Only 'channels' when mapped to consoles have a string name. */
470 }
471 
libxl__domain_build(libxl__gc * gc,libxl_domain_config * d_config,uint32_t domid,libxl__domain_build_state * state)472 int libxl__domain_build(libxl__gc *gc,
473                         libxl_domain_config *d_config,
474                         uint32_t domid,
475                         libxl__domain_build_state *state)
476 {
477     libxl_domain_build_info *const info = &d_config->b_info;
478     char **vments = NULL, **localents = NULL;
479     struct timeval start_time;
480     int i, ret;
481 
482     ret = libxl__build_pre(gc, domid, d_config, state);
483     if (ret)
484         goto out;
485 
486     gettimeofday(&start_time, NULL);
487 
488     switch (info->type) {
489     case LIBXL_DOMAIN_TYPE_HVM:
490         ret = libxl__build_hvm(gc, domid, d_config, state);
491         if (ret)
492             goto out;
493 
494         vments = libxl__calloc(gc, 7, sizeof(char *));
495         vments[0] = "rtc/timeoffset";
496         vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
497         vments[2] = "image/ostype";
498         vments[3] = "hvm";
499         vments[4] = "start_time";
500         vments[5] = GCSPRINTF("%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
501 
502         localents = libxl__calloc(gc, 13, sizeof(char *));
503         i = 0;
504         localents[i++] = "platform/acpi";
505         localents[i++] = libxl__acpi_defbool_val(info) ? "1" : "0";
506         localents[i++] = "platform/acpi_s3";
507         localents[i++] = libxl_defbool_val(info->u.hvm.acpi_s3) ? "1" : "0";
508         localents[i++] = "platform/acpi_s4";
509         localents[i++] = libxl_defbool_val(info->u.hvm.acpi_s4) ? "1" : "0";
510         localents[i++] = "platform/acpi_laptop_slate";
511         localents[i++] = libxl_defbool_val(info->u.hvm.acpi_laptop_slate) ? "1" : "0";
512         if (info->u.hvm.mmio_hole_memkb) {
513             uint64_t max_ram_below_4g =
514                 (1ULL << 32) - (info->u.hvm.mmio_hole_memkb << 10);
515 
516             if (max_ram_below_4g <= HVM_BELOW_4G_MMIO_START) {
517                 localents[i++] = "platform/mmio_hole_size";
518                 localents[i++] =
519                     GCSPRINTF("%"PRIu64,
520                                    info->u.hvm.mmio_hole_memkb << 10);
521             }
522         }
523         localents[i++] = "platform/device-model";
524         localents[i++] = (char *)libxl_device_model_version_to_string(info->device_model_version);
525 
526         break;
527     case LIBXL_DOMAIN_TYPE_PV:
528         ret = libxl__build_pv(gc, domid, d_config, state);
529         if (ret)
530             goto out;
531 
532         vments = libxl__calloc(gc, 11, sizeof(char *));
533         i = 0;
534         vments[i++] = "image/ostype";
535         vments[i++] = "linux";
536         vments[i++] = "image/kernel";
537         vments[i++] = (char *) state->pv_kernel.path;
538         vments[i++] = "start_time";
539         vments[i++] = GCSPRINTF("%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
540         if (state->pv_ramdisk.path) {
541             vments[i++] = "image/ramdisk";
542             vments[i++] = (char *) state->pv_ramdisk.path;
543         }
544         if (state->pv_cmdline) {
545             vments[i++] = "image/cmdline";
546             vments[i++] = (char *) state->pv_cmdline;
547         }
548 
549         break;
550     case LIBXL_DOMAIN_TYPE_PVH:
551         state->shim_path = info->u.pvh.pvshim_path;
552         state->shim_cmdline = GCSPRINTF("%s%s%s",
553                     info->u.pvh.pvshim_cmdline,
554                     info->u.pvh.pvshim_extra ? " " : "",
555                     info->u.pvh.pvshim_extra ? info->u.pvh.pvshim_extra : "");
556 
557         ret = libxl__build_hvm(gc, domid, d_config, state);
558         if (ret)
559             goto out;
560 
561         vments = libxl__calloc(gc, 3, sizeof(char *));
562         vments[0] = "start_time";
563         vments[1] = GCSPRINTF("%"PRIu64".%02ld",
564                               (uint64_t)start_time.tv_sec,
565                               (long)start_time.tv_usec/10000);
566 
567         break;
568     default:
569         ret = ERROR_INVAL;
570         goto out;
571     }
572     ret = libxl__build_post(gc, domid, info, state, vments, localents);
573 out:
574     return ret;
575 }
576 
libxl__domain_make(libxl__gc * gc,libxl_domain_config * d_config,libxl__domain_build_state * state,uint32_t * domid,bool soft_reset)577 int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
578                        libxl__domain_build_state *state,
579                        uint32_t *domid, bool soft_reset)
580 {
581     libxl_ctx *ctx = libxl__gc_owner(gc);
582     int ret, rc, nb_vm;
583     const char *dom_type;
584     char *uuid_string;
585     char *dom_path, *vm_path, *libxl_path;
586     struct xs_permissions roperm[2];
587     struct xs_permissions rwperm[1];
588     struct xs_permissions noperm[1];
589     xs_transaction_t t = 0;
590     libxl_vminfo *vm_list;
591 
592     /* convenience aliases */
593     libxl_domain_create_info *info = &d_config->c_info;
594     libxl_domain_build_info *b_info = &d_config->b_info;
595 
596     assert(soft_reset || *domid == INVALID_DOMID);
597 
598     uuid_string = libxl__uuid2string(gc, info->uuid);
599     if (!uuid_string) {
600         rc = ERROR_NOMEM;
601         goto out;
602     }
603 
604     if (!soft_reset) {
605         struct xen_domctl_createdomain create = {
606             .ssidref = info->ssidref,
607             .max_vcpus = b_info->max_vcpus,
608             .max_evtchn_port = b_info->event_channels,
609             .max_grant_frames = b_info->max_grant_frames,
610             .max_maptrack_frames = b_info->max_maptrack_frames,
611         };
612 
613         if (info->type != LIBXL_DOMAIN_TYPE_PV) {
614             create.flags |= XEN_DOMCTL_CDF_hvm;
615             create.flags |=
616                 libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0;
617             create.flags |=
618                 libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off;
619         }
620 
621         assert(info->passthrough != LIBXL_PASSTHROUGH_DEFAULT);
622         LOG(DETAIL, "passthrough: %s",
623             libxl_passthrough_to_string(info->passthrough));
624 
625         if (info->passthrough != LIBXL_PASSTHROUGH_DISABLED)
626             create.flags |= XEN_DOMCTL_CDF_iommu;
627 
628         if (info->passthrough == LIBXL_PASSTHROUGH_SYNC_PT)
629             create.iommu_opts |= XEN_DOMCTL_IOMMU_no_sharept;
630 
631         /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
632         libxl_uuid_copy(ctx, (libxl_uuid *)&create.handle, &info->uuid);
633 
634         ret = libxl__arch_domain_prepare_config(gc, d_config, &create);
635         if (ret < 0) {
636             LOGED(ERROR, *domid, "fail to get domain config");
637             rc = ERROR_FAIL;
638             goto out;
639         }
640 
641         for (;;) {
642             uint32_t local_domid;
643             bool recent;
644 
645             if (info->domid == RANDOM_DOMID) {
646                 uint16_t v;
647 
648                 ret = libxl__random_bytes(gc, (void *)&v, sizeof(v));
649                 if (ret < 0)
650                     break;
651 
652                 v &= DOMID_MASK;
653                 if (!libxl_domid_valid_guest(v))
654                     continue;
655 
656                 local_domid = v;
657             } else {
658                 local_domid = info->domid; /* May not be valid */
659             }
660 
661             ret = xc_domain_create(ctx->xch, &local_domid, &create);
662             if (ret < 0) {
663                 /*
664                  * If we generated a random domid and creation failed
665                  * because that domid already exists then simply try
666                  * again.
667                  */
668                 if (errno == EEXIST && info->domid == RANDOM_DOMID)
669                     continue;
670 
671                 LOGED(ERROR, local_domid, "domain creation fail");
672                 rc = ERROR_FAIL;
673                 goto out;
674             }
675 
676             /* A new domain now exists */
677             *domid = local_domid;
678 
679             rc = libxl__is_domid_recent(gc, local_domid, &recent);
680             if (rc)
681                 goto out;
682 
683             /* The domid is not recent, so we're done */
684             if (!recent)
685                 break;
686 
687             /*
688              * If the domid was specified then there's no point in
689              * trying again.
690              */
691             if (libxl_domid_valid_guest(info->domid)) {
692                 LOGED(ERROR, local_domid, "domain id recently used");
693                 rc = ERROR_FAIL;
694                 goto out;
695             }
696 
697             /*
698              * The domain is recent and so cannot be used. Clear domid
699              * here since, if xc_domain_destroy() fails below there is
700              * little point calling it again in the error path.
701              */
702             *domid = INVALID_DOMID;
703 
704             ret = xc_domain_destroy(ctx->xch, local_domid);
705             if (ret < 0) {
706                 LOGED(ERROR, local_domid, "domain destroy fail");
707                 rc = ERROR_FAIL;
708                 goto out;
709             }
710 
711             /* The domain was successfully destroyed, so we can try again */
712         }
713 
714         rc = libxl__arch_domain_save_config(gc, d_config, state, &create);
715         if (rc < 0)
716             goto out;
717     }
718 
719     /*
720      * If soft_reset is set the the domid will have been valid on entry.
721      * If it was not set then xc_domain_create() should have assigned a
722      * valid value. Either way, if we reach this point, domid should be
723      * valid.
724      */
725     assert(libxl_domid_valid_guest(*domid));
726 
727     ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
728     if (ret < 0) {
729         LOGED(ERROR, *domid, "domain move fail");
730         rc = ERROR_FAIL;
731         goto out;
732     }
733 
734     dom_path = libxl__xs_get_dompath(gc, *domid);
735     if (!dom_path) {
736         rc = ERROR_FAIL;
737         goto out;
738     }
739 
740     vm_path = GCSPRINTF("/vm/%s", uuid_string);
741     if (!vm_path) {
742         LOGD(ERROR, *domid, "cannot allocate create paths");
743         rc = ERROR_FAIL;
744         goto out;
745     }
746 
747     libxl_path = libxl__xs_libxl_path(gc, *domid);
748     if (!libxl_path) {
749         rc = ERROR_FAIL;
750         goto out;
751     }
752 
753     noperm[0].id = 0;
754     noperm[0].perms = XS_PERM_NONE;
755 
756     roperm[0].id = 0;
757     roperm[0].perms = XS_PERM_NONE;
758     roperm[1].id = *domid;
759     roperm[1].perms = XS_PERM_READ;
760 
761     rwperm[0].id = *domid;
762     rwperm[0].perms = XS_PERM_NONE;
763 
764 retry_transaction:
765     t = xs_transaction_start(ctx->xsh);
766 
767     xs_rm(ctx->xsh, t, dom_path);
768     libxl__xs_mknod(gc, t, dom_path, roperm, ARRAY_SIZE(roperm));
769 
770     xs_rm(ctx->xsh, t, vm_path);
771     libxl__xs_mknod(gc, t, vm_path, roperm, ARRAY_SIZE(roperm));
772 
773     xs_rm(ctx->xsh, t, libxl_path);
774     libxl__xs_mknod(gc, t, libxl_path, noperm, ARRAY_SIZE(noperm));
775     libxl__xs_mknod(gc, t, GCSPRINTF("%s/device", libxl_path),
776                     noperm, ARRAY_SIZE(noperm));
777 
778     xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, strlen(vm_path));
779     rc = libxl__domain_rename(gc, *domid, 0, info->name, t);
780     if (rc)
781         goto out;
782 
783     libxl__xs_mknod(gc, t,
784                     GCSPRINTF("%s/cpu", dom_path),
785                     roperm, ARRAY_SIZE(roperm));
786     libxl__xs_mknod(gc, t,
787                     GCSPRINTF("%s/memory", dom_path),
788                     roperm, ARRAY_SIZE(roperm));
789 
790     if (!libxl_defbool_val(info->xend_suspend_evtchn_compat)) {
791         libxl__xs_mknod(gc, t,
792                         GCSPRINTF("%s/device", dom_path),
793                         roperm, ARRAY_SIZE(roperm));
794         libxl__xs_mknod(gc, t,
795                         GCSPRINTF("%s/device/suspend/event-channel",
796                                   dom_path),
797                         rwperm, ARRAY_SIZE(rwperm));
798     } else {
799         libxl__xs_mknod(gc, t,
800                         GCSPRINTF("%s/device", dom_path),
801                         rwperm, ARRAY_SIZE(rwperm));
802     }
803 
804     libxl__xs_mknod(gc, t,
805                     GCSPRINTF("%s/control", dom_path),
806                     roperm, ARRAY_SIZE(roperm));
807     if (info->type == LIBXL_DOMAIN_TYPE_HVM)
808         libxl__xs_mknod(gc, t,
809                         GCSPRINTF("%s/hvmloader", dom_path),
810                         roperm, ARRAY_SIZE(roperm));
811 
812     libxl__xs_mknod(gc, t,
813                     GCSPRINTF("%s/control/shutdown", dom_path),
814                     rwperm, ARRAY_SIZE(rwperm));
815     libxl__xs_mknod(gc, t,
816                     GCSPRINTF("%s/control/feature-poweroff", dom_path),
817                     rwperm, ARRAY_SIZE(rwperm));
818     libxl__xs_mknod(gc, t,
819                     GCSPRINTF("%s/control/feature-reboot", dom_path),
820                     rwperm, ARRAY_SIZE(rwperm));
821     libxl__xs_mknod(gc, t,
822                     GCSPRINTF("%s/control/feature-suspend", dom_path),
823                     rwperm, ARRAY_SIZE(rwperm));
824     if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
825         libxl__xs_mknod(gc, t,
826                         GCSPRINTF("%s/control/feature-s3", dom_path),
827                         rwperm, ARRAY_SIZE(rwperm));
828         libxl__xs_mknod(gc, t,
829                         GCSPRINTF("%s/control/feature-s4", dom_path),
830                         rwperm, ARRAY_SIZE(rwperm));
831     }
832     libxl__xs_mknod(gc, t,
833                     GCSPRINTF("%s/control/sysrq", dom_path),
834                     rwperm, ARRAY_SIZE(rwperm));
835 
836     libxl__xs_mknod(gc, t,
837                     GCSPRINTF("%s/data", dom_path),
838                     rwperm, ARRAY_SIZE(rwperm));
839     libxl__xs_mknod(gc, t,
840                     GCSPRINTF("%s/drivers", dom_path),
841                     rwperm, ARRAY_SIZE(rwperm));
842     libxl__xs_mknod(gc, t,
843                     GCSPRINTF("%s/feature", dom_path),
844                     rwperm, ARRAY_SIZE(rwperm));
845     libxl__xs_mknod(gc, t,
846                     GCSPRINTF("%s/attr", dom_path),
847                     rwperm, ARRAY_SIZE(rwperm));
848     libxl__xs_mknod(gc, t,
849                     GCSPRINTF("%s/error", dom_path),
850                     rwperm, ARRAY_SIZE(rwperm));
851 
852     if (libxl_defbool_val(info->driver_domain)) {
853         /*
854          * Create a local "libxl" directory for each guest, since we might want
855          * to use libxl from inside the guest
856          */
857         libxl__xs_mknod(gc, t, GCSPRINTF("%s/libxl", dom_path), rwperm,
858                         ARRAY_SIZE(rwperm));
859         /*
860          * Create a local "device-model" directory for each guest, since we
861          * might want to use Qemu from inside the guest
862          */
863         libxl__xs_mknod(gc, t, GCSPRINTF("%s/device-model", dom_path), rwperm,
864                         ARRAY_SIZE(rwperm));
865     }
866 
867     vm_list = libxl_list_vm(ctx, &nb_vm);
868     if (!vm_list) {
869         LOGD(ERROR, *domid, "cannot get number of running guests");
870         rc = ERROR_FAIL;
871         goto out;
872     }
873     libxl_vminfo_list_free(vm_list, nb_vm);
874 
875     xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, strlen(uuid_string));
876     xs_write(ctx->xsh, t, GCSPRINTF("%s/name", vm_path), info->name, strlen(info->name));
877 
878     libxl__xs_writev(gc, t, dom_path, info->xsdata);
879     libxl__xs_writev(gc, t, GCSPRINTF("%s/platform", dom_path), info->platformdata);
880 
881     xs_write(ctx->xsh, t, GCSPRINTF("%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
882     xs_write(ctx->xsh, t, GCSPRINTF("%s/control/platform-feature-xs_reset_watches", dom_path), "1", 1);
883 
884     dom_type = libxl_domain_type_to_string(info->type);
885     xs_write(ctx->xsh, t, GCSPRINTF("%s/type", libxl_path), dom_type,
886              strlen(dom_type));
887 
888     if (!xs_transaction_end(ctx->xsh, t, 0)) {
889         if (errno == EAGAIN) {
890             t = 0;
891             goto retry_transaction;
892         }
893         LOGED(ERROR, *domid, "domain creation ""xenstore transaction commit failed");
894         rc = ERROR_FAIL;
895         goto out;
896     }
897     t = 0;
898 
899     rc = 0;
900  out:
901     if (t) xs_transaction_end(ctx->xsh, t, 1);
902     return rc;
903 }
904 
store_libxl_entry(libxl__gc * gc,uint32_t domid,libxl_domain_build_info * b_info)905 static int store_libxl_entry(libxl__gc *gc, uint32_t domid,
906                              libxl_domain_build_info *b_info)
907 {
908     char *path = NULL;
909 
910     path = libxl__xs_libxl_path(gc, domid);
911     path = GCSPRINTF("%s/dm-version", path);
912     return libxl__xs_printf(gc, XBT_NULL, path, "%s",
913                             libxl_device_model_version_to_string(b_info->device_model_version));
914 }
915 
libxl__domain_build_state_init(libxl__domain_build_state * state)916 void libxl__domain_build_state_init(libxl__domain_build_state *state)
917 {
918     state->dm_monitor_fd = -1;
919 }
920 
libxl__domain_build_state_dispose(libxl__domain_build_state * state)921 void libxl__domain_build_state_dispose(libxl__domain_build_state *state)
922 {
923     libxl__file_reference_unmap(&state->pv_kernel);
924     libxl__file_reference_unmap(&state->pv_ramdisk);
925     if (state->dm_monitor_fd >= 0) {
926         close(state->dm_monitor_fd);
927         state->dm_monitor_fd = -1;
928     }
929 }
930 
931 /*----- main domain creation -----*/
932 
933 /* We have a linear control flow; only one event callback is
934  * outstanding at any time.  Each initiation and callback function
935  * arranges for the next to be called, as the very last thing it
936  * does.  (If that particular sub-operation is not needed, a
937  * function will call the next event callback directly.)
938  */
939 
940 /* Event callbacks, in this order: */
941 static void domcreate_bootloader_console_available(libxl__egc *egc,
942                                                    libxl__bootloader_state *bl);
943 static void domcreate_console_available(libxl__egc *egc,
944                                         libxl__domain_create_state *dcs);
945 
946 static void domcreate_bootloader_done(libxl__egc *egc,
947                                       libxl__bootloader_state *bl,
948                                       int rc);
949 static void libxl__colo_restore_setup_done(libxl__egc *egc,
950                                            libxl__colo_restore_state *crs,
951                                            int rc);
952 static void domcreate_stream_done(libxl__egc *egc,
953                                   libxl__stream_read_state *srs,
954                                   int ret);
955 static void domcreate_rebuild_done(libxl__egc *egc,
956                                    libxl__domain_create_state *dcs,
957                                    int ret);
958 static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *aodevs,
959                                 int ret);
960 static void domcreate_devmodel_started(libxl__egc *egc,
961                                        libxl__dm_spawn_state *dmss,
962                                        int rc);
963 static void domcreate_attach_devices(libxl__egc *egc,
964                                      libxl__multidev *multidev,
965                                      int ret);
966 static void console_xswait_callback(libxl__egc *egc, libxl__xswait_state *xswa,
967                                     int rc, const char *p);
968 
969 /* Our own function to clean up and call the user's callback.
970  * The final call in the sequence. */
971 static void domcreate_complete(libxl__egc *egc,
972                                libxl__domain_create_state *dcs,
973                                int rc);
974 
975 /* If creation is not successful, this callback will be executed
976  * when domain destruction is finished */
977 static void domcreate_destruction_cb(libxl__egc *egc,
978                                      libxl__domain_destroy_state *dds,
979                                      int rc);
980 
ok_to_default_memkb_in_create(libxl__gc * gc)981 static bool ok_to_default_memkb_in_create(libxl__gc *gc)
982 {
983     /*
984      * This is a fudge.  We are trying to find whether the caller
985      * calls the old version of libxl_domain_need_memory.  If they do
986      * then, because it only gets the b_info, and because it can't
987      * update the b_info (because it's const), it will base its
988      * calculations on defaulting shadow_memkb and iommu_memkb to 0
989      * In that case we probably shouldn't default them differently
990      * during libxl_domain_create.
991      *
992      * The result is that the behaviour with old callers is the same
993      * as in 4.13: no additional memory is allocated for shadow and
994      * iommu (unless the caller set shadow_memkb, eg from a call to
995      * libxl_get_required_shadow_memory).
996      */
997     return !CTX->libxl_domain_need_memory_0x041200_called ||
998             CTX->libxl_domain_need_memory_called;
999     /*
1000      * Treat mixed callers as new callers.  Presumably they know what
1001      * they are doing.
1002      */
1003 }
1004 
libxl__get_required_iommu_memory(unsigned long maxmem_kb)1005 static unsigned long libxl__get_required_iommu_memory(unsigned long maxmem_kb)
1006 {
1007     unsigned long iommu_pages = 0, mem_pages = maxmem_kb / 4;
1008     unsigned int level;
1009 
1010     /* Assume a 4 level page table with 512 entries per level */
1011     for (level = 0; level < 4; level++)
1012     {
1013         mem_pages = DIV_ROUNDUP(mem_pages, 512);
1014         iommu_pages += mem_pages;
1015     }
1016 
1017     return iommu_pages * 4;
1018 }
1019 
libxl__domain_config_setdefault(libxl__gc * gc,libxl_domain_config * d_config,uint32_t domid)1020 int libxl__domain_config_setdefault(libxl__gc *gc,
1021                                     libxl_domain_config *d_config,
1022                                     uint32_t domid /* for logging, only */)
1023 {
1024     libxl_ctx *ctx = libxl__gc_owner(gc);
1025     int ret;
1026     bool pod_enabled = false;
1027     libxl_domain_create_info *c_info = &d_config->c_info;
1028 
1029     libxl_physinfo physinfo;
1030     ret = libxl_get_physinfo(CTX, &physinfo);
1031     if (ret) goto error_out;
1032 
1033     if (d_config->c_info.ssid_label) {
1034         char *s = d_config->c_info.ssid_label;
1035         ret = libxl_flask_context_to_sid(ctx, s, strlen(s),
1036                                          &d_config->c_info.ssidref);
1037         if (ret) {
1038             if (errno == ENOSYS) {
1039                 LOGD(WARN, domid, "XSM Disabled: init_seclabel not supported");
1040                 ret = 0;
1041             } else {
1042                 LOGD(ERROR, domid, "Invalid init_seclabel: %s", s);
1043                 goto error_out;
1044             }
1045         }
1046     }
1047 
1048     if (d_config->b_info.exec_ssid_label) {
1049         char *s = d_config->b_info.exec_ssid_label;
1050         ret = libxl_flask_context_to_sid(ctx, s, strlen(s),
1051                                          &d_config->b_info.exec_ssidref);
1052         if (ret) {
1053             if (errno == ENOSYS) {
1054                 LOGD(WARN, domid, "XSM Disabled: seclabel not supported");
1055                 ret = 0;
1056             } else {
1057                 LOGD(ERROR, domid, "Invalid seclabel: %s", s);
1058                 goto error_out;
1059             }
1060         }
1061     }
1062 
1063     if (d_config->b_info.device_model_ssid_label) {
1064         char *s = d_config->b_info.device_model_ssid_label;
1065         ret = libxl_flask_context_to_sid(ctx, s, strlen(s),
1066                                          &d_config->b_info.device_model_ssidref);
1067         if (ret) {
1068             if (errno == ENOSYS) {
1069                 LOGD(WARN, domid,
1070                      "XSM Disabled: device_model_stubdomain_seclabel not supported");
1071                 ret = 0;
1072             } else {
1073                 LOGD(ERROR, domid, "Invalid device_model_stubdomain_seclabel: %s", s);
1074                 goto error_out;
1075             }
1076         }
1077     }
1078 
1079     if (d_config->c_info.pool_name) {
1080         d_config->c_info.poolid = -1;
1081         libxl_cpupool_qualifier_to_cpupoolid(ctx, d_config->c_info.pool_name,
1082                                              &d_config->c_info.poolid,
1083                                              NULL);
1084     }
1085     if (!libxl_cpupoolid_is_valid(ctx, d_config->c_info.poolid)) {
1086         LOGD(ERROR, domid, "Illegal pool specified: %s",
1087              d_config->c_info.pool_name);
1088         ret = ERROR_INVAL;
1089         goto error_out;
1090     }
1091 
1092     ret = libxl__domain_create_info_setdefault(gc, &d_config->c_info,
1093                                                &physinfo);
1094     if (ret) {
1095         LOGD(ERROR, domid, "Unable to set domain create info defaults");
1096         goto error_out;
1097     }
1098 
1099     bool need_pt = d_config->num_pcidevs || d_config->num_dtdevs;
1100     if (c_info->passthrough == LIBXL_PASSTHROUGH_DEFAULT) {
1101         c_info->passthrough = need_pt
1102             ? LIBXL_PASSTHROUGH_ENABLED : LIBXL_PASSTHROUGH_DISABLED;
1103     }
1104 
1105     bool iommu_enabled = physinfo.cap_hvm_directio;
1106     if (c_info->passthrough != LIBXL_PASSTHROUGH_DISABLED && !iommu_enabled) {
1107         LOGD(ERROR, domid,
1108              "passthrough not supported on this platform\n");
1109         ret = ERROR_INVAL;
1110         goto error_out;
1111     }
1112 
1113     if (c_info->passthrough == LIBXL_PASSTHROUGH_DISABLED && need_pt) {
1114         LOGD(ERROR, domid,
1115              "passthrough disabled but devices are specified");
1116         ret = ERROR_INVAL;
1117         goto error_out;
1118     }
1119 
1120     ret = libxl__arch_passthrough_mode_setdefault(gc,domid,d_config,&physinfo);
1121     if (ret) goto error_out;
1122 
1123     /* An explicit setting should now have been chosen */
1124     assert(c_info->passthrough != LIBXL_PASSTHROUGH_DEFAULT);
1125     assert(c_info->passthrough != LIBXL_PASSTHROUGH_ENABLED);
1126 
1127     /* If target_memkb is smaller than max_memkb, the subsequent call
1128      * to libxc when building HVM domain will enable PoD mode.
1129      */
1130     pod_enabled = (d_config->c_info.type != LIBXL_DOMAIN_TYPE_PV) &&
1131         (d_config->b_info.target_memkb < d_config->b_info.max_memkb);
1132 
1133     /* We cannot have PoD and PCI device assignment at the same time
1134      * for HVM guest. It was reported that IOMMU cannot work with PoD
1135      * enabled because it needs to populated entire page table for
1136      * guest. To stay on the safe side, we disable PCI device
1137      * assignment when PoD is enabled.
1138      */
1139     if (d_config->c_info.type != LIBXL_DOMAIN_TYPE_PV &&
1140         d_config->num_pcidevs && pod_enabled) {
1141         ret = ERROR_INVAL;
1142         LOGD(ERROR, domid,
1143              "PCI device assignment for HVM guest failed due to PoD enabled");
1144         goto error_out;
1145     }
1146 
1147     /* Disallow PoD and vNUMA to be enabled at the same time because PoD
1148      * pool is not vNUMA-aware yet.
1149      */
1150     if (pod_enabled && d_config->b_info.num_vnuma_nodes) {
1151         ret = ERROR_INVAL;
1152         LOGD(ERROR, domid, "Cannot enable PoD and vNUMA at the same time");
1153         goto error_out;
1154     }
1155 
1156     /* PV vNUMA is not yet supported because there is an issue with
1157      * cpuid handling.
1158      */
1159     if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV &&
1160         d_config->b_info.num_vnuma_nodes) {
1161         ret = ERROR_INVAL;
1162         LOGD(ERROR, domid, "PV vNUMA is not yet supported");
1163         goto error_out;
1164     }
1165 
1166     if (d_config->b_info.shadow_memkb == LIBXL_MEMKB_DEFAULT
1167         && ok_to_default_memkb_in_create(gc))
1168         d_config->b_info.shadow_memkb =
1169             libxl_get_required_shadow_memory(d_config->b_info.max_memkb,
1170                                              d_config->b_info.max_vcpus);
1171 
1172     /* No IOMMU reservation is needed if passthrough mode is not 'sync_pt' */
1173     if (d_config->b_info.iommu_memkb == LIBXL_MEMKB_DEFAULT
1174         && ok_to_default_memkb_in_create(gc))
1175         d_config->b_info.iommu_memkb =
1176             (d_config->c_info.passthrough == LIBXL_PASSTHROUGH_SYNC_PT)
1177             ? libxl__get_required_iommu_memory(d_config->b_info.max_memkb)
1178             : 0;
1179 
1180     ret = libxl__domain_build_info_setdefault(gc, &d_config->b_info);
1181     if (ret) {
1182         LOGD(ERROR, domid, "Unable to set domain build info defaults");
1183         goto error_out;
1184     }
1185 
1186     if (d_config->c_info.type != LIBXL_DOMAIN_TYPE_PV &&
1187         (libxl_defbool_val(d_config->b_info.nested_hvm) &&
1188         ((d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM &&
1189           libxl_defbool_val(d_config->b_info.u.hvm.altp2m)) ||
1190         (d_config->b_info.altp2m != LIBXL_ALTP2M_MODE_DISABLED)))) {
1191         ret = ERROR_INVAL;
1192         LOGD(ERROR, domid, "nestedhvm and altp2mhvm cannot be used together");
1193         goto error_out;
1194     }
1195 
1196     if (((d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM &&
1197          libxl_defbool_val(d_config->b_info.u.hvm.altp2m)) ||
1198         (d_config->c_info.type != LIBXL_DOMAIN_TYPE_PV &&
1199          d_config->b_info.altp2m != LIBXL_ALTP2M_MODE_DISABLED)) &&
1200         pod_enabled) {
1201         ret = ERROR_INVAL;
1202         LOGD(ERROR, domid, "Cannot enable PoD and ALTP2M at the same time");
1203         goto error_out;
1204     }
1205 
1206     ret = 0;
1207  error_out:
1208     return ret;
1209 }
1210 
initiate_domain_create(libxl__egc * egc,libxl__domain_create_state * dcs)1211 static void initiate_domain_create(libxl__egc *egc,
1212                                    libxl__domain_create_state *dcs)
1213 {
1214     STATE_AO_GC(dcs->ao);
1215     uint32_t domid;
1216     int i, ret;
1217 
1218     /* convenience aliases */
1219     libxl_domain_config *const d_config = dcs->guest_config;
1220     libxl__domain_build_state *dbs = &dcs->build_state;
1221 
1222     libxl__xswait_init(&dcs->console_xswait);
1223 
1224     domid = dcs->domid;
1225     libxl__domain_build_state_init(dbs);
1226     dbs->restore = dcs->restore_fd >= 0;
1227 
1228     ret = libxl__domain_config_setdefault(gc,d_config,domid);
1229     if (ret) goto error_out;
1230 
1231     ret = libxl__domain_make(gc, d_config, dbs, &domid, dcs->soft_reset);
1232     if (ret) {
1233         LOGD(ERROR, domid, "cannot make domain: %d", ret);
1234         dcs->guest_domid = domid;
1235         ret = ERROR_FAIL;
1236         goto error_out;
1237     }
1238 
1239     dcs->guest_domid = domid;
1240     dcs->sdss.dm.guest_domid = 0; /* means we haven't spawned */
1241 
1242     /* post-4.13 todo: move these next bits of defaulting to
1243      * libxl__domain_config_setdefault */
1244 
1245     /*
1246      * Set the dm version quite early so that libxl doesn't have to pass the
1247      * build info around just to know if the domain has a device model or not.
1248      */
1249     store_libxl_entry(gc, domid, &d_config->b_info);
1250 
1251     for (i = 0; i < d_config->num_disks; i++) {
1252         ret = libxl__disk_devtype.set_default(gc, domid, &d_config->disks[i],
1253                                               false);
1254         if (ret) {
1255             LOGD(ERROR, domid, "Unable to set disk defaults for disk %d", i);
1256             goto error_out;
1257         }
1258     }
1259 
1260     dcs->bl.ao = ao;
1261     libxl_device_disk *bootdisk =
1262         d_config->num_disks > 0 ? &d_config->disks[0] : NULL;
1263 
1264     /*
1265      * The devid has to be set before launching the device model. For the
1266      * hotplug case this is done in libxl_device_nic_add but on domain
1267      * creation this is called too late.
1268      * Make two runs over configured NICs in order to avoid duplicate IDs
1269      * in case the caller partially assigned IDs.
1270      */
1271     ret = libxl__device_nic_set_devids(gc, d_config, domid);
1272     if (ret)
1273         goto error_out;
1274 
1275     if (dbs->restore || dcs->soft_reset) {
1276         LOGD(DEBUG, domid, "restoring, not running bootloader");
1277         domcreate_bootloader_done(egc, &dcs->bl, 0);
1278     } else  {
1279         LOGD(DEBUG, domid, "running bootloader");
1280         dcs->bl.callback = domcreate_bootloader_done;
1281         dcs->bl.console_available = domcreate_bootloader_console_available;
1282         dcs->bl.info = &d_config->b_info;
1283         dcs->bl.disk = bootdisk;
1284         dcs->bl.domid = dcs->guest_domid;
1285 
1286         dcs->bl.kernel = &dbs->pv_kernel;
1287         dcs->bl.ramdisk = &dbs->pv_ramdisk;
1288 
1289         libxl__bootloader_run(egc, &dcs->bl);
1290     }
1291     return;
1292 
1293 error_out:
1294     assert(ret);
1295     domcreate_complete(egc, dcs, ret);
1296 }
1297 
domcreate_bootloader_console_available(libxl__egc * egc,libxl__bootloader_state * bl)1298 static void domcreate_bootloader_console_available(libxl__egc *egc,
1299                                                    libxl__bootloader_state *bl)
1300 {
1301     libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
1302     STATE_AO_GC(bl->ao);
1303     domcreate_console_available(egc, dcs);
1304 }
1305 
domcreate_console_available(libxl__egc * egc,libxl__domain_create_state * dcs)1306 static void domcreate_console_available(libxl__egc *egc,
1307                                         libxl__domain_create_state *dcs) {
1308     libxl__ao_progress_report(egc, dcs->ao, &dcs->aop_console_how,
1309                               NEW_EVENT(egc, DOMAIN_CREATE_CONSOLE_AVAILABLE,
1310                                         dcs->guest_domid,
1311                                         dcs->aop_console_how.for_event));
1312 }
1313 
domcreate_bootloader_done(libxl__egc * egc,libxl__bootloader_state * bl,int rc)1314 static void domcreate_bootloader_done(libxl__egc *egc,
1315                                       libxl__bootloader_state *bl,
1316                                       int rc)
1317 {
1318     libxl__domain_create_state *dcs = CONTAINER_OF(bl, *dcs, bl);
1319     STATE_AO_GC(bl->ao);
1320 
1321     /* convenience aliases */
1322     const uint32_t domid = dcs->guest_domid;
1323     libxl_domain_config *const d_config = dcs->guest_config;
1324     const int restore_fd = dcs->restore_fd;
1325     libxl__domain_build_state *const state = &dcs->build_state;
1326     const int checkpointed_stream = dcs->restore_params.checkpointed_stream;
1327     libxl__colo_restore_state *const crs = &dcs->crs;
1328     libxl_domain_build_info *const info = &d_config->b_info;
1329     libxl__srm_restore_autogen_callbacks *const callbacks =
1330         &dcs->srs.shs.callbacks.restore.a;
1331 
1332     if (rc) {
1333         domcreate_rebuild_done(egc, dcs, rc);
1334         return;
1335     }
1336 
1337     /* consume bootloader outputs. state->pv_{kernel,ramdisk} have
1338      * been initialised by the bootloader already.
1339      */
1340     state->pv_cmdline = bl->cmdline;
1341 
1342     /* We might be going to call libxl__spawn_local_dm, or _spawn_stub_dm.
1343      * Fill in any field required by either, including both relevant
1344      * callbacks (_spawn_stub_dm will overwrite our trespass if needed). */
1345     dcs->sdss.dm.spawn.ao = ao;
1346     dcs->sdss.dm.guest_config = dcs->guest_config;
1347     dcs->sdss.dm.build_state = &dcs->build_state;
1348     dcs->sdss.dm.callback = domcreate_devmodel_started;
1349     dcs->sdss.callback = domcreate_devmodel_started;
1350 
1351     if (restore_fd < 0 && !dcs->soft_reset) {
1352         rc = libxl__domain_build(gc, d_config, domid, state);
1353         domcreate_rebuild_done(egc, dcs, rc);
1354         return;
1355     }
1356 
1357     /* Prepare environment for domcreate_stream_done */
1358     dcs->srs.dcs = dcs;
1359 
1360     /* Restore */
1361     callbacks->static_data_done = libxl__srm_callout_callback_static_data_done;
1362     callbacks->restore_results = libxl__srm_callout_callback_restore_results;
1363 
1364     /* COLO only supports HVM now because it does not work very
1365      * well with pv drivers:
1366      * 1. We need to resume vm in the slow path. In this case we
1367      *    need to disconnect/reconnect backend and frontend. It
1368      *    will take too much time and the performance is very slow.
1369      * 2. PV disk cannot reuse block replication that is implemented
1370      *    in QEMU.
1371      */
1372     if (info->type != LIBXL_DOMAIN_TYPE_HVM &&
1373         checkpointed_stream == LIBXL_CHECKPOINTED_STREAM_COLO) {
1374         LOGD(ERROR, domid, "COLO only supports HVM, unable to restore domain");
1375         rc = ERROR_FAIL;
1376         goto out;
1377     }
1378 
1379     rc = libxl__build_pre(gc, domid, d_config, state);
1380     if (rc)
1381         goto out;
1382 
1383     dcs->srs.ao = ao;
1384     dcs->srs.fd = restore_fd;
1385     dcs->srs.legacy = (dcs->restore_params.stream_version == 1);
1386     dcs->srs.back_channel = false;
1387     dcs->srs.completion_callback = domcreate_stream_done;
1388 
1389     if (restore_fd >= 0) {
1390         switch (checkpointed_stream) {
1391         case LIBXL_CHECKPOINTED_STREAM_COLO:
1392             /* colo restore setup */
1393             crs->ao = ao;
1394             crs->domid = domid;
1395             crs->send_back_fd = dcs->send_back_fd;
1396             crs->recv_fd = restore_fd;
1397             crs->hvm = (info->type != LIBXL_DOMAIN_TYPE_PV);
1398             crs->callback = libxl__colo_restore_setup_done;
1399             libxl__colo_restore_setup(egc, crs);
1400             break;
1401         case LIBXL_CHECKPOINTED_STREAM_REMUS:
1402             libxl__remus_restore_setup(egc, dcs);
1403             /* fall through */
1404         case LIBXL_CHECKPOINTED_STREAM_NONE:
1405             libxl__stream_read_start(egc, &dcs->srs);
1406         }
1407         return;
1408     }
1409 
1410  out:
1411     domcreate_stream_done(egc, &dcs->srs, rc);
1412 }
1413 
libxl__colo_restore_setup_done(libxl__egc * egc,libxl__colo_restore_state * crs,int rc)1414 static void libxl__colo_restore_setup_done(libxl__egc *egc,
1415                                            libxl__colo_restore_state *crs,
1416                                            int rc)
1417 {
1418     libxl__domain_create_state *dcs = CONTAINER_OF(crs, *dcs, crs);
1419 
1420     EGC_GC;
1421 
1422     if (rc) {
1423         LOGD(ERROR, dcs->guest_domid, "colo restore setup fails: %d", rc);
1424         domcreate_stream_done(egc, &dcs->srs, rc);
1425         return;
1426     }
1427 
1428     libxl__stream_read_start(egc, &dcs->srs);
1429 }
1430 
libxl__srm_callout_callback_static_data_done(unsigned int missing,void * user)1431 int libxl__srm_callout_callback_static_data_done(unsigned int missing,
1432                                                  void *user)
1433 {
1434     libxl__save_helper_state *shs = user;
1435     libxl__domain_create_state *dcs = shs->caller_state;
1436     STATE_AO_GC(dcs->ao);
1437     libxl_ctx *ctx = libxl__gc_owner(gc);
1438 
1439     libxl_domain_config *d_config = dcs->guest_config;
1440     libxl_domain_build_info *info = &d_config->b_info;
1441 
1442     /*
1443      * CPUID/MSR information is not present in pre Xen-4.14 streams.
1444      *
1445      * Libxl used to always regenerate the CPUID policy from first principles
1446      * on migrate.  Continue to do so for backwards compatibility when the
1447      * stream doesn't contain any CPUID data.
1448      */
1449     if (missing & XGR_SDD_MISSING_CPUID)
1450         libxl__cpuid_legacy(ctx, dcs->guest_domid, true, info);
1451 
1452     return 0;
1453 }
1454 
libxl__srm_callout_callback_restore_results(xen_pfn_t store_mfn,xen_pfn_t console_mfn,void * user)1455 void libxl__srm_callout_callback_restore_results(xen_pfn_t store_mfn,
1456           xen_pfn_t console_mfn, void *user)
1457 {
1458     libxl__save_helper_state *shs = user;
1459     libxl__domain_create_state *dcs = shs->caller_state;
1460     STATE_AO_GC(dcs->ao);
1461     libxl__domain_build_state *const state = &dcs->build_state;
1462 
1463     state->store_mfn =            store_mfn;
1464     state->console_mfn =          console_mfn;
1465     shs->need_results =           0;
1466 }
1467 
domcreate_stream_done(libxl__egc * egc,libxl__stream_read_state * srs,int ret)1468 static void domcreate_stream_done(libxl__egc *egc,
1469                                   libxl__stream_read_state *srs,
1470                                   int ret)
1471 {
1472     /* NB perhaps only srs->dcs is valid; eg in the case of an
1473      * early branch to domcreate_bootloader_done's `out' block */
1474     libxl__domain_create_state *dcs = srs->dcs;
1475     STATE_AO_GC(dcs->ao);
1476     libxl_ctx *ctx = libxl__gc_owner(gc);
1477     char **vments = NULL, **localents = NULL;
1478     struct timeval start_time;
1479     int i, esave;
1480 
1481     /* convenience aliases */
1482     const uint32_t domid = dcs->guest_domid;
1483     libxl_domain_config *const d_config = dcs->guest_config;
1484     libxl_domain_build_info *const info = &d_config->b_info;
1485     libxl__domain_build_state *const state = &dcs->build_state;
1486     const int fd = dcs->restore_fd;
1487 
1488     if (ret)
1489         goto out;
1490 
1491     gettimeofday(&start_time, NULL);
1492 
1493     switch (info->type) {
1494     case LIBXL_DOMAIN_TYPE_HVM:
1495         vments = libxl__calloc(gc, 7, sizeof(char *));
1496         vments[0] = "rtc/timeoffset";
1497         vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
1498         vments[2] = "image/ostype";
1499         vments[3] = "hvm";
1500         vments[4] = "start_time";
1501         vments[5] = GCSPRINTF("%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
1502         break;
1503     case LIBXL_DOMAIN_TYPE_PV:
1504         vments = libxl__calloc(gc, 11, sizeof(char *));
1505         i = 0;
1506         vments[i++] = "image/ostype";
1507         vments[i++] = "linux";
1508         vments[i++] = "image/kernel";
1509         vments[i++] = (char *) state->pv_kernel.path;
1510         vments[i++] = "start_time";
1511         vments[i++] = GCSPRINTF("%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
1512         if (state->pv_ramdisk.path) {
1513             vments[i++] = "image/ramdisk";
1514             vments[i++] = (char *) state->pv_ramdisk.path;
1515         }
1516         if (state->pv_cmdline) {
1517             vments[i++] = "image/cmdline";
1518             vments[i++] = (char *) state->pv_cmdline;
1519         }
1520         break;
1521     case LIBXL_DOMAIN_TYPE_PVH:
1522         vments = libxl__calloc(gc, 3, sizeof(char *));
1523         vments[0] = "start_time";
1524         vments[1] = GCSPRINTF("%"PRIu64".%02ld",
1525                               (uint64_t)start_time.tv_sec,
1526                               (long)start_time.tv_usec/10000);
1527         break;
1528     default:
1529         ret = ERROR_INVAL;
1530         goto out;
1531     }
1532 
1533     /*
1534      * The scheduler on the sending domain may be different than the
1535      * scheduler running here.  Setting the scheduler to UNKNOWN will
1536      * cause the code to take to take whatever parameters are
1537      * available in that scheduler, while discarding the rest.
1538      */
1539     info->sched_params.sched = LIBXL_SCHEDULER_UNKNOWN;
1540 
1541     ret = libxl__build_post(gc, domid, info, state, vments, localents);
1542     if (ret)
1543         goto out;
1544 
1545     if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
1546         state->saved_state = GCSPRINTF(
1547                        LIBXL_DEVICE_MODEL_RESTORE_FILE".%d", domid);
1548     }
1549 
1550 out:
1551     if (info->type == LIBXL_DOMAIN_TYPE_PV) {
1552         libxl__file_reference_unmap(&state->pv_kernel);
1553         libxl__file_reference_unmap(&state->pv_ramdisk);
1554     }
1555 
1556     /* fd == -1 here means we're doing soft reset. */
1557     if (fd != -1) {
1558         esave = errno;
1559         libxl_fd_set_nonblock(ctx, fd, 0);
1560         errno = esave;
1561     }
1562     domcreate_rebuild_done(egc, dcs, ret);
1563 }
1564 
domcreate_rebuild_done(libxl__egc * egc,libxl__domain_create_state * dcs,int ret)1565 static void domcreate_rebuild_done(libxl__egc *egc,
1566                                    libxl__domain_create_state *dcs,
1567                                    int ret)
1568 {
1569     STATE_AO_GC(dcs->ao);
1570 
1571     /* convenience aliases */
1572     const uint32_t domid = dcs->guest_domid;
1573     libxl_domain_config *const d_config = dcs->guest_config;
1574 
1575     if (ret) {
1576         LOGD(ERROR, domid, "cannot (re-)build domain: %d", ret);
1577         ret = ERROR_FAIL;
1578         goto error_out;
1579     }
1580 
1581     store_libxl_entry(gc, domid, &d_config->b_info);
1582 
1583     libxl__multidev_begin(ao, &dcs->multidev);
1584     dcs->multidev.callback = domcreate_launch_dm;
1585     libxl__add_disks(egc, ao, domid, d_config, &dcs->multidev);
1586     libxl__multidev_prepared(egc, &dcs->multidev, 0);
1587 
1588     return;
1589 
1590  error_out:
1591     assert(ret);
1592     domcreate_complete(egc, dcs, ret);
1593 }
1594 
domcreate_launch_dm(libxl__egc * egc,libxl__multidev * multidev,int ret)1595 static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
1596                                 int ret)
1597 {
1598     libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
1599     STATE_AO_GC(dcs->ao);
1600     int i;
1601 
1602     /* convenience aliases */
1603     const uint32_t domid = dcs->guest_domid;
1604     libxl_domain_config *const d_config = dcs->guest_config;
1605     libxl__domain_build_state *const state = &dcs->build_state;
1606 
1607     if (ret) {
1608         LOGD(ERROR, domid, "unable to add disk devices");
1609         goto error_out;
1610     }
1611 
1612     for (i = 0; i < d_config->b_info.num_ioports; i++) {
1613         libxl_ioport_range *io = &d_config->b_info.ioports[i];
1614 
1615         LOGD(DEBUG, domid, "ioports %"PRIx32"-%"PRIx32,
1616              io->first, io->first + io->number - 1);
1617 
1618         ret = xc_domain_ioport_permission(CTX->xch, domid,
1619                                           io->first, io->number, 1);
1620         if (ret < 0) {
1621             LOGED(ERROR, domid,
1622                   "failed give domain access to ioports %"PRIx32"-%"PRIx32,
1623                   io->first, io->first + io->number - 1);
1624             ret = ERROR_FAIL;
1625             goto error_out;
1626         }
1627     }
1628 
1629     for (i = 0; i < d_config->b_info.num_irqs; i++) {
1630         int irq = d_config->b_info.irqs[i];
1631 
1632         LOGD(DEBUG, domid, "irq %d", irq);
1633 
1634         ret = irq >= 0 ? libxl__arch_domain_map_irq(gc, domid, irq)
1635                        : -EOVERFLOW;
1636         if (ret) {
1637             LOGED(ERROR, domid, "failed give domain access to irq %d", irq);
1638             ret = ERROR_FAIL;
1639             goto error_out;
1640         }
1641     }
1642 
1643     for (i = 0; i < d_config->b_info.num_iomem; i++) {
1644         libxl_iomem_range *io = &d_config->b_info.iomem[i];
1645 
1646         LOGD(DEBUG, domid, "iomem %"PRIx64"-%"PRIx64,
1647              io->start, io->start + io->number - 1);
1648 
1649         ret = xc_domain_iomem_permission(CTX->xch, domid,
1650                                           io->start, io->number, 1);
1651         if (ret < 0) {
1652             LOGED(ERROR, domid,
1653                   "failed give domain access to iomem range %"PRIx64"-%"PRIx64,
1654                   io->start, io->start + io->number - 1);
1655             ret = ERROR_FAIL;
1656             goto error_out;
1657         }
1658         ret = xc_domain_memory_mapping(CTX->xch, domid,
1659                                        io->gfn, io->start,
1660                                        io->number, 1);
1661         if (ret < 0) {
1662             LOGED(ERROR, domid,
1663                   "failed to map to domain iomem range %"PRIx64"-%"PRIx64
1664                   " to guest address %"PRIx64,
1665                   io->start, io->start + io->number - 1, io->gfn);
1666             ret = ERROR_FAIL;
1667             goto error_out;
1668         }
1669     }
1670 
1671     /* For both HVM and PV the 0th console is a regular console. We
1672        map channels to IOEMU consoles starting at 1 */
1673     for (i = 0; i < d_config->num_channels; i++) {
1674         libxl__device_console console;
1675         libxl__device device;
1676         ret = libxl__init_console_from_channel(gc, &console, i + 1,
1677                                                &d_config->channels[i]);
1678         if ( ret ) {
1679             libxl__device_console_dispose(&console);
1680             goto error_out;
1681         }
1682         libxl__device_console_add(gc, domid, &console, NULL, &device);
1683         libxl__device_console_dispose(&console);
1684     }
1685 
1686     for (i = 0; i < d_config->num_p9s; i++)
1687         libxl__device_add(gc, domid, &libxl__p9_devtype, &d_config->p9s[i]);
1688 
1689     for (i = 0; i < d_config->num_pvcallsifs; i++)
1690         libxl__device_add(gc, domid, &libxl__pvcallsif_devtype,
1691                           &d_config->pvcallsifs[i]);
1692 
1693     switch (d_config->c_info.type) {
1694     case LIBXL_DOMAIN_TYPE_HVM:
1695     {
1696         libxl__device_console console;
1697         libxl__device device;
1698         libxl_device_vkb vkb;
1699 
1700         init_console_info(gc, &console, 0);
1701         console.backend_domid = state->console_domid;
1702         libxl__device_console_add(gc, domid, &console, state, &device);
1703         libxl__device_console_dispose(&console);
1704 
1705         if (libxl_defbool_val(d_config->b_info.u.hvm.vkb_device)) {
1706             libxl_device_vkb_init(&vkb);
1707             libxl__device_add(gc, domid, &libxl__vkb_devtype, &vkb);
1708             libxl_device_vkb_dispose(&vkb);
1709         }
1710 
1711         dcs->sdss.dm.guest_domid = domid;
1712         if (libxl_defbool_val(d_config->b_info.device_model_stubdomain))
1713             libxl__spawn_stub_dm(egc, &dcs->sdss);
1714         else
1715             libxl__spawn_local_dm(egc, &dcs->sdss.dm);
1716 
1717         /*
1718          * Handle the domain's (and the related stubdomain's) access to
1719          * the VGA framebuffer.
1720          */
1721         ret = libxl__grant_vga_iomem_permission(gc, domid, d_config);
1722         if ( ret )
1723             goto error_out;
1724 
1725         return;
1726     }
1727     case LIBXL_DOMAIN_TYPE_PV:
1728     case LIBXL_DOMAIN_TYPE_PVH:
1729     {
1730         libxl__device_console console, vuart;
1731         libxl__device device;
1732 
1733         for (i = 0; i < d_config->num_vfbs; i++) {
1734             libxl__device_add(gc, domid, &libxl__vfb_devtype,
1735                               &d_config->vfbs[i]);
1736         }
1737 
1738         for (i = 0; i < d_config->num_vkbs; i++) {
1739             libxl__device_add(gc, domid, &libxl__vkb_devtype,
1740                               &d_config->vkbs[i]);
1741         }
1742 
1743         if (d_config->b_info.arch_arm.vuart == LIBXL_VUART_TYPE_SBSA_UART) {
1744             init_console_info(gc, &vuart, 0);
1745             vuart.backend_domid = state->console_domid;
1746             libxl__device_vuart_add(gc, domid, &vuart, state);
1747             libxl__device_console_dispose(&vuart);
1748         }
1749 
1750         init_console_info(gc, &console, 0);
1751         console.backend_domid = state->console_domid;
1752         libxl__device_console_add(gc, domid, &console, state, &device);
1753         libxl__device_console_dispose(&console);
1754 
1755         ret = libxl__need_xenpv_qemu(gc, d_config);
1756         if (ret < 0)
1757             goto error_out;
1758         if (ret) {
1759             dcs->sdss.dm.guest_domid = domid;
1760             libxl__spawn_local_dm(egc, &dcs->sdss.dm);
1761             return;
1762         } else {
1763             assert(!dcs->sdss.dm.guest_domid);
1764             domcreate_devmodel_started(egc, &dcs->sdss.dm, 0);
1765             return;
1766         }
1767     }
1768     default:
1769         ret = ERROR_INVAL;
1770         goto error_out;
1771     }
1772     abort(); /* not reached */
1773 
1774  error_out:
1775     assert(ret);
1776     domcreate_complete(egc, dcs, ret);
1777 }
1778 
libxl__add_dtdevs(libxl__egc * egc,libxl__ao * ao,uint32_t domid,libxl_domain_config * d_config,libxl__multidev * multidev)1779 static void libxl__add_dtdevs(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
1780                               libxl_domain_config *d_config,
1781                               libxl__multidev *multidev)
1782 {
1783     AO_GC;
1784     libxl__ao_device *aodev = libxl__multidev_prepare(multidev);
1785     int i, rc = 0;
1786 
1787     for (i = 0; i < d_config->num_dtdevs; i++) {
1788         const libxl_device_dtdev *dtdev = &d_config->dtdevs[i];
1789 
1790         LOGD(DEBUG, domid, "Assign device \"%s\" to domain", dtdev->path);
1791         rc = xc_assign_dt_device(CTX->xch, domid, dtdev->path);
1792         if (rc < 0) {
1793             LOGD(ERROR, domid, "xc_assign_dtdevice failed: %d", rc);
1794             goto out;
1795         }
1796     }
1797 
1798 out:
1799     aodev->rc = rc;
1800     aodev->callback(egc, aodev);
1801 }
1802 
1803 #define libxl_device_dtdev_list NULL
1804 #define libxl_device_dtdev_compare NULL
1805 #define libxl__device_from_dtdev NULL
1806 #define libxl__device_dtdev_setdefault NULL
1807 #define libxl__device_dtdev_update_devid NULL
1808 static DEFINE_DEVICE_TYPE_STRUCT(dtdev, NONE);
1809 
1810 const libxl__device_type *device_type_tbl[] = {
1811     &libxl__disk_devtype,
1812     &libxl__nic_devtype,
1813     &libxl__vtpm_devtype,
1814     &libxl__usbctrl_devtype,
1815     &libxl__usbdev_devtype,
1816     &libxl__pcidev_devtype,
1817     &libxl__dtdev_devtype,
1818     &libxl__vdispl_devtype,
1819     &libxl__vsnd_devtype,
1820     NULL
1821 };
1822 
domcreate_devmodel_started(libxl__egc * egc,libxl__dm_spawn_state * dmss,int ret)1823 static void domcreate_devmodel_started(libxl__egc *egc,
1824                                        libxl__dm_spawn_state *dmss,
1825                                        int ret)
1826 {
1827     libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, sdss.dm);
1828     STATE_AO_GC(dmss->spawn.ao);
1829     int domid = dcs->guest_domid;
1830 
1831     if (ret) {
1832         LOGD(ERROR, domid, "device model did not start: %d", ret);
1833         goto error_out;
1834     }
1835 
1836     dcs->device_type_idx = -1;
1837     domcreate_attach_devices(egc, &dcs->multidev, 0);
1838     return;
1839 
1840 error_out:
1841     assert(ret);
1842     domcreate_complete(egc, dcs, ret);
1843 }
1844 
domcreate_attach_devices(libxl__egc * egc,libxl__multidev * multidev,int ret)1845 static void domcreate_attach_devices(libxl__egc *egc,
1846                                      libxl__multidev *multidev,
1847                                      int ret)
1848 {
1849     libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
1850     STATE_AO_GC(dcs->ao);
1851     int domid = dcs->guest_domid;
1852     libxl_domain_config *const d_config = dcs->guest_config;
1853     const libxl__device_type *dt;
1854     char *tty_path;
1855 
1856     if (ret) {
1857         LOGD(ERROR, domid, "unable to add %s devices",
1858              libxl__device_kind_to_string(device_type_tbl[dcs->device_type_idx]->type));
1859         goto error_out;
1860     }
1861 
1862     dcs->device_type_idx++;
1863     dt = device_type_tbl[dcs->device_type_idx];
1864     if (dt) {
1865         if (*libxl__device_type_get_num(dt, d_config) > 0 && !dt->skip_attach) {
1866             /* Attach devices */
1867             libxl__multidev_begin(ao, &dcs->multidev);
1868             dcs->multidev.callback = domcreate_attach_devices;
1869             dt->add(egc, ao, domid, d_config, &dcs->multidev);
1870             libxl__multidev_prepared(egc, &dcs->multidev, 0);
1871             return;
1872         }
1873 
1874         domcreate_attach_devices(egc, &dcs->multidev, 0);
1875         return;
1876     }
1877 
1878     ret = libxl__console_tty_path(gc, domid, 0, LIBXL_CONSOLE_TYPE_PV, &tty_path);
1879     if (ret) {
1880         LOG(ERROR, "failed to get domain %d console tty path",
1881             domid);
1882         goto error_out;
1883     }
1884 
1885     dcs->console_xswait.ao = ao;
1886     dcs->console_xswait.what = GCSPRINTF("domain %d console tty", domid);
1887     dcs->console_xswait.path = tty_path;
1888     dcs->console_xswait.timeout_ms = LIBXL_INIT_TIMEOUT * 1000;
1889     dcs->console_xswait.callback = console_xswait_callback;
1890     ret = libxl__xswait_start(gc, &dcs->console_xswait);
1891     if (ret) {
1892         LOG(ERROR, "unable to set up watch for domain %d console tty path",
1893             domid);
1894         goto error_out;
1895     }
1896 
1897     return;
1898 
1899 error_out:
1900     assert(ret);
1901     domcreate_complete(egc, dcs, ret);
1902 }
1903 
console_xswait_callback(libxl__egc * egc,libxl__xswait_state * xswa,int rc,const char * p)1904 static void console_xswait_callback(libxl__egc *egc, libxl__xswait_state *xswa,
1905                                     int rc, const char *p)
1906 {
1907     EGC_GC;
1908     libxl__domain_create_state *dcs = CONTAINER_OF(xswa, *dcs, console_xswait);
1909 
1910     if (rc) {
1911         if (rc == ERROR_TIMEDOUT)
1912             LOG(ERROR, "%s: timed out", xswa->what);
1913         goto out;
1914     }
1915 
1916     if (p && p[0] != '\0') {
1917         domcreate_console_available(egc, dcs);
1918         goto out;
1919     }
1920 
1921     return;
1922 
1923 out:
1924     libxl__xswait_stop(gc, xswa);
1925     domcreate_complete(egc, dcs, rc);
1926 }
1927 
domcreate_complete(libxl__egc * egc,libxl__domain_create_state * dcs,int rc)1928 static void domcreate_complete(libxl__egc *egc,
1929                                libxl__domain_create_state *dcs,
1930                                int rc)
1931 {
1932     STATE_AO_GC(dcs->ao);
1933     libxl_domain_config *const d_config = dcs->guest_config;
1934     libxl_domain_config *d_config_saved = &dcs->guest_config_saved;
1935 
1936     libxl__xswait_stop(gc, &dcs->console_xswait);
1937 
1938     libxl__domain_build_state_dispose(&dcs->build_state);
1939 
1940     if (!rc && d_config->b_info.exec_ssidref)
1941         rc = xc_flask_relabel_domain(CTX->xch, dcs->guest_domid, d_config->b_info.exec_ssidref);
1942 
1943     bool retain_domain = !rc || rc == ERROR_ABORTED;
1944 
1945     if (retain_domain) {
1946         libxl__flock *lock;
1947 
1948         /* Note that we hold CTX lock at this point so only need to
1949          * take data store lock
1950          */
1951         lock = libxl__lock_domain_userdata(gc, dcs->guest_domid);
1952         if (!lock) {
1953             rc = ERROR_LOCK_FAIL;
1954         } else {
1955             libxl__update_domain_configuration(gc, d_config_saved, d_config);
1956             int cfg_rc = libxl__set_domain_configuration
1957                 (gc, dcs->guest_domid, d_config_saved);
1958             if (!rc)
1959                 rc = cfg_rc;
1960             libxl__unlock_file(lock);
1961         }
1962     }
1963 
1964     libxl_domain_config_dispose(d_config_saved);
1965 
1966     if (!retain_domain) {
1967         if (dcs->guest_domid > 0) {
1968             dcs->dds.ao = ao;
1969             dcs->dds.domid = dcs->guest_domid;
1970             dcs->dds.callback = domcreate_destruction_cb;
1971             libxl__domain_destroy(egc, &dcs->dds);
1972             return;
1973         }
1974         dcs->guest_domid = INVALID_DOMID;
1975     }
1976     dcs->callback(egc, dcs, rc, dcs->guest_domid);
1977 }
1978 
domcreate_destruction_cb(libxl__egc * egc,libxl__domain_destroy_state * dds,int rc)1979 static void domcreate_destruction_cb(libxl__egc *egc,
1980                                      libxl__domain_destroy_state *dds,
1981                                      int rc)
1982 {
1983     STATE_AO_GC(dds->ao);
1984     libxl__domain_create_state *dcs = CONTAINER_OF(dds, *dcs, dds);
1985 
1986     if (rc)
1987         LOGD(ERROR, dds->domid, "unable to destroy domain following failed creation");
1988 
1989     dcs->callback(egc, dcs, ERROR_FAIL, dcs->guest_domid);
1990 }
1991 
1992 /*----- application-facing domain creation interface -----*/
1993 
1994 typedef struct {
1995     libxl__domain_create_state dcs;
1996     uint32_t *domid_out;
1997 } libxl__app_domain_create_state;
1998 
1999 typedef struct {
2000     libxl__app_domain_create_state cdcs;
2001     libxl__domain_destroy_state dds;
2002     libxl__domain_save_state dss;
2003     char *toolstack_buf;
2004     uint32_t toolstack_len;
2005 } libxl__domain_soft_reset_state;
2006 
2007 static void domain_create_cb(libxl__egc *egc,
2008                              libxl__domain_create_state *dcs,
2009                              int rc, uint32_t domid);
2010 
do_domain_create(libxl_ctx * ctx,libxl_domain_config * d_config,uint32_t * domid,int restore_fd,int send_back_fd,const libxl_domain_restore_params * params,const libxl_asyncop_how * ao_how,const libxl_asyncprogress_how * aop_console_how)2011 static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
2012                             uint32_t *domid, int restore_fd, int send_back_fd,
2013                             const libxl_domain_restore_params *params,
2014                             const libxl_asyncop_how *ao_how,
2015                             const libxl_asyncprogress_how *aop_console_how)
2016 {
2017     AO_CREATE(ctx, 0, ao_how);
2018     libxl__app_domain_create_state *cdcs;
2019     int rc;
2020 
2021     GCNEW(cdcs);
2022     cdcs->dcs.ao = ao;
2023     cdcs->dcs.guest_config = d_config;
2024     libxl_domain_config_init(&cdcs->dcs.guest_config_saved);
2025     libxl_domain_config_copy(ctx, &cdcs->dcs.guest_config_saved, d_config);
2026     cdcs->dcs.restore_fd = cdcs->dcs.libxc_fd = restore_fd;
2027     cdcs->dcs.send_back_fd = send_back_fd;
2028     if (restore_fd >= 0) {
2029         cdcs->dcs.restore_params = *params;
2030         rc = libxl__fd_flags_modify_save(gc, cdcs->dcs.restore_fd,
2031                                          ~(O_NONBLOCK|O_NDELAY), 0,
2032                                          &cdcs->dcs.restore_fdfl);
2033         if (rc < 0) goto out_err;
2034     }
2035     cdcs->dcs.callback = domain_create_cb;
2036     cdcs->dcs.domid = INVALID_DOMID;
2037     cdcs->dcs.soft_reset = false;
2038 
2039     if (cdcs->dcs.restore_params.checkpointed_stream ==
2040         LIBXL_CHECKPOINTED_STREAM_COLO) {
2041         cdcs->dcs.colo_proxy_script =
2042             cdcs->dcs.restore_params.colo_proxy_script;
2043         cdcs->dcs.crs.cps.is_userspace_proxy =
2044             libxl_defbool_val(cdcs->dcs.restore_params.userspace_colo_proxy);
2045     } else {
2046         cdcs->dcs.colo_proxy_script = NULL;
2047         cdcs->dcs.crs.cps.is_userspace_proxy = false;
2048     }
2049 
2050     libxl__ao_progress_gethow(&cdcs->dcs.aop_console_how, aop_console_how);
2051     cdcs->domid_out = domid;
2052 
2053     initiate_domain_create(egc, &cdcs->dcs);
2054 
2055     return AO_INPROGRESS;
2056 
2057  out_err:
2058     return AO_CREATE_FAIL(rc);
2059 
2060 }
2061 
domain_soft_reset_cb(libxl__egc * egc,libxl__domain_destroy_state * dds,int rc)2062 static void domain_soft_reset_cb(libxl__egc *egc,
2063                                  libxl__domain_destroy_state *dds,
2064                                  int rc)
2065 {
2066     STATE_AO_GC(dds->ao);
2067     libxl__domain_soft_reset_state *srs = CONTAINER_OF(dds, *srs, dds);
2068     libxl__app_domain_create_state *cdcs = &srs->cdcs;
2069     char *savefile, *restorefile;
2070 
2071     if (rc) {
2072         LOGD(ERROR, dds->domid, "destruction of domain failed.");
2073         goto error;
2074     }
2075 
2076     cdcs->dcs.guest_domid = dds->domid;
2077     rc = libxl__restore_emulator_xenstore_data(&cdcs->dcs, srs->toolstack_buf,
2078                                                srs->toolstack_len);
2079     if (rc) {
2080         LOGD(ERROR, dds->domid, "failed to restore toolstack record.");
2081         goto error;
2082     }
2083 
2084     if (cdcs->dcs.guest_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM) {
2085         savefile = GCSPRINTF(LIBXL_DEVICE_MODEL_SAVE_FILE".%d", dds->domid);
2086         restorefile = GCSPRINTF(LIBXL_DEVICE_MODEL_RESTORE_FILE".%d",
2087                                 dds->domid);
2088         rc = rename(savefile, restorefile);
2089         if (rc) {
2090             LOGD(ERROR, dds->domid, "failed to rename dm save file.");
2091             goto error;
2092         }
2093     }
2094 
2095     initiate_domain_create(egc, &cdcs->dcs);
2096     return;
2097 
2098 error:
2099     domcreate_complete(egc, &cdcs->dcs, rc);
2100 }
2101 
2102 static void soft_reset_dm_suspended(libxl__egc *egc,
2103                                     libxl__domain_suspend_state *dsps,
2104                                     int rc);
do_domain_soft_reset(libxl_ctx * ctx,libxl_domain_config * d_config,uint32_t domid,const libxl_asyncop_how * ao_how,const libxl_asyncprogress_how * aop_console_how)2105 static int do_domain_soft_reset(libxl_ctx *ctx,
2106                                 libxl_domain_config *d_config,
2107                                 uint32_t domid,
2108                                 const libxl_asyncop_how *ao_how,
2109                                 const libxl_asyncprogress_how
2110                                 *aop_console_how)
2111 {
2112     AO_CREATE(ctx, 0, ao_how);
2113     libxl__domain_soft_reset_state *srs;
2114     libxl__app_domain_create_state *cdcs;
2115     libxl__domain_create_state *dcs;
2116     libxl__domain_build_state *state;
2117     libxl__domain_save_state *dss;
2118     const char *console_tty, *xs_store_mfn, *xs_console_mfn;
2119     char *dom_path;
2120     uint32_t domid_out;
2121     int rc;
2122 
2123     GCNEW(srs);
2124     cdcs = &srs->cdcs;
2125     dcs = &cdcs->dcs;
2126     state = &dcs->build_state;
2127     dss = &srs->dss;
2128 
2129     srs->cdcs.dcs.ao = ao;
2130     srs->cdcs.dcs.guest_config = d_config;
2131     libxl_domain_config_init(&srs->cdcs.dcs.guest_config_saved);
2132     libxl_domain_config_copy(ctx, &srs->cdcs.dcs.guest_config_saved,
2133                              d_config);
2134     cdcs->dcs.restore_fd = -1;
2135     cdcs->dcs.domid = domid;
2136     cdcs->dcs.soft_reset = true;
2137     cdcs->dcs.callback = domain_create_cb;
2138     libxl__ao_progress_gethow(&srs->cdcs.dcs.aop_console_how,
2139                               aop_console_how);
2140     cdcs->domid_out = &domid_out;
2141 
2142     dom_path = libxl__xs_get_dompath(gc, domid);
2143     if (!dom_path) {
2144         LOGD(ERROR, domid, "failed to read domain path");
2145         rc = ERROR_FAIL;
2146         goto out;
2147     }
2148 
2149     rc = libxl__xs_read_checked(gc, XBT_NULL,
2150                                 GCSPRINTF("%s/store/ring-ref", dom_path),
2151                                 &xs_store_mfn);
2152     if (rc) {
2153         LOGD(ERROR, domid, "failed to read store/ring-ref.");
2154         goto out;
2155     }
2156     state->store_mfn = xs_store_mfn ? atol(xs_store_mfn): 0;
2157 
2158     rc = libxl__xs_read_checked(gc, XBT_NULL,
2159                                 GCSPRINTF("%s/console/ring-ref", dom_path),
2160                                 &xs_console_mfn);
2161     if (rc) {
2162         LOGD(ERROR, domid, "failed to read console/ring-ref.");
2163         goto out;
2164     }
2165     state->console_mfn = xs_console_mfn ? atol(xs_console_mfn): 0;
2166 
2167     rc = libxl__xs_read_mandatory(gc, XBT_NULL,
2168                                   GCSPRINTF("%s/console/tty", dom_path),
2169                                   &console_tty);
2170     if (rc) {
2171         LOGD(ERROR, domid, "failed to read console/tty.");
2172         goto out;
2173     }
2174     state->console_tty = libxl__strdup(gc, console_tty);
2175 
2176     dss->ao = ao;
2177     dss->domid = dss->dsps.domid = domid;
2178     dss->dsps.dm_savefile = GCSPRINTF(LIBXL_DEVICE_MODEL_SAVE_FILE".%d",
2179                                       domid);
2180 
2181     rc = libxl__save_emulator_xenstore_data(dss, &srs->toolstack_buf,
2182                                             &srs->toolstack_len);
2183     if (rc) {
2184         LOGD(ERROR, domid, "failed to save toolstack record.");
2185         goto out;
2186     }
2187 
2188     dss->dsps.ao = ao;
2189     dss->dsps.callback_device_model_done = soft_reset_dm_suspended;
2190     libxl__domain_suspend_device_model(egc, &dss->dsps); /* must be last */
2191 
2192     return AO_INPROGRESS;
2193 
2194  out:
2195     return AO_CREATE_FAIL(rc);
2196 }
2197 
soft_reset_dm_suspended(libxl__egc * egc,libxl__domain_suspend_state * dsps,int rc)2198 static void soft_reset_dm_suspended(libxl__egc *egc,
2199                                     libxl__domain_suspend_state *dsps,
2200                                     int rc)
2201 {
2202     STATE_AO_GC(dsps->ao);
2203     libxl__domain_soft_reset_state *srs =
2204         CONTAINER_OF(dsps, *srs, dss.dsps);
2205     libxl__app_domain_create_state *cdcs = &srs->cdcs;
2206 
2207     /*
2208      * Ask all backends to disconnect by removing the domain from
2209      * xenstore. On the creation path the domain will be introduced to
2210      * xenstore again with probably different store/console/...
2211      * channels.
2212      */
2213     xs_release_domain(CTX->xsh, cdcs->dcs.domid);
2214 
2215     srs->dds.ao = ao;
2216     srs->dds.domid = cdcs->dcs.domid;
2217     srs->dds.callback = domain_soft_reset_cb;
2218     srs->dds.soft_reset = true;
2219     libxl__domain_destroy(egc, &srs->dds);
2220 }
2221 
domain_create_cb(libxl__egc * egc,libxl__domain_create_state * dcs,int rc,uint32_t domid)2222 static void domain_create_cb(libxl__egc *egc,
2223                              libxl__domain_create_state *dcs,
2224                              int rc, uint32_t domid)
2225 {
2226     libxl__app_domain_create_state *cdcs = CONTAINER_OF(dcs, *cdcs, dcs);
2227     int flrc;
2228     STATE_AO_GC(cdcs->dcs.ao);
2229 
2230     *cdcs->domid_out = domid;
2231 
2232     if (dcs->restore_fd >= 0) {
2233         flrc = libxl__fd_flags_restore(gc,
2234                 dcs->restore_fd, dcs->restore_fdfl);
2235         /*
2236          * If restore has failed already then report that error not
2237          * this one.
2238          */
2239         if (flrc && !rc) rc = flrc;
2240     }
2241 
2242     libxl__ao_complete(egc, ao, rc);
2243 }
2244 
2245 
set_disk_colo_restore(libxl_domain_config * d_config)2246 static void set_disk_colo_restore(libxl_domain_config *d_config)
2247 {
2248     int i;
2249 
2250     for (i = 0; i < d_config->num_disks; i++)
2251         libxl_defbool_set(&d_config->disks[i].colo_restore_enable, true);
2252 }
2253 
unset_disk_colo_restore(libxl_domain_config * d_config)2254 static void unset_disk_colo_restore(libxl_domain_config *d_config)
2255 {
2256     int i;
2257 
2258     for (i = 0; i < d_config->num_disks; i++)
2259         libxl_defbool_set(&d_config->disks[i].colo_restore_enable, false);
2260 }
2261 
libxl_domain_create_new(libxl_ctx * ctx,libxl_domain_config * d_config,uint32_t * domid,const libxl_asyncop_how * ao_how,const libxl_asyncprogress_how * aop_console_how)2262 int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
2263                             uint32_t *domid,
2264                             const libxl_asyncop_how *ao_how,
2265                             const libxl_asyncprogress_how *aop_console_how)
2266 {
2267     unset_disk_colo_restore(d_config);
2268     return do_domain_create(ctx, d_config, domid, -1, -1, NULL,
2269                             ao_how, aop_console_how);
2270 }
2271 
libxl_domain_create_restore(libxl_ctx * ctx,libxl_domain_config * d_config,uint32_t * domid,int restore_fd,int send_back_fd,const libxl_domain_restore_params * params,const libxl_asyncop_how * ao_how,const libxl_asyncprogress_how * aop_console_how)2272 int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
2273                                 uint32_t *domid, int restore_fd,
2274                                 int send_back_fd,
2275                                 const libxl_domain_restore_params *params,
2276                                 const libxl_asyncop_how *ao_how,
2277                                 const libxl_asyncprogress_how *aop_console_how)
2278 {
2279     if (params->checkpointed_stream == LIBXL_CHECKPOINTED_STREAM_COLO) {
2280         set_disk_colo_restore(d_config);
2281     } else {
2282         unset_disk_colo_restore(d_config);
2283     }
2284 
2285     return do_domain_create(ctx, d_config, domid, restore_fd, send_back_fd,
2286                             params, ao_how, aop_console_how);
2287 }
2288 
libxl_domain_soft_reset(libxl_ctx * ctx,libxl_domain_config * d_config,uint32_t domid,const libxl_asyncop_how * ao_how,const libxl_asyncprogress_how * aop_console_how)2289 int libxl_domain_soft_reset(libxl_ctx *ctx,
2290                             libxl_domain_config *d_config,
2291                             uint32_t domid,
2292                             const libxl_asyncop_how *ao_how,
2293                             const libxl_asyncprogress_how
2294                             *aop_console_how)
2295 {
2296     libxl_domain_build_info *const info = &d_config->b_info;
2297 
2298     if (info->type != LIBXL_DOMAIN_TYPE_HVM) return ERROR_INVAL;
2299 
2300     return do_domain_soft_reset(ctx, d_config, domid, ao_how,
2301                                 aop_console_how);
2302 }
2303 
2304 /*
2305  * Local variables:
2306  * mode: C
2307  * c-basic-offset: 4
2308  * indent-tabs-mode: nil
2309  * End:
2310  */
2311