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 | 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 "$bluez" = "yes" ; 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); | ... | ... |