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