1 /******************************************************************************
2 * kernel.c
3 *
4 * Copyright (c) 2002-2005 K A Fraser
5 */
6
7 #include <xen/init.h>
8 #include <xen/lib.h>
9 #include <xen/errno.h>
10 #include <xen/param.h>
11 #include <xen/version.h>
12 #include <xen/sched.h>
13 #include <xen/paging.h>
14 #include <xen/guest_access.h>
15 #include <xen/hypercall.h>
16 #include <xen/hypfs.h>
17 #include <xsm/xsm.h>
18 #include <asm/current.h>
19 #include <public/version.h>
20
21 #ifndef COMPAT
22
23 enum system_state system_state = SYS_STATE_early_boot;
24
25 xen_commandline_t saved_cmdline;
26 static const char __initconst opt_builtin_cmdline[] = CONFIG_CMDLINE;
27
assign_integer_param(const struct kernel_param * param,uint64_t val)28 static int assign_integer_param(const struct kernel_param *param, uint64_t val)
29 {
30 switch ( param->len )
31 {
32 case sizeof(uint8_t):
33 if ( val > UINT8_MAX && val < (uint64_t)INT8_MIN )
34 return -EOVERFLOW;
35 *(uint8_t *)param->par.var = val;
36 break;
37 case sizeof(uint16_t):
38 if ( val > UINT16_MAX && val < (uint64_t)INT16_MIN )
39 return -EOVERFLOW;
40 *(uint16_t *)param->par.var = val;
41 break;
42 case sizeof(uint32_t):
43 if ( val > UINT32_MAX && val < (uint64_t)INT32_MIN )
44 return -EOVERFLOW;
45 *(uint32_t *)param->par.var = val;
46 break;
47 case sizeof(uint64_t):
48 *(uint64_t *)param->par.var = val;
49 break;
50 default:
51 BUG();
52 }
53
54 return 0;
55 }
56
parse_params(const char * cmdline,const struct kernel_param * start,const struct kernel_param * end)57 static int parse_params(const char *cmdline, const struct kernel_param *start,
58 const struct kernel_param *end)
59 {
60 char opt[MAX_PARAM_SIZE], *optval, *optkey, *q;
61 const char *p = cmdline, *key;
62 const struct kernel_param *param;
63 int rc, final_rc = 0;
64 bool bool_assert, found;
65
66 for ( ; ; )
67 {
68 /* Skip whitespace. */
69 while ( *p == ' ' )
70 p++;
71 if ( *p == '\0' )
72 break;
73
74 /* Grab the next whitespace-delimited option. */
75 q = optkey = opt;
76 while ( (*p != ' ') && (*p != '\0') )
77 {
78 if ( (q-opt) < (sizeof(opt)-1) ) /* avoid overflow */
79 *q++ = *p;
80 p++;
81 }
82 *q = '\0';
83
84 /* Search for value part of a key=value option. */
85 optval = strchr(opt, '=');
86 if ( optval != NULL )
87 {
88 *optval++ = '\0'; /* nul-terminate the option value */
89 q = strpbrk(opt, "([{<");
90 }
91 else
92 {
93 optval = q; /* default option value is empty string */
94 q = NULL;
95 }
96
97 /* Boolean parameters can be inverted with 'no-' prefix. */
98 key = optkey;
99 bool_assert = !!strncmp("no-", optkey, 3);
100 if ( !bool_assert )
101 optkey += 3;
102
103 rc = 0;
104 found = false;
105 for ( param = start; param < end; param++ )
106 {
107 int rctmp;
108 const char *s;
109
110 if ( strcmp(param->name, optkey) )
111 {
112 if ( param->type == OPT_CUSTOM && q &&
113 strlen(param->name) == q + 1 - opt &&
114 !strncmp(param->name, opt, q + 1 - opt) )
115 {
116 found = true;
117 optval[-1] = '=';
118 rctmp = param->par.func(q);
119 optval[-1] = '\0';
120 if ( !rc )
121 rc = rctmp;
122 }
123 continue;
124 }
125
126 rctmp = 0;
127 found = true;
128 switch ( param->type )
129 {
130 case OPT_STR:
131 strlcpy(param->par.var, optval, param->len);
132 break;
133 case OPT_UINT:
134 rctmp = assign_integer_param(
135 param,
136 simple_strtoll(optval, &s, 0));
137 if ( *s )
138 rctmp = -EINVAL;
139 break;
140 case OPT_BOOL:
141 rctmp = *optval ? parse_bool(optval, NULL) : 1;
142 if ( rctmp < 0 )
143 break;
144 if ( !rctmp )
145 bool_assert = !bool_assert;
146 rctmp = 0;
147 assign_integer_param(param, bool_assert);
148 break;
149 case OPT_SIZE:
150 rctmp = assign_integer_param(
151 param,
152 parse_size_and_unit(optval, &s));
153 if ( *s )
154 rctmp = -EINVAL;
155 break;
156 case OPT_CUSTOM:
157 rctmp = -EINVAL;
158 if ( !bool_assert )
159 {
160 if ( *optval )
161 break;
162 safe_strcpy(opt, "no");
163 optval = opt;
164 }
165 rctmp = param->par.func(optval);
166 break;
167 case OPT_IGNORE:
168 break;
169 default:
170 BUG();
171 break;
172 }
173
174 if ( !rc )
175 rc = rctmp;
176 }
177
178 if ( rc )
179 {
180 printk("parameter \"%s\" has invalid value \"%s\", rc=%d!\n",
181 key, optval, rc);
182 final_rc = rc;
183 }
184 if ( !found )
185 {
186 printk("parameter \"%s\" unknown!\n", key);
187 final_rc = -EINVAL;
188 }
189 }
190
191 return final_rc;
192 }
193
_cmdline_parse(const char * cmdline)194 static void __init _cmdline_parse(const char *cmdline)
195 {
196 parse_params(cmdline, __setup_start, __setup_end);
197 }
198
199 /**
200 * cmdline_parse -- parses the xen command line.
201 * If CONFIG_CMDLINE is set, it would be parsed prior to @cmdline.
202 * But if CONFIG_CMDLINE_OVERRIDE is set to y, @cmdline will be ignored.
203 */
cmdline_parse(const char * cmdline)204 void __init cmdline_parse(const char *cmdline)
205 {
206 if ( opt_builtin_cmdline[0] )
207 {
208 printk("Built-in command line: %s\n", opt_builtin_cmdline);
209 _cmdline_parse(opt_builtin_cmdline);
210 }
211
212 #ifndef CONFIG_CMDLINE_OVERRIDE
213 if ( cmdline == NULL )
214 return;
215
216 safe_strcpy(saved_cmdline, cmdline);
217 _cmdline_parse(cmdline);
218 #endif
219 }
220
parse_bool(const char * s,const char * e)221 int parse_bool(const char *s, const char *e)
222 {
223 size_t len = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
224
225 switch ( len )
226 {
227 case 1:
228 if ( *s == '1' )
229 return 1;
230 if ( *s == '0' )
231 return 0;
232 break;
233
234 case 2:
235 if ( !strncmp("on", s, 2) )
236 return 1;
237 if ( !strncmp("no", s, 2) )
238 return 0;
239 break;
240
241 case 3:
242 if ( !strncmp("yes", s, 3) )
243 return 1;
244 if ( !strncmp("off", s, 3) )
245 return 0;
246 break;
247
248 case 4:
249 if ( !strncmp("true", s, 4) )
250 return 1;
251 break;
252
253 case 5:
254 if ( !strncmp("false", s, 5) )
255 return 0;
256 break;
257
258 case 6:
259 if ( !strncmp("enable", s, 6) )
260 return 1;
261 break;
262
263 case 7:
264 if ( !strncmp("disable", s, 7) )
265 return 0;
266 break;
267 }
268
269 return -1;
270 }
271
parse_boolean(const char * name,const char * s,const char * e)272 int parse_boolean(const char *name, const char *s, const char *e)
273 {
274 size_t slen, nlen;
275 int val = !!strncmp(s, "no-", 3);
276
277 if ( !val )
278 s += 3;
279
280 slen = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
281 nlen = strlen(name);
282
283 /* Does s now start with name? */
284 if ( slen < nlen || strncmp(s, name, nlen) )
285 return -1;
286
287 /* Exact, unadorned name? Result depends on the 'no-' prefix. */
288 if ( slen == nlen )
289 return val;
290
291 /* =$SOMETHING? Defer to the regular boolean parsing. */
292 if ( s[nlen] == '=' )
293 return parse_bool(&s[nlen + 1], e);
294
295 /* Unrecognised. Give up. */
296 return -1;
297 }
298
cmdline_strcmp(const char * frag,const char * name)299 int cmdline_strcmp(const char *frag, const char *name)
300 {
301 for ( ; ; frag++, name++ )
302 {
303 unsigned char f = *frag, n = *name;
304 int res = f - n;
305
306 if ( res || n == '\0' )
307 {
308 /*
309 * NUL in 'name' matching a comma, colon, semicolon or equals in
310 * 'frag' implies success.
311 */
312 if ( n == '\0' && (f == ',' || f == ':' || f == ';' || f == '=') )
313 res = 0;
314
315 return res;
316 }
317 }
318 }
319
320 unsigned int tainted;
321
322 /**
323 * print_tainted - return a string to represent the kernel taint state.
324 *
325 * 'C' - Console output is synchronous.
326 * 'E' - An error (e.g. a machine check exceptions) has been injected.
327 * 'H' - HVM forced emulation prefix is permitted.
328 * 'M' - Machine had a machine check experience.
329 *
330 * The string is overwritten by the next call to print_taint().
331 */
print_tainted(char * str)332 char *print_tainted(char *str)
333 {
334 if ( tainted )
335 {
336 snprintf(str, TAINT_STRING_MAX_LEN, "Tainted: %c%c%c%c",
337 tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
338 tainted & TAINT_SYNC_CONSOLE ? 'C' : ' ',
339 tainted & TAINT_ERROR_INJECT ? 'E' : ' ',
340 tainted & TAINT_HVM_FEP ? 'H' : ' ');
341 }
342 else
343 {
344 snprintf(str, TAINT_STRING_MAX_LEN, "Not tainted");
345 }
346
347 return str;
348 }
349
add_taint(unsigned int flag)350 void add_taint(unsigned int flag)
351 {
352 tainted |= flag;
353 }
354
355 extern const initcall_t __initcall_start[], __presmp_initcall_end[],
356 __initcall_end[];
357
do_presmp_initcalls(void)358 void __init do_presmp_initcalls(void)
359 {
360 const initcall_t *call;
361 for ( call = __initcall_start; call < __presmp_initcall_end; call++ )
362 (*call)();
363 }
364
do_initcalls(void)365 void __init do_initcalls(void)
366 {
367 const initcall_t *call;
368 for ( call = __presmp_initcall_end; call < __initcall_end; call++ )
369 (*call)();
370 }
371
372 #ifdef CONFIG_HYPFS
373 static unsigned int __read_mostly major_version;
374 static unsigned int __read_mostly minor_version;
375
376 static HYPFS_DIR_INIT(buildinfo, "buildinfo");
377 static HYPFS_DIR_INIT(compileinfo, "compileinfo");
378 static HYPFS_DIR_INIT(version, "version");
379 static HYPFS_UINT_INIT(major, "major", major_version);
380 static HYPFS_UINT_INIT(minor, "minor", minor_version);
381 static HYPFS_STRING_INIT(changeset, "changeset");
382 static HYPFS_STRING_INIT(compiler, "compiler");
383 static HYPFS_STRING_INIT(compile_by, "compile_by");
384 static HYPFS_STRING_INIT(compile_date, "compile_date");
385 static HYPFS_STRING_INIT(compile_domain, "compile_domain");
386 static HYPFS_STRING_INIT(extra, "extra");
387
388 #ifdef CONFIG_HYPFS_CONFIG
389 static HYPFS_STRING_INIT(config, "config");
390 #endif
391
buildinfo_init(void)392 static int __init buildinfo_init(void)
393 {
394 hypfs_add_dir(&hypfs_root, &buildinfo, true);
395
396 hypfs_string_set_reference(&changeset, xen_changeset());
397 hypfs_add_leaf(&buildinfo, &changeset, true);
398
399 hypfs_add_dir(&buildinfo, &compileinfo, true);
400 hypfs_string_set_reference(&compiler, xen_compiler());
401 hypfs_string_set_reference(&compile_by, xen_compile_by());
402 hypfs_string_set_reference(&compile_date, xen_compile_date());
403 hypfs_string_set_reference(&compile_domain, xen_compile_domain());
404 hypfs_add_leaf(&compileinfo, &compiler, true);
405 hypfs_add_leaf(&compileinfo, &compile_by, true);
406 hypfs_add_leaf(&compileinfo, &compile_date, true);
407 hypfs_add_leaf(&compileinfo, &compile_domain, true);
408
409 major_version = xen_major_version();
410 minor_version = xen_minor_version();
411 hypfs_add_dir(&buildinfo, &version, true);
412 hypfs_string_set_reference(&extra, xen_extra_version());
413 hypfs_add_leaf(&version, &extra, true);
414 hypfs_add_leaf(&version, &major, true);
415 hypfs_add_leaf(&version, &minor, true);
416
417 #ifdef CONFIG_HYPFS_CONFIG
418 config.e.encoding = XEN_HYPFS_ENC_GZIP;
419 config.e.size = xen_config_data_size;
420 config.u.content = xen_config_data;
421 hypfs_add_leaf(&buildinfo, &config, true);
422 #endif
423
424 return 0;
425 }
426 __initcall(buildinfo_init);
427
428 static HYPFS_DIR_INIT(params, "params");
429
param_init(void)430 static int __init param_init(void)
431 {
432 struct param_hypfs *param;
433
434 hypfs_add_dir(&hypfs_root, ¶ms, true);
435
436 for ( param = __paramhypfs_start; param < __paramhypfs_end; param++ )
437 {
438 if ( param->init_leaf )
439 param->init_leaf(param);
440 else if ( param->hypfs.e.type == XEN_HYPFS_TYPE_STRING )
441 param->hypfs.e.size = strlen(param->hypfs.u.content) + 1;
442 hypfs_add_leaf(¶ms, ¶m->hypfs, true);
443 }
444
445 return 0;
446 }
447 __initcall(param_init);
448 #endif
449
450 # define DO(fn) long do_##fn
451
452 #endif
453
454 /*
455 * Simple hypercalls.
456 */
457
DO(xen_version)458 DO(xen_version)(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
459 {
460 bool_t deny = !!xsm_xen_version(XSM_OTHER, cmd);
461
462 switch ( cmd )
463 {
464 case XENVER_version:
465 return (xen_major_version() << 16) | xen_minor_version();
466
467 case XENVER_extraversion:
468 {
469 xen_extraversion_t extraversion;
470
471 memset(extraversion, 0, sizeof(extraversion));
472 safe_strcpy(extraversion, deny ? xen_deny() : xen_extra_version());
473 if ( copy_to_guest(arg, extraversion, ARRAY_SIZE(extraversion)) )
474 return -EFAULT;
475 return 0;
476 }
477
478 case XENVER_compile_info:
479 {
480 xen_compile_info_t info;
481
482 memset(&info, 0, sizeof(info));
483 safe_strcpy(info.compiler, deny ? xen_deny() : xen_compiler());
484 safe_strcpy(info.compile_by, deny ? xen_deny() : xen_compile_by());
485 safe_strcpy(info.compile_domain, deny ? xen_deny() : xen_compile_domain());
486 safe_strcpy(info.compile_date, deny ? xen_deny() : xen_compile_date());
487 if ( copy_to_guest(arg, &info, 1) )
488 return -EFAULT;
489 return 0;
490 }
491
492 case XENVER_capabilities:
493 {
494 xen_capabilities_info_t info;
495
496 memset(info, 0, sizeof(info));
497 if ( !deny )
498 arch_get_xen_caps(&info);
499
500 if ( copy_to_guest(arg, info, ARRAY_SIZE(info)) )
501 return -EFAULT;
502 return 0;
503 }
504
505 case XENVER_platform_parameters:
506 {
507 xen_platform_parameters_t params = {
508 .virt_start = HYPERVISOR_VIRT_START
509 };
510
511 if ( copy_to_guest(arg, ¶ms, 1) )
512 return -EFAULT;
513 return 0;
514
515 }
516
517 case XENVER_changeset:
518 {
519 xen_changeset_info_t chgset;
520
521 memset(chgset, 0, sizeof(chgset));
522 safe_strcpy(chgset, deny ? xen_deny() : xen_changeset());
523 if ( copy_to_guest(arg, chgset, ARRAY_SIZE(chgset)) )
524 return -EFAULT;
525 return 0;
526 }
527
528 case XENVER_get_features:
529 {
530 xen_feature_info_t fi;
531 struct domain *d = current->domain;
532
533 if ( copy_from_guest(&fi, arg, 1) )
534 return -EFAULT;
535
536 switch ( fi.submap_idx )
537 {
538 case 0:
539 fi.submap = (1U << XENFEAT_memory_op_vnode_supported);
540 if ( VM_ASSIST(d, pae_extended_cr3) )
541 fi.submap |= (1U << XENFEAT_pae_pgdir_above_4gb);
542 if ( paging_mode_translate(d) )
543 fi.submap |=
544 (1U << XENFEAT_writable_page_tables) |
545 (1U << XENFEAT_auto_translated_physmap);
546 if ( is_hardware_domain(d) )
547 fi.submap |= 1U << XENFEAT_dom0;
548 #ifdef CONFIG_ARM
549 fi.submap |= (1U << XENFEAT_ARM_SMCCC_supported);
550 #endif
551 #ifdef CONFIG_X86
552 if ( is_pv_domain(d) )
553 fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
554 (1U << XENFEAT_highmem_assist) |
555 (1U << XENFEAT_gnttab_map_avail_bits);
556 else
557 fi.submap |= (1U << XENFEAT_hvm_safe_pvclock) |
558 (1U << XENFEAT_hvm_callback_vector) |
559 (has_pirq(d) ? (1U << XENFEAT_hvm_pirqs) : 0);
560 #endif
561 break;
562 default:
563 return -EINVAL;
564 }
565
566 if ( __copy_to_guest(arg, &fi, 1) )
567 return -EFAULT;
568 return 0;
569 }
570
571 case XENVER_pagesize:
572 if ( deny )
573 return 0;
574 return (!guest_handle_is_null(arg) ? -EINVAL : PAGE_SIZE);
575
576 case XENVER_guest_handle:
577 {
578 xen_domain_handle_t hdl;
579
580 if ( deny )
581 memset(&hdl, 0, ARRAY_SIZE(hdl));
582
583 BUILD_BUG_ON(ARRAY_SIZE(current->domain->handle) != ARRAY_SIZE(hdl));
584
585 if ( copy_to_guest(arg, deny ? hdl : current->domain->handle,
586 ARRAY_SIZE(hdl) ) )
587 return -EFAULT;
588 return 0;
589 }
590
591 case XENVER_commandline:
592 {
593 size_t len = ARRAY_SIZE(saved_cmdline);
594
595 if ( deny )
596 len = strlen(xen_deny()) + 1;
597
598 if ( copy_to_guest(arg, deny ? xen_deny() : saved_cmdline, len) )
599 return -EFAULT;
600 return 0;
601 }
602
603 case XENVER_build_id:
604 {
605 xen_build_id_t build_id;
606 unsigned int sz;
607 int rc;
608 const void *p;
609
610 if ( deny )
611 return -EPERM;
612
613 /* Only return size. */
614 if ( !guest_handle_is_null(arg) )
615 {
616 if ( copy_from_guest(&build_id, arg, 1) )
617 return -EFAULT;
618
619 if ( build_id.len == 0 )
620 return -EINVAL;
621 }
622
623 rc = xen_build_id(&p, &sz);
624 if ( rc )
625 return rc;
626
627 if ( guest_handle_is_null(arg) )
628 return sz;
629
630 if ( sz > build_id.len )
631 return -ENOBUFS;
632
633 if ( copy_to_guest_offset(arg, offsetof(xen_build_id_t, buf), p, sz) )
634 return -EFAULT;
635
636 return sz;
637 }
638 }
639
640 return -ENOSYS;
641 }
642
643 /*
644 * Local variables:
645 * mode: C
646 * c-file-style: "BSD"
647 * c-basic-offset: 4
648 * tab-width: 4
649 * indent-tabs-mode: nil
650 * End:
651 */
652