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