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