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