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@xxxxxxxxxx>
---
Makefile.target | 2 +-
configure | 2 +-
hw/xen_backend.h | 3 +
hw/xen_devconfig.c | 29 +++++
hw/xen_domainbuild.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/xen_domainbuild.h | 13 +++
hw/xen_machine_pv.c | 19 ++++
7 files changed, 360 insertions(+), 2 deletions(-)
create mode 100644 hw/xen_domainbuild.c
create mode 100644 hw/xen_domainbuild.h
diff --git a/Makefile.target b/Makefile.target
index 24d409e..2171587 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -561,7 +561,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS)
endif
# xen backend driver support
-XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
ifeq ($(CONFIG_XEN), yes)
OBJS += $(XEN_OBJS)
diff --git a/configure b/configure
index ec761ff..b7b7b01 100755
--- a/configure
+++ b/configure
@@ -1634,7 +1634,7 @@ if test "$bluez" = "yes" ; then
echo "#define CONFIG_BLUEZ 1" >> $config_h
fi
if test "$xen" = "yes" ; then
- echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak
+ echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak
fi
if test "$aio" = "yes" ; then
echo "#define CONFIG_AIO 1" >> $config_h
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 7f1804e..4dbfdb4 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -100,5 +100,8 @@ void xen_init_display(int domid);
void xen_config_cleanup(void);
int xen_config_dev_blk(DriveInfo *disk);
int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index 4420561..4121188 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -140,3 +140,32 @@ int xen_config_dev_nic(NICInfo *nic)
/* common stuff */
return xen_config_dev_all(fe, be);
}
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+ /* backend */
+ xenstore_write_str(be, "type", type);
+
+ /* common stuff */
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+ return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
new file mode 100644
index 0000000..21710eb
--- /dev/null
+++ b/hw/xen_domainbuild.c
@@ -0,0 +1,294 @@
+#include <signal.h>
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+ struct xs_permissions perms_ro[] = {{
+ .id = 0, /* set owner: dom0 */
+ },{
+ .id = xen_domid,
+ .perms = XS_PERM_READ,
+ }};
+ struct xs_permissions perms_rw[] = {{
+ .id = 0, /* set owner: dom0 */
+ },{
+ .id = xen_domid,
+ .perms = XS_PERM_READ | XS_PERM_WRITE,
+ }};
+ const char *writable[] = { "device", "control", "error", NULL };
+ char subpath[256];
+ int i;
+
+ if (!xs_mkdir(xenstore, 0, path)) {
+ fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+ return -1;
+ }
+ if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+ fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+ return -1;
+ }
+
+ for (i = 0; writable[i]; i++) {
+ snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+ if (!xs_mkdir(xenstore, 0, subpath)) {
+ fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__,
subpath);
+ return -1;
+ }
+ if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+ fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+ const char *cmdline)
+{
+ char *dom, uuid_string[42], vm[256], path[256];
+ int i;
+
+ snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+ qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+ qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+ qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+ qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+ dom = xs_get_domain_path(xenstore, xen_domid);
+ snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
+
+ xenstore_domain_mkdir(dom);
+
+ xenstore_write_str(vm, "image/ostype", "linux");
+ if (kernel)
+ xenstore_write_str(vm, "image/kernel", kernel);
+ if (ramdisk)
+ xenstore_write_str(vm, "image/ramdisk", ramdisk);
+ if (cmdline)
+ xenstore_write_str(vm, "image/cmdline", cmdline);
+
+ /* name + id */
+ xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
+ xenstore_write_str(vm, "uuid", uuid_string);
+ xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
+ xenstore_write_int(dom, "domid", xen_domid);
+ xenstore_write_str(dom, "vm", vm);
+
+ /* memory */
+ xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB
+ xenstore_write_int(vm, "memory", ram_size >> 20); // MB
+ xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB
+
+ /* cpus */
+ for (i = 0; i < smp_cpus; i++) {
+ snprintf(path, sizeof(path), "cpu/%d/availability",i);
+ xenstore_write_str(dom, path, "online");
+ }
+ xenstore_write_int(vm, "vcpu_avail", smp_cpus);
+ xenstore_write_int(vm, "vcpus", smp_cpus);
+
+ /* vnc password */
+ xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+ free(dom);
+ return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+ int console_port, int console_mfn)
+{
+ char *dom;
+
+ dom = xs_get_domain_path(xenstore, xen_domid);
+
+ /* signal new domain */
+ xs_introduce_domain(xenstore,
+ xen_domid,
+ xenstore_mfn,
+ xenstore_port);
+
+ /* xenstore */
+ xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
+ xenstore_write_int(dom, "store/port", xenstore_port);
+
+ /* console */
+ xenstore_write_str(dom, "console/type", "ioemu");
+ xenstore_write_int(dom, "console/limit", 128 * 1024);
+ xenstore_write_int(dom, "console/ring-ref", console_mfn);
+ xenstore_write_int(dom, "console/port", console_port);
+ xen_config_dev_console(0);
+
+ free(dom);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+ struct xc_dominfo info;
+ int rc;
+
+ rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+ if ((1 != rc) || (info.domid != xen_domid)) {
+ qemu_log("xen: domain %d is gone\n", xen_domid);
+ goto quit;
+ }
+ if (info.dying) {
+ qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
+ info.crashed ? "crashed" : "",
+ info.shutdown ? "shutdown" : "");
+ goto quit;
+ }
+
+ qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+ return;
+
+quit:
+ qemu_system_shutdown_request();
+ return;
+}
+
+static void xen_domain_watcher(void)
+{
+ int qemu_running = 1;
+ int fd[2], i, n, rc;
+ char byte;
+
+ pipe(fd);
+ if (fork() != 0)
+ return; /* not child */
+
+ /* close all file handles, except stdio/out/err,
+ * our watch pipe and the xen interface handle */
+ n = getdtablesize();
+ for (i = 3; i < n; i++) {
+ if (i == fd[0])
+ continue;
+ if (i == xen_xc)
+ continue;
+ close(i);
+ }
+
+ /* ignore term signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+
+ /* wait for qemu exiting */
+ while (qemu_running) {
+ rc = read(fd[0], &byte, 1);
+ switch (rc) {
+ case -1:
+ if (EINTR == errno)
+ continue;
+ qemu_log("%s: Huh? read error: %s\n", __FUNCTION__,
strerror(errno));
+ qemu_running = 0;
+ break;
+ case 0:
+ /* EOF -> qemu exited */
+ qemu_running = 0;
+ break;
+ default:
+ qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+ break;
+ }
+ }
+
+ /* cleanup */
+ qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+ xc_domain_destroy(xen_xc, xen_domid);
+ _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+ char *dom;
+
+ dom = xs_get_domain_path(xenstore, xen_domid);
+ if (dom) {
+ xs_rm(xenstore, 0, dom);
+ free(dom);
+ }
+ xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+ const char *cmdline)
+{
+ uint32_t ssidref = 0;
+ uint32_t flags = 0;
+ xen_domain_handle_t uuid;
+ unsigned int xenstore_port = 0, console_port = 0;
+ unsigned long xenstore_mfn = 0, console_mfn = 0;
+ int rc;
+
+ memcpy(uuid, qemu_uuid, sizeof(uuid));
+ rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_create() failed\n");
+ goto err;
+ }
+ qemu_log("xen: created domain %d\n", xen_domid);
+ atexit(xen_domain_cleanup);
+ xen_domain_watcher();
+
+ xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+ rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+ goto err;
+ }
+
+#if 0
+ rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+ goto err;
+ }
+#endif
+
+ rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+ goto err;
+ }
+
+ xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+ console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+ rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+ kernel, ramdisk, cmdline,
+ 0, flags,
+ xenstore_port, &xenstore_mfn,
+ console_port, &console_mfn);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_linux_build() failed\n");
+ goto err;
+ }
+
+ xenstore_domain_init2(xenstore_port, xenstore_mfn,
+ console_port, console_mfn);
+
+ qemu_log("xen: unpausing domain %d\n", xen_domid);
+ rc = xc_domain_unpause(xen_xc, xen_domid);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+ goto err;
+ }
+
+ xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
+ qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+ return 0;
+
+err:
+ return -1;
+}
diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h
new file mode 100644
index 0000000..dea0121
--- /dev/null
+++ b/hw/xen_domainbuild.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+ const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+ int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+ const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 154cf71..56b01aa 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -27,6 +27,7 @@
#include "sysemu.h"
#include "boards.h"
#include "xen_backend.h"
+#include "xen_domainbuild.h"
uint32_t xen_domid;
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,
fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
exit(1);
}
+
+ switch (xen_mode) {
+ case XEN_ATTACH:
+ /* nothing to do, xend handles everything */
+ break;
+ case XEN_CREATE:
+ if (xen_domain_build_pv(kernel_filename, initrd_filename,
+ kernel_cmdline) < 0) {
+ fprintf(stderr, "xen pv domain creation failed\n");
+ exit(1);
+ }
+ break;
+ case XEN_EMULATE:
+ fprintf(stderr, "xen emulation not implemented (yet)\n");
+ exit(1);
+ break;
+ }
+
xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
xen_be_register("vfb", &xen_framebuffer_ops);
--
1.6.2.2
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|