libxl_create.c 22.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright (C) 2010      Citrix Ltd.
 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
 * Author Gianni Tedesco <gianni.tedesco@citrix.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; version 2.1 only. with the special
 * exception on linking described in file LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 */

#include "libxl_osdeps.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
25 26 27
#include <xenctrl.h>
#include <xc_dom.h>
#include <xenguest.h>
28
#include <assert.h>
29 30 31 32 33
#include "libxl.h"
#include "libxl_utils.h"
#include "libxl_internal.h"
#include "flexarray.h"

34
void libxl_domain_config_dispose(libxl_domain_config *d_config)
35 36 37 38
{
    int i;

    for (i=0; i<d_config->num_disks; i++)
39
        libxl_device_disk_dispose(&d_config->disks[i]);
40 41 42
    free(d_config->disks);

    for (i=0; i<d_config->num_vifs; i++)
43
        libxl_device_nic_dispose(&d_config->vifs[i]);
44 45 46
    free(d_config->vifs);

    for (i=0; i<d_config->num_pcidevs; i++)
47
        libxl_device_pci_dispose(&d_config->pcidevs[i]);
48 49 50
    free(d_config->pcidevs);

    for (i=0; i<d_config->num_vfbs; i++)
51
        libxl_device_vfb_dispose(&d_config->vfbs[i]);
52 53 54
    free(d_config->vfbs);

    for (i=0; i<d_config->num_vkbs; i++)
55
        libxl_device_vkb_dispose(&d_config->vkbs[i]);
56 57
    free(d_config->vkbs);

58 59 60
    libxl_domain_create_info_dispose(&d_config->c_info);
    libxl_domain_build_info_dispose(&d_config->b_info);
    libxl_device_model_info_dispose(&d_config->dm_info);
61 62
}

63
int libxl_init_create_info(libxl_ctx *ctx, libxl_domain_create_info *c_info)
64 65 66 67 68
{
    memset(c_info, '\0', sizeof(*c_info));
    c_info->xsdata = NULL;
    c_info->platformdata = NULL;
    c_info->hap = 1;
69
    c_info->type = LIBXL_DOMAIN_TYPE_HVM;
70 71 72
    c_info->oos = 1;
    c_info->ssidref = 0;
    c_info->poolid = 0;
73
    return 0;
74 75
}

76 77 78
int libxl_init_build_info(libxl_ctx *ctx,
                          libxl_domain_build_info *b_info,
                          libxl_domain_create_info *c_info)
79 80 81
{
    memset(b_info, '\0', sizeof(*b_info));
    b_info->max_vcpus = 1;
82
    b_info->cur_vcpus = 1;
83 84 85 86 87
    b_info->max_memkb = 32 * 1024;
    b_info->target_memkb = b_info->max_memkb;
    b_info->disable_migrate = 0;
    b_info->cpuid = NULL;
    b_info->shadow_memkb = 0;
88 89 90
    b_info->type = c_info->type;
    switch (b_info->type) {
    case LIBXL_DOMAIN_TYPE_HVM:
91
        b_info->video_memkb = 8 * 1024;
92
        b_info->u.hvm.firmware = NULL;
93 94 95
        b_info->u.hvm.pae = 1;
        b_info->u.hvm.apic = 1;
        b_info->u.hvm.acpi = 1;
96 97
        b_info->u.hvm.acpi_s3 = 1;
        b_info->u.hvm.acpi_s4 = 1;
98 99 100 101 102
        b_info->u.hvm.nx = 1;
        b_info->u.hvm.viridian = 0;
        b_info->u.hvm.hpet = 1;
        b_info->u.hvm.vpt_align = 1;
        b_info->u.hvm.timer_mode = 1;
103
        b_info->u.hvm.nested_hvm = 0;
104 105
        break;
    case LIBXL_DOMAIN_TYPE_PV:
106
        b_info->u.pv.slack_memkb = 8 * 1024;
107 108 109 110 111 112
        break;
    default:
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                   "invalid domain type %s in create info",
                   libxl_domain_type_to_string(b_info->type));
        return ERROR_INVAL;
113
    }
114
    return 0;
115 116
}

117 118 119 120
int libxl_init_dm_info(libxl_ctx *ctx,
                       libxl_device_model_info *dm_info,
                       libxl_domain_create_info *c_info,
                       libxl_domain_build_info *b_info)
121 122 123 124 125 126
{
    memset(dm_info, '\0', sizeof(*dm_info));

    libxl_uuid_generate(&dm_info->uuid);

    dm_info->dom_name = strdup(c_info->name);
127 128 129
    dm_info->device_model_version = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
    dm_info->device_model_stubdomain = false;
    dm_info->device_model = NULL;
130 131
    dm_info->target_ram = libxl__sizekb_to_mb(b_info->target_memkb);
    dm_info->videoram = libxl__sizekb_to_mb(b_info->video_memkb);
Ian Jackson's avatar
Ian Jackson committed
132
    dm_info->acpi = b_info->u.hvm.acpi;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    dm_info->vcpus = b_info->max_vcpus;
    dm_info->vcpu_avail = b_info->cur_vcpus;

    dm_info->stdvga = 0;
    dm_info->vnc = 1;
    dm_info->vnclisten = strdup("127.0.0.1");
    dm_info->vncdisplay = 0;
    dm_info->vncunused = 1;
    dm_info->keymap = NULL;
    dm_info->sdl = 0;
    dm_info->opengl = 0;
    dm_info->nographic = 0;
    dm_info->serial = NULL;
    dm_info->boot = strdup("cda");
    dm_info->usb = 0;
    dm_info->usbdevice = NULL;
    dm_info->xen_platform_pci = 1;
150
    return 0;
151 152
}

153
static int init_console_info(libxl_device_console *console, int dev_num)
154 155 156
{
    memset(console, 0x00, sizeof(libxl_device_console));
    console->devid = dev_num;
157
    console->consback = LIBXL_CONSOLE_BACKEND_XENCONSOLED;
158 159 160 161 162 163
    console->output = strdup("pty");
    if ( NULL == console->output )
        return ERROR_NOMEM;
    return 0;
}

164 165 166 167 168
int libxl__domain_build(libxl__gc *gc,
                        libxl_domain_build_info *info,
                        libxl_device_model_info *dm_info,
                        uint32_t domid,
                        libxl__domain_build_state *state)
169 170 171 172 173
{
    char **vments = NULL, **localents = NULL;
    struct timeval start_time;
    int i, ret;

174
    ret = libxl__build_pre(gc, domid, info, state);
175 176 177 178 179
    if (ret)
        goto out;

    gettimeofday(&start_time, NULL);

180 181
    switch (info->type) {
    case LIBXL_DOMAIN_TYPE_HVM:
182
        ret = libxl__build_hvm(gc, domid, info, dm_info, state);
183 184 185
        if (ret)
            goto out;

186
        vments = libxl__calloc(gc, 7, sizeof(char *));
187 188 189 190 191
        vments[0] = "rtc/timeoffset";
        vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
        vments[2] = "image/ostype";
        vments[3] = "hvm";
        vments[4] = "start_time";
192
        vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
193

194
        localents = libxl__calloc(gc, 7, sizeof(char *));
195 196
        localents[0] = "platform/acpi";
        localents[1] = (info->u.hvm.acpi) ? "1" : "0";
197 198 199 200
        localents[2] = "platform/acpi_s3";
        localents[3] = (info->u.hvm.acpi_s3) ? "1" : "0";
        localents[4] = "platform/acpi_s4";
        localents[5] = (info->u.hvm.acpi_s4) ? "1" : "0";
201

202 203
        break;
    case LIBXL_DOMAIN_TYPE_PV:
204
        ret = libxl__build_pv(gc, domid, info, state);
205 206 207
        if (ret)
            goto out;

208
        vments = libxl__calloc(gc, 11, sizeof(char *));
209 210 211 212
        i = 0;
        vments[i++] = "image/ostype";
        vments[i++] = "linux";
        vments[i++] = "image/kernel";
213
        vments[i++] = (char*) info->u.pv.kernel.path;
214
        vments[i++] = "start_time";
215
        vments[i++] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
216 217 218 219 220 221 222 223
        if (info->u.pv.ramdisk.path) {
            vments[i++] = "image/ramdisk";
            vments[i++] = (char*) info->u.pv.ramdisk.path;
        }
        if (info->u.pv.cmdline) {
            vments[i++] = "image/cmdline";
            vments[i++] = (char*) info->u.pv.cmdline;
        }
224 225 226 227
        break;
    default:
        ret = ERROR_INVAL;
        goto out;
228
    }
229
    ret = libxl__build_post(gc, domid, info, state, vments, localents);
230 231 232 233
out:
    return ret;
}

234
static int domain_restore(libxl__gc *gc, libxl_domain_build_info *info,
235 236
                          uint32_t domid, int fd,
                          libxl__domain_build_state *state,
237
                          libxl_device_model_info *dm_info)
238
{
239
    libxl_ctx *ctx = libxl__gc_owner(gc);
240 241 242 243
    char **vments = NULL, **localents = NULL;
    struct timeval start_time;
    int i, ret, esave, flags;

244
    ret = libxl__build_pre(gc, domid, info, state);
245 246 247
    if (ret)
        goto out;

248
    ret = libxl__domain_restore_common(gc, domid, info, state, fd);
249 250 251 252 253
    if (ret)
        goto out;

    gettimeofday(&start_time, NULL);

254 255
    switch (info->type) {
    case LIBXL_DOMAIN_TYPE_HVM:
256
        vments = libxl__calloc(gc, 7, sizeof(char *));
257 258 259 260 261
        vments[0] = "rtc/timeoffset";
        vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
        vments[2] = "image/ostype";
        vments[3] = "hvm";
        vments[4] = "start_time";
262
        vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
263 264
        break;
    case LIBXL_DOMAIN_TYPE_PV:
265
        vments = libxl__calloc(gc, 11, sizeof(char *));
266 267 268 269
        i = 0;
        vments[i++] = "image/ostype";
        vments[i++] = "linux";
        vments[i++] = "image/kernel";
270
        vments[i++] = (char*) info->u.pv.kernel.path;
271
        vments[i++] = "start_time";
272
        vments[i++] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
273 274 275 276 277 278 279 280
        if (info->u.pv.ramdisk.path) {
            vments[i++] = "image/ramdisk";
            vments[i++] = (char*) info->u.pv.ramdisk.path;
        }
        if (info->u.pv.cmdline) {
            vments[i++] = "image/cmdline";
            vments[i++] = (char*) info->u.pv.cmdline;
        }
281 282 283 284
        break;
    default:
        ret = ERROR_INVAL;
        goto out;
285
    }
286
    ret = libxl__build_post(gc, domid, info, state, vments, localents);
287 288 289 290
    if (ret)
        goto out;

    dm_info->saved_state = NULL;
291
    if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
292
        ret = asprintf(&dm_info->saved_state,
293
                       XC_DEVICE_MODEL_RESTORE_FILE".%d", domid);
294 295 296 297
        ret = (ret < 0) ? ERROR_FAIL : 0;
    }

out:
298
    if (info->type == LIBXL_DOMAIN_TYPE_PV) {
299 300 301
        libxl__file_reference_unmap(&info->u.pv.kernel);
        libxl__file_reference_unmap(&info->u.pv.ramdisk);
    }
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

    esave = errno;

    flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get flags on restore fd");
    } else {
        flags &= ~O_NONBLOCK;
        if (fcntl(fd, F_SETFL, flags) == -1)
            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to put restore fd"
                         " back to blocking mode");
    }

    errno = esave;
    return ret;
}

319
int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info,
320
                       uint32_t *domid)
321 322
 /* on entry, libxl_domid_valid_guest(domid) must be false;
  * on exit (even error exit), domid may be valid and refer to a domain */
323
{
324
    libxl_ctx *ctx = libxl__gc_owner(gc);
325 326
    int flags, ret, i, rc;
    char *uuid_string;
327
    char *rw_paths[] = { "control/shutdown", "device", "device/suspend/event-channel" , "data"};
328 329
    char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
                         "control", "attr", "messages" };
330
    char *dom_path, *vm_path, *libxl_path;
331 332
    struct xs_permissions roperm[2];
    struct xs_permissions rwperm[1];
333
    struct xs_permissions noperm[1];
334
    xs_transaction_t t = 0;
335 336
    xen_domain_handle_t handle;

337

338 339
    assert(!libxl_domid_valid_guest(*domid));

340
    uuid_string = libxl__uuid2string(gc, info->uuid);
341
    if (!uuid_string) {
342 343
        rc = ERROR_NOMEM;
        goto out;
344 345
    }

346 347 348 349 350 351
    flags = 0;
    if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
        flags |= XEN_DOMCTL_CDF_hvm_guest;
        flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
        flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
    }
352 353 354 355 356 357 358 359
    *domid = -1;

    /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
    libxl_uuid_copy((libxl_uuid *)handle, &info->uuid);

    ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
    if (ret < 0) {
        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail");
360 361
        rc = ERROR_FAIL;
        goto out;
362 363 364 365 366
    }

    ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
    if (ret < 0) {
        LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail");
367 368
        rc = ERROR_FAIL;
        goto out;
369 370
    }

371
    dom_path = libxl__xs_get_dompath(gc, *domid);
372
    if (!dom_path) {
373 374
        rc = ERROR_FAIL;
        goto out;
375 376
    }

377
    vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string);
378 379
    if (!vm_path) {
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
380 381
        rc = ERROR_FAIL;
        goto out;
382 383
    }

384 385 386 387 388 389 390 391
    libxl_path = libxl__xs_libxl_path(gc, *domid);
    if (!libxl_path) {
        rc = ERROR_FAIL;
        goto out;
    }
    noperm[0].id = 0;
    noperm[0].perms = XS_PERM_NONE;

392 393 394 395 396 397 398 399 400
    roperm[0].id = 0;
    roperm[0].perms = XS_PERM_NONE;
    roperm[1].id = *domid;
    roperm[1].perms = XS_PERM_READ;
    rwperm[0].id = *domid;
    rwperm[0].perms = XS_PERM_NONE;

retry_transaction:
    t = xs_transaction_start(ctx->xsh);
401

402 403 404 405 406 407 408 409
    xs_rm(ctx->xsh, t, dom_path);
    xs_mkdir(ctx->xsh, t, dom_path);
    xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));

    xs_rm(ctx->xsh, t, vm_path);
    xs_mkdir(ctx->xsh, t, vm_path);
    xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));

410 411 412 413
    xs_rm(ctx->xsh, t, libxl_path);
    xs_mkdir(ctx->xsh, t, libxl_path);
    xs_set_permissions(ctx->xsh, t, libxl_path, noperm, ARRAY_SIZE(noperm));

414
    xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
415
    rc = libxl__domain_rename(gc, *domid, 0, info->name, t);
416 417
    if (rc)
        goto out;
418 419

    for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
420
        char *path = libxl__sprintf(gc, "%s/%s", dom_path, rw_paths[i]);
421 422 423 424
        xs_mkdir(ctx->xsh, t, path);
        xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
    }
    for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
425
        char *path = libxl__sprintf(gc, "%s/%s", dom_path, ro_paths[i]);
426 427 428 429
        xs_mkdir(ctx->xsh, t, path);
        xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
    }

430 431
    xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
    xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name));
432
    if (info->poolname)
433
        xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/pool_name", vm_path), info->poolname, strlen(info->poolname));
434

435 436
    libxl__xs_writev(gc, t, dom_path, info->xsdata);
    libxl__xs_writev(gc, t, libxl__sprintf(gc, "%s/platform", dom_path), info->platformdata);
437

438
    xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
439 440 441
    if (!xs_transaction_end(ctx->xsh, t, 0)) {
        if (errno == EAGAIN) {
            t = 0;
442
            goto retry_transaction;
443 444 445 446 447 448 449
        }
        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "domain creation "
                         "xenstore transaction commit failed");
        rc = ERROR_FAIL;
        goto out;
    }
    t = 0;
450

451 452 453 454
    rc = 0;
 out:
    if (t) xs_transaction_end(ctx->xsh, t, 1);
    return rc;
455 456
}

457 458 459 460 461 462 463 464 465 466 467
static int store_libxl_entry(libxl__gc *gc, uint32_t domid,
                             libxl_device_model_info *dm_info)
{
    char *path = NULL;

    path = libxl__xs_libxl_path(gc, domid);
    path = libxl__sprintf(gc, "%s/dm-version", path);
    return libxl__xs_write(gc, XBT_NULL, path, libxl__strdup(gc,
        libxl_device_model_version_to_string(dm_info->device_model_version)));
}

468
static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
469 470 471
                            libxl_console_ready cb, void *priv,
                            uint32_t *domid_out, int restore_fd)
{
472
    libxl_ctx *ctx = libxl__gc_owner(gc);
473
    libxl__spawner_starting *dm_starting = 0;
474
    libxl_device_model_info *dm_info = &d_config->dm_info;
475
    libxl__domain_build_state state;
476 477 478 479 480
    uint32_t domid;
    int i, ret;

    domid = 0;

481
    ret = libxl__domain_make(gc, &d_config->c_info, &domid);
482
    if (ret) {
483
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot make domain: %d", ret);
484 485 486 487
        ret = ERROR_FAIL;
        goto error_out;
    }

488
    if ( d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV && cb ) {
489 490 491 492
        if ( (*cb)(ctx, domid, priv) )
            goto error_out;
    }

493 494 495 496 497 498

    for (i = 0; i < d_config->num_disks; i++) {
        ret = libxl__device_disk_set_backend(gc, &d_config->disks[i]);
        if (ret) goto error_out;
    }

499 500 501
    if ( restore_fd < 0 ) {
        ret = libxl_run_bootloader(ctx, &d_config->b_info, d_config->num_disks > 0 ? &d_config->disks[0] : NULL, domid);
        if (ret) {
502 503
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "failed to run bootloader: %d", ret);
504 505 506 507 508
            goto error_out;
        }
    }

    if ( restore_fd >= 0 ) {
509
        ret = domain_restore(gc, &d_config->b_info, domid, restore_fd, &state, dm_info);
510 511 512 513 514
    } else {
        if (dm_info->saved_state) {
            free(dm_info->saved_state);
            dm_info->saved_state = NULL;
        }
515
        ret = libxl__domain_build(gc, &d_config->b_info, dm_info, domid, &state);
516 517 518
    }

    if (ret) {
519
        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot (re-)build domain: %d", ret);
520 521 522 523
        ret = ERROR_FAIL;
        goto error_out;
    }

524 525
    store_libxl_entry(gc, domid, dm_info);

526 527 528
    for (i = 0; i < d_config->num_disks; i++) {
        ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]);
        if (ret) {
529 530
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "cannot add disk %d to domain: %d", i, ret);
531 532 533 534 535 536 537
            ret = ERROR_FAIL;
            goto error_out;
        }
    }
    for (i = 0; i < d_config->num_vifs; i++) {
        ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
        if (ret) {
538 539
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "cannot add nic %d to domain: %d", i, ret);
540 541 542 543
            ret = ERROR_FAIL;
            goto error_out;
        }
    }
544 545 546
    switch (d_config->c_info.type) {
    case LIBXL_DOMAIN_TYPE_HVM:
    {
547
        libxl_device_console console;
548
        libxl_device_vkb vkb;
549

550
        ret = init_console_info(&console, 0);
551 552
        if ( ret )
            goto error_out;
553
        libxl__device_console_add(gc, domid, &console, &state);
554
        libxl_device_console_dispose(&console);
555

556 557 558 559 560 561
        ret = libxl_device_vkb_init(ctx, &vkb);
        if ( ret )
            goto error_out;
        libxl_device_vkb_add(ctx, domid, &vkb);
        libxl_device_vkb_dispose(&vkb);

562
        dm_info->domid = domid;
563
        ret = libxl__create_device_model(gc, dm_info,
564 565 566 567
                                        d_config->disks, d_config->num_disks,
                                        d_config->vifs, d_config->num_vifs,
                                        &dm_starting);
        if (ret < 0) {
568 569
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "failed to create device model: %d", ret);
570 571
            goto error_out;
        }
572 573 574 575
        break;
    }
    case LIBXL_DOMAIN_TYPE_PV:
    {
576 577
        int need_qemu = 0;
        libxl_device_console console;
578
        libxl_device_model_info xenpv_dm_info;
579 580 581 582 583 584

        for (i = 0; i < d_config->num_vfbs; i++) {
            libxl_device_vfb_add(ctx, domid, &d_config->vfbs[i]);
            libxl_device_vkb_add(ctx, domid, &d_config->vkbs[i]);
        }

585
        ret = init_console_info(&console, 0);
586 587 588
        if ( ret )
            goto error_out;

589
        need_qemu = libxl__need_xenpv_qemu(gc, 1, &console,
590 591 592 593
                d_config->num_vfbs, d_config->vfbs,
                d_config->num_disks, &d_config->disks[0]);

        if (need_qemu)
594
             console.consback = LIBXL_CONSOLE_BACKEND_IOEMU;
595

596
        libxl__device_console_add(gc, domid, &console, &state);
597
        libxl_device_console_dispose(&console);
598

599 600 601 602 603 604 605 606 607 608 609 610 611 612
        if (need_qemu) {
            /* only copy those useful configs */
            memset((void*)&xenpv_dm_info, 0, sizeof(libxl_device_model_info));
            xenpv_dm_info.device_model_version =
                d_config->dm_info.device_model_version;
            xenpv_dm_info.type = d_config->dm_info.type;
            xenpv_dm_info.device_model = d_config->dm_info.device_model;
            xenpv_dm_info.extra = d_config->dm_info.extra;
            xenpv_dm_info.extra_pv = d_config->dm_info.extra_pv;
            xenpv_dm_info.extra_hvm = d_config->dm_info.extra_hvm;

            libxl__create_xenpv_qemu(gc, domid, &xenpv_dm_info,
                                     d_config->vfbs, &dm_starting);
        }
613 614 615 616 617
        break;
    }
    default:
        ret = ERROR_INVAL;
        goto error_out;
618 619 620
    }

    if (dm_starting) {
Anthony PERARD's avatar
Anthony PERARD committed
621 622 623 624
        if (dm_info->device_model_version
            == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN) {
            libxl__qmp_initializations(ctx, domid);
        }
625
        ret = libxl__confirm_device_model_startup(gc, dm_starting);
626
        if (ret < 0) {
627 628
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                       "device model did not start: %d", ret);
629 630 631 632 633
            goto error_out;
        }
    }

    for (i = 0; i < d_config->num_pcidevs; i++)
634
        libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);
635

636 637 638 639 640 641 642 643
    if (d_config->num_pcidevs > 0) {
        ret = libxl__create_pci_backend(gc, domid, d_config->pcidevs,
            d_config->num_pcidevs);
        if (ret < 0) {
            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
                "libxl_create_pci_backend failed: %d", ret);
            goto error_out;
        }
644 645
    }

646 647
    if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV &&
        d_config->b_info.u.pv.e820_host) {
648
        int rc;
649
        rc = libxl__e820_alloc(gc, domid, d_config);
650 651 652 653 654
        if (rc)
            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
                      "Failed while collecting E820 with: %d (errno:%d)\n",
                      rc, errno);
    }
655 656 657
    if ( cb && (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM ||
                (d_config->c_info.type == LIBXL_DOMAIN_TYPE_PV &&
                 d_config->b_info.u.pv.bootloader ))) {
658 659 660 661 662 663 664 665 666 667 668 669 670
        if ( (*cb)(ctx, domid, priv) )
            goto error_out;
    }

    *domid_out = domid;
    return 0;

error_out:
    if (domid)
        libxl_domain_destroy(ctx, domid, 0);

    return ret;
}
671

672 673 674
int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
                            libxl_console_ready cb, void *priv, uint32_t *domid)
{
675 676 677 678 679
    libxl__gc gc = LIBXL_INIT_GC(ctx);
    int rc;
    rc = do_domain_create(&gc, d_config, cb, priv, domid, -1);
    libxl__free_all(&gc);
    return rc;
680 681 682 683 684
}

int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
                                libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd)
{
685 686 687 688 689
    libxl__gc gc = LIBXL_INIT_GC(ctx);
    int rc;
    rc = do_domain_create(&gc, d_config, cb, priv, domid, restore_fd);
    libxl__free_all(&gc);
    return rc;
690
}
691 692 693 694 695 696 697 698

/*
 * Local variables:
 * mode: C
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 */