]>
Commit | Line | Data |
---|---|---|
21cbfe5f | 1 | #include "qemu/osdep.h" |
0d09e41a | 2 | #include "hw/xen/xen_backend.h" |
47b43a1f | 3 | #include "xen_domainbuild.h" |
1de7afc9 PB |
4 | #include "qemu/timer.h" |
5 | #include "qemu/log.h" | |
9306acb5 AL |
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 | ||
9c5ce8db | 56 | qemu_uuid_unparse(&qemu_uuid, uuid_string); |
9306acb5 AL |
57 | dom = xs_get_domain_path(xenstore, xen_domid); |
58 | snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); | |
59 | ||
60 | xenstore_domain_mkdir(dom); | |
61 | ||
62 | xenstore_write_str(vm, "image/ostype", "linux"); | |
63 | if (kernel) | |
64 | xenstore_write_str(vm, "image/kernel", kernel); | |
65 | if (ramdisk) | |
66 | xenstore_write_str(vm, "image/ramdisk", ramdisk); | |
67 | if (cmdline) | |
68 | xenstore_write_str(vm, "image/cmdline", cmdline); | |
69 | ||
70 | /* name + id */ | |
71 | xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name"); | |
72 | xenstore_write_str(vm, "uuid", uuid_string); | |
73 | xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name"); | |
74 | xenstore_write_int(dom, "domid", xen_domid); | |
75 | xenstore_write_str(dom, "vm", vm); | |
76 | ||
77 | /* memory */ | |
78 | xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB | |
79 | xenstore_write_int(vm, "memory", ram_size >> 20); // MB | |
80 | xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB | |
81 | ||
82 | /* cpus */ | |
83 | for (i = 0; i < smp_cpus; i++) { | |
84 | snprintf(path, sizeof(path), "cpu/%d/availability",i); | |
85 | xenstore_write_str(dom, path, "online"); | |
86 | } | |
87 | xenstore_write_int(vm, "vcpu_avail", smp_cpus); | |
88 | xenstore_write_int(vm, "vcpus", smp_cpus); | |
89 | ||
90 | /* vnc password */ | |
91 | xenstore_write_str(vm, "vncpassword", "" /* FIXME */); | |
92 | ||
93 | free(dom); | |
94 | return 0; | |
95 | } | |
96 | ||
97 | int xenstore_domain_init2(int xenstore_port, int xenstore_mfn, | |
98 | int console_port, int console_mfn) | |
99 | { | |
100 | char *dom; | |
101 | ||
102 | dom = xs_get_domain_path(xenstore, xen_domid); | |
103 | ||
104 | /* signal new domain */ | |
105 | xs_introduce_domain(xenstore, | |
106 | xen_domid, | |
107 | xenstore_mfn, | |
108 | xenstore_port); | |
109 | ||
110 | /* xenstore */ | |
111 | xenstore_write_int(dom, "store/ring-ref", xenstore_mfn); | |
112 | xenstore_write_int(dom, "store/port", xenstore_port); | |
113 | ||
114 | /* console */ | |
115 | xenstore_write_str(dom, "console/type", "ioemu"); | |
116 | xenstore_write_int(dom, "console/limit", 128 * 1024); | |
117 | xenstore_write_int(dom, "console/ring-ref", console_mfn); | |
118 | xenstore_write_int(dom, "console/port", console_port); | |
119 | xen_config_dev_console(0); | |
120 | ||
121 | free(dom); | |
122 | return 0; | |
123 | } | |
124 | ||
125 | /* ------------------------------------------------------------- */ | |
126 | ||
127 | static QEMUTimer *xen_poll; | |
128 | ||
129 | /* check domain state once per second */ | |
130 | static void xen_domain_poll(void *opaque) | |
131 | { | |
132 | struct xc_dominfo info; | |
133 | int rc; | |
134 | ||
135 | rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info); | |
fc1f79f7 | 136 | if ((rc != 1) || (info.domid != xen_domid)) { |
9306acb5 AL |
137 | qemu_log("xen: domain %d is gone\n", xen_domid); |
138 | goto quit; | |
139 | } | |
140 | if (info.dying) { | |
141 | qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid, | |
142 | info.crashed ? "crashed" : "", | |
143 | info.shutdown ? "shutdown" : ""); | |
144 | goto quit; | |
145 | } | |
146 | ||
bc72ad67 | 147 | timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); |
9306acb5 AL |
148 | return; |
149 | ||
150 | quit: | |
cf83f140 | 151 | qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); |
9306acb5 AL |
152 | } |
153 | ||
acdc3f0c | 154 | static int xen_domain_watcher(void) |
9306acb5 AL |
155 | { |
156 | int qemu_running = 1; | |
157 | int fd[2], i, n, rc; | |
158 | char byte; | |
159 | ||
acdc3f0c JQ |
160 | if (pipe(fd) != 0) { |
161 | qemu_log("%s: Huh? pipe error: %s\n", __FUNCTION__, strerror(errno)); | |
162 | return -1; | |
163 | } | |
9306acb5 | 164 | if (fork() != 0) |
acdc3f0c | 165 | return 0; /* not child */ |
9306acb5 AL |
166 | |
167 | /* close all file handles, except stdio/out/err, | |
168 | * our watch pipe and the xen interface handle */ | |
169 | n = getdtablesize(); | |
170 | for (i = 3; i < n; i++) { | |
171 | if (i == fd[0]) | |
172 | continue; | |
9306acb5 AL |
173 | close(i); |
174 | } | |
175 | ||
228df5c9 IC |
176 | /* |
177 | * Reopen xc interface, since the original is unsafe after fork | |
178 | * and was closed above. | |
179 | */ | |
180 | xen_xc = xc_interface_open(0, 0, 0); | |
181 | ||
9306acb5 AL |
182 | /* ignore term signals */ |
183 | signal(SIGINT, SIG_IGN); | |
184 | signal(SIGTERM, SIG_IGN); | |
185 | ||
186 | /* wait for qemu exiting */ | |
187 | while (qemu_running) { | |
188 | rc = read(fd[0], &byte, 1); | |
189 | switch (rc) { | |
190 | case -1: | |
fc1f79f7 | 191 | if (errno == EINTR) |
9306acb5 AL |
192 | continue; |
193 | qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno)); | |
194 | qemu_running = 0; | |
195 | break; | |
196 | case 0: | |
197 | /* EOF -> qemu exited */ | |
198 | qemu_running = 0; | |
199 | break; | |
200 | default: | |
201 | qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__); | |
202 | break; | |
203 | } | |
204 | } | |
205 | ||
206 | /* cleanup */ | |
207 | qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid); | |
208 | xc_domain_destroy(xen_xc, xen_domid); | |
209 | _exit(0); | |
210 | } | |
211 | ||
212 | /* normal cleanup */ | |
28695489 | 213 | static void xen_domain_cleanup(void) |
9306acb5 AL |
214 | { |
215 | char *dom; | |
216 | ||
217 | dom = xs_get_domain_path(xenstore, xen_domid); | |
218 | if (dom) { | |
219 | xs_rm(xenstore, 0, dom); | |
220 | free(dom); | |
221 | } | |
222 | xs_release_domain(xenstore, xen_domid); | |
223 | } | |
224 | ||
225 | int xen_domain_build_pv(const char *kernel, const char *ramdisk, | |
226 | const char *cmdline) | |
227 | { | |
228 | uint32_t ssidref = 0; | |
229 | uint32_t flags = 0; | |
230 | xen_domain_handle_t uuid; | |
231 | unsigned int xenstore_port = 0, console_port = 0; | |
232 | unsigned long xenstore_mfn = 0, console_mfn = 0; | |
233 | int rc; | |
234 | ||
84d0984d | 235 | memcpy(uuid, &qemu_uuid, sizeof(uuid)); |
cdadde39 | 236 | rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); |
9306acb5 AL |
237 | if (rc < 0) { |
238 | fprintf(stderr, "xen: xc_domain_create() failed\n"); | |
239 | goto err; | |
240 | } | |
241 | qemu_log("xen: created domain %d\n", xen_domid); | |
28695489 | 242 | atexit(xen_domain_cleanup); |
acdc3f0c JQ |
243 | if (xen_domain_watcher() == -1) { |
244 | goto err; | |
245 | } | |
9306acb5 AL |
246 | |
247 | xenstore_domain_init1(kernel, ramdisk, cmdline); | |
248 | ||
249 | rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus); | |
250 | if (rc < 0) { | |
251 | fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n"); | |
252 | goto err; | |
253 | } | |
254 | ||
255 | #if 0 | |
256 | rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256); | |
257 | if (rc < 0) { | |
258 | fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n"); | |
259 | goto err; | |
260 | } | |
261 | #endif | |
262 | ||
263 | rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10); | |
264 | if (rc < 0) { | |
265 | fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n"); | |
266 | goto err; | |
267 | } | |
268 | ||
269 | xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); | |
270 | console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0); | |
271 | ||
272 | rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20, | |
273 | kernel, ramdisk, cmdline, | |
274 | 0, flags, | |
275 | xenstore_port, &xenstore_mfn, | |
276 | console_port, &console_mfn); | |
277 | if (rc < 0) { | |
278 | fprintf(stderr, "xen: xc_linux_build() failed\n"); | |
279 | goto err; | |
280 | } | |
281 | ||
282 | xenstore_domain_init2(xenstore_port, xenstore_mfn, | |
283 | console_port, console_mfn); | |
284 | ||
285 | qemu_log("xen: unpausing domain %d\n", xen_domid); | |
286 | rc = xc_domain_unpause(xen_xc, xen_domid); | |
287 | if (rc < 0) { | |
288 | fprintf(stderr, "xen: xc_domain_unpause() failed\n"); | |
289 | goto err; | |
290 | } | |
291 | ||
bc72ad67 AB |
292 | xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL); |
293 | timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000); | |
9306acb5 AL |
294 | return 0; |
295 | ||
296 | err: | |
297 | return -1; | |
298 | } |