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