Commit 9306acb50991b7c78510ff4ffe19a190f2fc89c0
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
Showing
7 changed files
with
360 additions
and
2 deletions
Makefile.target
@@ -561,7 +561,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS) | @@ -561,7 +561,7 @@ LIBS += $(CONFIG_BLUEZ_LIBS) | ||
561 | endif | 561 | endif |
562 | 562 | ||
563 | # xen backend driver support | 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 | XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o | 565 | XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o |
566 | ifeq ($(CONFIG_XEN), yes) | 566 | ifeq ($(CONFIG_XEN), yes) |
567 | OBJS += $(XEN_OBJS) | 567 | OBJS += $(XEN_OBJS) |
configure
@@ -1634,7 +1634,7 @@ if test "$bluez" = "yes" ; then | @@ -1634,7 +1634,7 @@ if test "$bluez" = "yes" ; then | ||
1634 | echo "#define CONFIG_BLUEZ 1" >> $config_h | 1634 | echo "#define CONFIG_BLUEZ 1" >> $config_h |
1635 | fi | 1635 | fi |
1636 | if test "$xen" = "yes" ; then | 1636 | if test "$xen" = "yes" ; then |
1637 | - echo "XEN_LIBS=-lxenstore -lxenctrl" >> $config_mak | 1637 | + echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak |
1638 | fi | 1638 | fi |
1639 | if test "$aio" = "yes" ; then | 1639 | if test "$aio" = "yes" ; then |
1640 | echo "#define CONFIG_AIO 1" >> $config_h | 1640 | echo "#define CONFIG_AIO 1" >> $config_h |
hw/xen_backend.h
@@ -100,5 +100,8 @@ void xen_init_display(int domid); | @@ -100,5 +100,8 @@ void xen_init_display(int domid); | ||
100 | void xen_config_cleanup(void); | 100 | void xen_config_cleanup(void); |
101 | int xen_config_dev_blk(DriveInfo *disk); | 101 | int xen_config_dev_blk(DriveInfo *disk); |
102 | int xen_config_dev_nic(NICInfo *nic); | 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 | #endif /* QEMU_HW_XEN_BACKEND_H */ | 107 | #endif /* QEMU_HW_XEN_BACKEND_H */ |
hw/xen_devconfig.c
@@ -140,3 +140,32 @@ int xen_config_dev_nic(NICInfo *nic) | @@ -140,3 +140,32 @@ int xen_config_dev_nic(NICInfo *nic) | ||
140 | /* common stuff */ | 140 | /* common stuff */ |
141 | return xen_config_dev_all(fe, be); | 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,6 +27,7 @@ | ||
27 | #include "sysemu.h" | 27 | #include "sysemu.h" |
28 | #include "boards.h" | 28 | #include "boards.h" |
29 | #include "xen_backend.h" | 29 | #include "xen_backend.h" |
30 | +#include "xen_domainbuild.h" | ||
30 | 31 | ||
31 | uint32_t xen_domid; | 32 | uint32_t xen_domid; |
32 | enum xen_mode xen_mode = XEN_EMULATE; | 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,6 +58,24 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size, | ||
57 | fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); | 58 | fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); |
58 | exit(1); | 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 | xen_be_register("console", &xen_console_ops); | 79 | xen_be_register("console", &xen_console_ops); |
61 | xen_be_register("vkbd", &xen_kbdmouse_ops); | 80 | xen_be_register("vkbd", &xen_kbdmouse_ops); |
62 | xen_be_register("vfb", &xen_framebuffer_ops); | 81 | xen_be_register("vfb", &xen_framebuffer_ops); |