1 #include <fcntl.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <getopt.h>
8 #include <sys/ioctl.h>
9 #include <sys/mman.h>
10 #include <xenctrl.h>
11 #include <xc_dom.h>
12 #include <xenstore.h>
13 #include <xen/sys/xenbus_dev.h>
14 #include <xen-xsm/flask/flask.h>
15 #include <xen/io/xenbus.h>
16
17 #include "init-dom-json.h"
18 #include "_paths.h"
19
20 static uint32_t domid = ~0;
21 static char *kernel;
22 static char *ramdisk;
23 static char *flask;
24 static char *param;
25 static char *name = "Xenstore";
26 static int memory;
27 static int maxmem;
28 static xen_pfn_t console_mfn;
29 static xc_evtchn_port_or_error_t console_evtchn;
30
31 static struct option options[] = {
32 { "kernel", 1, NULL, 'k' },
33 { "memory", 1, NULL, 'm' },
34 { "flask", 1, NULL, 'f' },
35 { "ramdisk", 1, NULL, 'r' },
36 { "param", 1, NULL, 'p' },
37 { "name", 1, NULL, 'n' },
38 { "maxmem", 1, NULL, 'M' },
39 { NULL, 0, NULL, 0 }
40 };
41
usage(void)42 static void usage(void)
43 {
44 fprintf(stderr,
45 "Usage:\n"
46 "\n"
47 "init-xenstore-domain <options>\n"
48 "\n"
49 "where options may include:\n"
50 "\n"
51 " --kernel <xenstore-kernel> kernel file of the xenstore domain, mandatory\n"
52 " --memory <memory size> size of the domain in MB, mandatory\n"
53 " --flask <flask-label> optional flask label of the domain\n"
54 " --ramdisk <ramdisk-file> optional ramdisk file for the domain\n"
55 " --param <cmdline> optional additional parameters for the domain\n"
56 " --name <name> name of the domain (default: Xenstore)\n"
57 " --maxmem <max size> maximum memory size in the format:\n"
58 " <MB val>|<a>/<b>|<MB val>:<a>/<b>\n"
59 " (an absolute value in MB, a fraction a/b of\n"
60 " the host memory, or the maximum of both)\n");
61 }
62
build(xc_interface * xch)63 static int build(xc_interface *xch)
64 {
65 char cmdline[512];
66 int rv, xs_fd;
67 struct xc_dom_image *dom = NULL;
68 int limit_kb = (maxmem ? : (memory + 1)) * 1024;
69 struct xen_domctl_createdomain config = {
70 .ssidref = SECINITSID_DOMU,
71 .flags = XEN_DOMCTL_CDF_xs_domain,
72 .max_vcpus = 1,
73 .max_evtchn_port = -1, /* No limit. */
74
75 /*
76 * 1 grant frame is enough: we don't need many grants.
77 * Mini-OS doesn't like less than 4, though, so use 4.
78 * 128 maptrack frames: 256 entries per frame, enough for 32768 domains.
79 */
80 .max_grant_frames = 4,
81 .max_maptrack_frames = 128,
82 };
83
84 xs_fd = open("/dev/xen/xenbus_backend", O_RDWR);
85 if ( xs_fd == -1 )
86 {
87 fprintf(stderr, "Could not open /dev/xen/xenbus_backend\n");
88 return -1;
89 }
90
91 if ( flask )
92 {
93 rv = xc_flask_context_to_sid(xch, flask, strlen(flask), &config.ssidref);
94 if ( rv )
95 {
96 fprintf(stderr, "xc_flask_context_to_sid failed\n");
97 goto err;
98 }
99 }
100
101 rv = xc_domain_create(xch, &domid, &config);
102 if ( rv )
103 {
104 fprintf(stderr, "xc_domain_create failed\n");
105 goto err;
106 }
107 rv = xc_domain_max_vcpus(xch, domid, config.max_vcpus);
108 if ( rv )
109 {
110 fprintf(stderr, "xc_domain_max_vcpus failed\n");
111 goto err;
112 }
113 rv = xc_domain_setmaxmem(xch, domid, limit_kb);
114 if ( rv )
115 {
116 fprintf(stderr, "xc_domain_setmaxmem failed\n");
117 goto err;
118 }
119 console_evtchn = xc_evtchn_alloc_unbound(xch, domid, 0);
120 if ( console_evtchn < 0 )
121 {
122 fprintf(stderr, "xc_evtchn_alloc_unbound failed\n");
123 goto err;
124 }
125 rv = xc_domain_set_memmap_limit(xch, domid, limit_kb);
126 if ( rv )
127 {
128 fprintf(stderr, "xc_domain_set_memmap_limit failed\n");
129 goto err;
130 }
131
132 rv = ioctl(xs_fd, IOCTL_XENBUS_BACKEND_SETUP, domid);
133 if ( rv < 0 )
134 {
135 fprintf(stderr, "Xenbus setup ioctl failed\n");
136 goto err;
137 }
138
139 if ( param )
140 snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
141 else
142 snprintf(cmdline, 512, "--event %d --internal-db", rv);
143
144 dom = xc_dom_allocate(xch, cmdline, NULL);
145 if ( !dom )
146 {
147 fprintf(stderr, "xc_dom_allocate failed\n");
148 goto err;
149 }
150 dom->container_type = XC_DOM_PV_CONTAINER;
151 dom->xenstore_domid = domid;
152 dom->console_evtchn = console_evtchn;
153
154 rv = xc_dom_kernel_file(dom, kernel);
155 if ( rv )
156 {
157 fprintf(stderr, "xc_dom_kernel_file failed\n");
158 goto err;
159 }
160
161 if ( ramdisk )
162 {
163 rv = xc_dom_module_file(dom, ramdisk, NULL);
164 if ( rv )
165 {
166 fprintf(stderr, "xc_dom_module_file failed\n");
167 goto err;
168 }
169 }
170
171 rv = xc_dom_boot_xen_init(dom, xch, domid);
172 if ( rv )
173 {
174 fprintf(stderr, "xc_dom_boot_xen_init failed\n");
175 goto err;
176 }
177 rv = xc_dom_parse_image(dom);
178 if ( rv )
179 {
180 fprintf(stderr, "xc_dom_parse_image failed\n");
181 goto err;
182 }
183 rv = xc_dom_mem_init(dom, memory);
184 if ( rv )
185 {
186 fprintf(stderr, "xc_dom_mem_init failed\n");
187 goto err;
188 }
189 rv = xc_dom_boot_mem_init(dom);
190 if ( rv )
191 {
192 fprintf(stderr, "xc_dom_boot_mem_init failed\n");
193 goto err;
194 }
195 rv = xc_dom_build_image(dom);
196 if ( rv )
197 {
198 fprintf(stderr, "xc_dom_build_image failed\n");
199 goto err;
200 }
201 rv = xc_dom_boot_image(dom);
202 if ( rv )
203 {
204 fprintf(stderr, "xc_dom_boot_image failed\n");
205 goto err;
206 }
207 rv = xc_dom_gnttab_init(dom);
208 if ( rv )
209 {
210 fprintf(stderr, "xc_dom_gnttab_init failed\n");
211 goto err;
212 }
213
214 rv = xc_domain_set_virq_handler(xch, domid, VIRQ_DOM_EXC);
215 if ( rv )
216 {
217 fprintf(stderr, "xc_domain_set_virq_handler failed\n");
218 goto err;
219 }
220 rv = xc_domain_unpause(xch, domid);
221 if ( rv )
222 {
223 fprintf(stderr, "xc_domain_unpause failed\n");
224 goto err;
225 }
226
227 rv = 0;
228 console_mfn = xc_dom_p2m(dom, dom->console_pfn);
229
230 err:
231 if ( dom )
232 xc_dom_release(dom);
233 if ( xs_fd >= 0 )
234 close(xs_fd);
235
236 /* if we failed then destroy the domain */
237 if ( rv && domid != ~0 )
238 xc_domain_destroy(xch, domid);
239
240 return rv;
241 }
242
check_domain(xc_interface * xch)243 static int check_domain(xc_interface *xch)
244 {
245 xc_dominfo_t info;
246 uint32_t dom;
247 int ret;
248
249 dom = 1;
250 while ( (ret = xc_domain_getinfo(xch, dom, 1, &info)) == 1 )
251 {
252 if ( info.xenstore )
253 return 1;
254 dom = info.domid + 1;
255 }
256 if ( ret < 0 && errno != ESRCH )
257 {
258 fprintf(stderr, "xc_domain_getinfo failed\n");
259 return ret;
260 }
261
262 return 0;
263 }
264
parse_maxmem(xc_interface * xch,char * str)265 static int parse_maxmem(xc_interface *xch, char *str)
266 {
267 xc_physinfo_t info;
268 int rv;
269 unsigned long mb = 0, a = 0, b = 0;
270 unsigned long val;
271 unsigned long *res;
272 char *p;
273 char *s = str;
274
275 rv = xc_physinfo(xch, &info);
276 if ( rv )
277 {
278 fprintf(stderr, "xc_physinfo failed\n");
279 return -1;
280 }
281
282 res = &mb;
283 for (p = s; *p; s = p + 1)
284 {
285 val = strtoul(s, &p, 10);
286 if ( val == 0 || val >= INT_MAX / 1024 )
287 goto err;
288 if ( *p == '/' )
289 {
290 if ( res != &mb || a != 0 )
291 goto err;
292 a = val;
293 res = &b;
294 continue;
295 }
296 if ( *res != 0 )
297 goto err;
298 *res = val;
299 if ( *p != 0 && *p != ':' )
300 goto err;
301 res = &mb;
302 }
303 if ( a && !b )
304 goto err;
305
306 val = a ? info.total_pages * a / (b * 1024 * 1024 / XC_PAGE_SIZE) : 0;
307 if ( val >= INT_MAX / 1024 )
308 goto err;
309
310 maxmem = mb < val ? val : mb;
311 if ( maxmem < memory )
312 maxmem = 0;
313
314 return maxmem;
315
316 err:
317 fprintf(stderr, "illegal value for maxmem: %s\n", str);
318 return -1;
319 }
320
do_xs_write(struct xs_handle * xsh,char * path,char * val)321 static void do_xs_write(struct xs_handle *xsh, char *path, char *val)
322 {
323 if ( !xs_write(xsh, XBT_NULL, path, val, strlen(val)) )
324 fprintf(stderr, "writing %s to xenstore failed.\n", path);
325 }
326
do_xs_write_dir_node(struct xs_handle * xsh,char * dir,char * node,char * val)327 static void do_xs_write_dir_node(struct xs_handle *xsh, char *dir, char *node,
328 char *val)
329 {
330 char full_path[100];
331
332 snprintf(full_path, 100, "%s/%s", dir, node);
333 do_xs_write(xsh, full_path, val);
334 }
335
do_xs_write_dom(struct xs_handle * xsh,char * path,char * val)336 static void do_xs_write_dom(struct xs_handle *xsh, char *path, char *val)
337 {
338 char full_path[64];
339
340 snprintf(full_path, 64, "/local/domain/%d/%s", domid, path);
341 do_xs_write(xsh, full_path, val);
342 }
343
main(int argc,char ** argv)344 int main(int argc, char** argv)
345 {
346 int opt;
347 xc_interface *xch;
348 struct xs_handle *xsh;
349 char buf[16], be_path[64], fe_path[64];
350 int rv, fd;
351 char *maxmem_str = NULL;
352
353 while ( (opt = getopt_long(argc, argv, "", options, NULL)) != -1 )
354 {
355 switch ( opt )
356 {
357 case 'k':
358 kernel = optarg;
359 break;
360 case 'm':
361 memory = strtol(optarg, NULL, 10);
362 break;
363 case 'f':
364 flask = optarg;
365 break;
366 case 'r':
367 ramdisk = optarg;
368 break;
369 case 'p':
370 param = optarg;
371 break;
372 case 'n':
373 name = optarg;
374 break;
375 case 'M':
376 maxmem_str = optarg;
377 break;
378 default:
379 usage();
380 return 2;
381 }
382 }
383
384 if ( optind != argc || !kernel || !memory )
385 {
386 usage();
387 return 2;
388 }
389
390 xch = xc_interface_open(NULL, NULL, 0);
391 if ( !xch )
392 {
393 fprintf(stderr, "xc_interface_open() failed\n");
394 return 1;
395 }
396
397 if ( maxmem_str )
398 {
399 maxmem = parse_maxmem(xch, maxmem_str);
400 if ( maxmem < 0 )
401 {
402 xc_interface_close(xch);
403 return 1;
404 }
405 }
406
407 rv = check_domain(xch);
408
409 if ( !rv )
410 rv = build(xch);
411 else if ( rv > 0 )
412 fprintf(stderr, "xenstore domain already present.\n");
413
414 xc_interface_close(xch);
415
416 if ( rv )
417 return 1;
418
419 rv = gen_stub_json_config(domid, NULL);
420 if ( rv )
421 return 3;
422
423 xsh = xs_open(0);
424 if ( !xsh )
425 {
426 fprintf(stderr, "xs_open() failed.\n");
427 return 3;
428 }
429 snprintf(buf, 16, "%d", domid);
430 do_xs_write(xsh, "/tool/xenstored/domid", buf);
431 do_xs_write_dom(xsh, "domid", buf);
432 do_xs_write_dom(xsh, "name", name);
433 snprintf(buf, 16, "%d", memory * 1024);
434 do_xs_write_dom(xsh, "memory/target", buf);
435 if (maxmem)
436 snprintf(buf, 16, "%d", maxmem * 1024);
437 do_xs_write_dom(xsh, "memory/static-max", buf);
438 snprintf(be_path, 64, "/local/domain/0/backend/console/%d/0", domid);
439 snprintf(fe_path, 64, "/local/domain/%d/console", domid);
440 snprintf(buf, 16, "%d", domid);
441 do_xs_write_dir_node(xsh, be_path, "frontend-id", buf);
442 do_xs_write_dir_node(xsh, be_path, "frontend", fe_path);
443 do_xs_write_dir_node(xsh, be_path, "online", "1");
444 snprintf(buf, 16, "%d", XenbusStateInitialising);
445 do_xs_write_dir_node(xsh, be_path, "state", buf);
446 do_xs_write_dir_node(xsh, be_path, "protocol", "vt100");
447 do_xs_write_dir_node(xsh, fe_path, "backend", be_path);
448 do_xs_write_dir_node(xsh, fe_path, "backend-id", "0");
449 do_xs_write_dir_node(xsh, fe_path, "limit", "1048576");
450 do_xs_write_dir_node(xsh, fe_path, "type", "xenconsoled");
451 do_xs_write_dir_node(xsh, fe_path, "output", "pty");
452 do_xs_write_dir_node(xsh, fe_path, "tty", "");
453 snprintf(buf, 16, "%d", console_evtchn);
454 do_xs_write_dir_node(xsh, fe_path, "port", buf);
455 snprintf(buf, 16, "%ld", console_mfn);
456 do_xs_write_dir_node(xsh, fe_path, "ring-ref", buf);
457 xs_close(xsh);
458
459 fd = creat(XEN_RUN_DIR "/xenstored.pid", 0666);
460 if ( fd < 0 )
461 {
462 fprintf(stderr, "Creating " XEN_RUN_DIR "/xenstored.pid failed\n");
463 return 3;
464 }
465 rv = snprintf(buf, 16, "domid:%d\n", domid);
466 rv = write(fd, buf, rv);
467 close(fd);
468 if ( rv < 0 )
469 {
470 fprintf(stderr,
471 "Writing domid to " XEN_RUN_DIR "/xenstored.pid failed\n");
472 return 3;
473 }
474
475 return 0;
476 }
477
478 /*
479 * Local variables:
480 * mode: C
481 * c-file-style: "BSD"
482 * c-basic-offset: 4
483 * indent-tabs-mode: nil
484 * End:
485 */
486