Commit 9306acb50991b7c78510ff4ffe19a190f2fc89c0

Authored by aliguori
1 parent 2c8b24a3

xen: pv domain builder. (Gerd Hoffmann)

This adds domain building support for paravirtual domains to qemu.
This allows booting xen guests directly with qemu, without Xend
and the management stack.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7226 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -561,7 +561,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
561 561 endif
562 562  
563 563 # xen backend driver support
564   -XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
  564 +XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
565 565 XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
566 566 ifeq ($(CONFIG_XEN), yes)
567 567 OBJS += $(XEN_OBJS)
... ...
configure
... ... @@ -1634,7 +1634,7 @@ if test &quot;$bluez&quot; = &quot;yes&quot; ; then
1634 1634 echo "#define CONFIG_BLUEZ 1" >> $config_h
1635 1635 fi
1636 1636 if test "$xen" = "yes" ; then
1637   - echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
  1637 + echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak
1638 1638 fi
1639 1639 if test "$aio" = "yes" ; then
1640 1640 echo "#define CONFIG_AIO 1" >> $config_h
... ...
hw/xen_backend.h
... ... @@ -100,5 +100,8 @@ void xen_init_display(int domid);
100 100 void xen_config_cleanup(void);
101 101 int xen_config_dev_blk(DriveInfo *disk);
102 102 int xen_config_dev_nic(NICInfo *nic);
  103 +int xen_config_dev_vfb(int vdev, const char *type);
  104 +int xen_config_dev_vkbd(int vdev);
  105 +int xen_config_dev_console(int vdev);
103 106  
104 107 #endif /* QEMU_HW_XEN_BACKEND_H */
... ...
hw/xen_devconfig.c
... ... @@ -140,3 +140,32 @@ int xen_config_dev_nic(NICInfo *nic)
140 140 /* common stuff */
141 141 return xen_config_dev_all(fe, be);
142 142 }
  143 +
  144 +int xen_config_dev_vfb(int vdev, const char *type)
  145 +{
  146 + char fe[256], be[256];
  147 +
  148 + xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
  149 +
  150 + /* backend */
  151 + xenstore_write_str(be, "type", type);
  152 +
  153 + /* common stuff */
  154 + return xen_config_dev_all(fe, be);
  155 +}
  156 +
  157 +int xen_config_dev_vkbd(int vdev)
  158 +{
  159 + char fe[256], be[256];
  160 +
  161 + xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
  162 + return xen_config_dev_all(fe, be);
  163 +}
  164 +
  165 +int xen_config_dev_console(int vdev)
  166 +{
  167 + char fe[256], be[256];
  168 +
  169 + xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
  170 + return xen_config_dev_all(fe, be);
  171 +}
... ...
hw/xen_domainbuild.c 0 → 100644
  1 +#include <signal.h>
  2 +#include "xen_backend.h"
  3 +#include "xen_domainbuild.h"
  4 +#include "sysemu.h"
  5 +#include "qemu-timer.h"
  6 +
  7 +#include <xenguest.h>
  8 +
  9 +static int xenstore_domain_mkdir(char *path)
  10 +{
  11 + struct xs_permissions perms_ro[] = {{
  12 + .id = 0, /* set owner: dom0 */
  13 + },{
  14 + .id = xen_domid,
  15 + .perms = XS_PERM_READ,
  16 + }};
  17 + struct xs_permissions perms_rw[] = {{
  18 + .id = 0, /* set owner: dom0 */
  19 + },{
  20 + .id = xen_domid,
  21 + .perms = XS_PERM_READ | XS_PERM_WRITE,
  22 + }};
  23 + const char *writable[] = { "device", "control", "error", NULL };
  24 + char subpath[256];
  25 + int i;
  26 +
  27 + if (!xs_mkdir(xenstore, 0, path)) {
  28 + fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
  29 + return -1;
  30 + }
  31 + if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
  32 + fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
  33 + return -1;
  34 + }
  35 +
  36 + for (i = 0; writable[i]; i++) {
  37 + snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
  38 + if (!xs_mkdir(xenstore, 0, subpath)) {
  39 + fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
  40 + return -1;
  41 + }
  42 + if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
  43 + fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
  44 + return -1;
  45 + }
  46 + }
  47 + return 0;
  48 +}
  49 +
  50 +int xenstore_domain_init1(const char *kernel, const char *ramdisk,
  51 + const char *cmdline)
  52 +{
  53 + char *dom, uuid_string[42], vm[256], path[256];
  54 + int i;
  55 +
  56 + snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
  57 + qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
  58 + qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
  59 + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
  60 + qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
  61 + dom = xs_get_domain_path(xenstore, xen_domid);
  62 + snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
  63 +
  64 + xenstore_domain_mkdir(dom);
  65 +
  66 + xenstore_write_str(vm, "image/ostype", "linux");
  67 + if (kernel)
  68 + xenstore_write_str(vm, "image/kernel", kernel);
  69 + if (ramdisk)
  70 + xenstore_write_str(vm, "image/ramdisk", ramdisk);
  71 + if (cmdline)
  72 + xenstore_write_str(vm, "image/cmdline", cmdline);
  73 +
  74 + /* name + id */
  75 + xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
  76 + xenstore_write_str(vm, "uuid", uuid_string);
  77 + xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
  78 + xenstore_write_int(dom, "domid", xen_domid);
  79 + xenstore_write_str(dom, "vm", vm);
  80 +
  81 + /* memory */
  82 + xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB
  83 + xenstore_write_int(vm, "memory", ram_size >> 20); // MB
  84 + xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB
  85 +
  86 + /* cpus */
  87 + for (i = 0; i < smp_cpus; i++) {
  88 + snprintf(path, sizeof(path), "cpu/%d/availability",i);
  89 + xenstore_write_str(dom, path, "online");
  90 + }
  91 + xenstore_write_int(vm, "vcpu_avail", smp_cpus);
  92 + xenstore_write_int(vm, "vcpus", smp_cpus);
  93 +
  94 + /* vnc password */
  95 + xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
  96 +
  97 + free(dom);
  98 + return 0;
  99 +}
  100 +
  101 +int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
  102 + int console_port, int console_mfn)
  103 +{
  104 + char *dom;
  105 +
  106 + dom = xs_get_domain_path(xenstore, xen_domid);
  107 +
  108 + /* signal new domain */
  109 + xs_introduce_domain(xenstore,
  110 + xen_domid,
  111 + xenstore_mfn,
  112 + xenstore_port);
  113 +
  114 + /* xenstore */
  115 + xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
  116 + xenstore_write_int(dom, "store/port", xenstore_port);
  117 +
  118 + /* console */
  119 + xenstore_write_str(dom, "console/type", "ioemu");
  120 + xenstore_write_int(dom, "console/limit", 128 * 1024);
  121 + xenstore_write_int(dom, "console/ring-ref", console_mfn);
  122 + xenstore_write_int(dom, "console/port", console_port);
  123 + xen_config_dev_console(0);
  124 +
  125 + free(dom);
  126 + return 0;
  127 +}
  128 +
  129 +/* ------------------------------------------------------------- */
  130 +
  131 +static QEMUTimer *xen_poll;
  132 +
  133 +/* check domain state once per second */
  134 +static void xen_domain_poll(void *opaque)
  135 +{
  136 + struct xc_dominfo info;
  137 + int rc;
  138 +
  139 + rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
  140 + if ((1 != rc) || (info.domid != xen_domid)) {
  141 + qemu_log("xen: domain %d is gone\n", xen_domid);
  142 + goto quit;
  143 + }
  144 + if (info.dying) {
  145 + qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
  146 + info.crashed ? "crashed" : "",
  147 + info.shutdown ? "shutdown" : "");
  148 + goto quit;
  149 + }
  150 +
  151 + qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
  152 + return;
  153 +
  154 +quit:
  155 + qemu_system_shutdown_request();
  156 + return;
  157 +}
  158 +
  159 +static void xen_domain_watcher(void)
  160 +{
  161 + int qemu_running = 1;
  162 + int fd[2], i, n, rc;
  163 + char byte;
  164 +
  165 + pipe(fd);
  166 + if (fork() != 0)
  167 + return; /* not child */
  168 +
  169 + /* close all file handles, except stdio/out/err,
  170 + * our watch pipe and the xen interface handle */
  171 + n = getdtablesize();
  172 + for (i = 3; i < n; i++) {
  173 + if (i == fd[0])
  174 + continue;
  175 + if (i == xen_xc)
  176 + continue;
  177 + close(i);
  178 + }
  179 +
  180 + /* ignore term signals */
  181 + signal(SIGINT, SIG_IGN);
  182 + signal(SIGTERM, SIG_IGN);
  183 +
  184 + /* wait for qemu exiting */
  185 + while (qemu_running) {
  186 + rc = read(fd[0], &byte, 1);
  187 + switch (rc) {
  188 + case -1:
  189 + if (EINTR == errno)
  190 + continue;
  191 + qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
  192 + qemu_running = 0;
  193 + break;
  194 + case 0:
  195 + /* EOF -> qemu exited */
  196 + qemu_running = 0;
  197 + break;
  198 + default:
  199 + qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
  200 + break;
  201 + }
  202 + }
  203 +
  204 + /* cleanup */
  205 + qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
  206 + xc_domain_destroy(xen_xc, xen_domid);
  207 + _exit(0);
  208 +}
  209 +
  210 +/* normal cleanup */
  211 +static void xen_domain_cleanup(void)
  212 +{
  213 + char *dom;
  214 +
  215 + dom = xs_get_domain_path(xenstore, xen_domid);
  216 + if (dom) {
  217 + xs_rm(xenstore, 0, dom);
  218 + free(dom);
  219 + }
  220 + xs_release_domain(xenstore, xen_domid);
  221 +}
  222 +
  223 +int xen_domain_build_pv(const char *kernel, const char *ramdisk,
  224 + const char *cmdline)
  225 +{
  226 + uint32_t ssidref = 0;
  227 + uint32_t flags = 0;
  228 + xen_domain_handle_t uuid;
  229 + unsigned int xenstore_port = 0, console_port = 0;
  230 + unsigned long xenstore_mfn = 0, console_mfn = 0;
  231 + int rc;
  232 +
  233 + memcpy(uuid, qemu_uuid, sizeof(uuid));
  234 + rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
  235 + if (rc < 0) {
  236 + fprintf(stderr, "xen: xc_domain_create() failed\n");
  237 + goto err;
  238 + }
  239 + qemu_log("xen: created domain %d\n", xen_domid);
  240 + atexit(xen_domain_cleanup);
  241 + xen_domain_watcher();
  242 +
  243 + xenstore_domain_init1(kernel, ramdisk, cmdline);
  244 +
  245 + rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
  246 + if (rc < 0) {
  247 + fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
  248 + goto err;
  249 + }
  250 +
  251 +#if 0
  252 + rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
  253 + if (rc < 0) {
  254 + fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
  255 + goto err;
  256 + }
  257 +#endif
  258 +
  259 + rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
  260 + if (rc < 0) {
  261 + fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
  262 + goto err;
  263 + }
  264 +
  265 + xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
  266 + console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
  267 +
  268 + rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
  269 + kernel, ramdisk, cmdline,
  270 + 0, flags,
  271 + xenstore_port, &xenstore_mfn,
  272 + console_port, &console_mfn);
  273 + if (rc < 0) {
  274 + fprintf(stderr, "xen: xc_linux_build() failed\n");
  275 + goto err;
  276 + }
  277 +
  278 + xenstore_domain_init2(xenstore_port, xenstore_mfn,
  279 + console_port, console_mfn);
  280 +
  281 + qemu_log("xen: unpausing domain %d\n", xen_domid);
  282 + rc = xc_domain_unpause(xen_xc, xen_domid);
  283 + if (rc < 0) {
  284 + fprintf(stderr, "xen: xc_domain_unpause() failed\n");
  285 + goto err;
  286 + }
  287 +
  288 + xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
  289 + qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
  290 + return 0;
  291 +
  292 +err:
  293 + return -1;
  294 +}
... ...
hw/xen_domainbuild.h 0 → 100644
  1 +#ifndef QEMU_HW_XEN_DOMAINBUILD_H
  2 +#define QEMU_HW_XEN_DOMAINBUILD_H 1
  3 +
  4 +#include "xen_common.h"
  5 +
  6 +int xenstore_domain_init1(const char *kernel, const char *ramdisk,
  7 + const char *cmdline);
  8 +int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
  9 + int console_port, int console_mfn);
  10 +int xen_domain_build_pv(const char *kernel, const char *ramdisk,
  11 + const char *cmdline);
  12 +
  13 +#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
... ...
hw/xen_machine_pv.c
... ... @@ -27,6 +27,7 @@
27 27 #include "sysemu.h"
28 28 #include "boards.h"
29 29 #include "xen_backend.h"
  30 +#include "xen_domainbuild.h"
30 31  
31 32 uint32_t xen_domid;
32 33 enum xen_mode xen_mode = XEN_EMULATE;
... ... @@ -57,6 +58,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
57 58 fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
58 59 exit(1);
59 60 }
  61 +
  62 + switch (xen_mode) {
  63 + case XEN_ATTACH:
  64 + /* nothing to do, xend handles everything */
  65 + break;
  66 + case XEN_CREATE:
  67 + if (xen_domain_build_pv(kernel_filename, initrd_filename,
  68 + kernel_cmdline) < 0) {
  69 + fprintf(stderr, "xen pv domain creation failed\n");
  70 + exit(1);
  71 + }
  72 + break;
  73 + case XEN_EMULATE:
  74 + fprintf(stderr, "xen emulation not implemented (yet)\n");
  75 + exit(1);
  76 + break;
  77 + }
  78 +
60 79 xen_be_register("console", &xen_console_ops);
61 80 xen_be_register("vkbd", &xen_kbdmouse_ops);
62 81 xen_be_register("vfb", &xen_framebuffer_ops);
... ...