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, &params, 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(&params, &param->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, &params, 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