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/version.h>
11 #include <xen/sched.h>
12 #include <xen/paging.h>
13 #include <xen/guest_access.h>
14 #include <xen/hypercall.h>
15 #include <xsm/xsm.h>
16 #include <asm/current.h>
17 #include <public/version.h>
18 
19 #ifndef COMPAT
20 
21 enum system_state system_state = SYS_STATE_early_boot;
22 
23 xen_commandline_t saved_cmdline;
24 static const char __initconst opt_builtin_cmdline[] = CONFIG_CMDLINE;
25 
assign_integer_param(const struct kernel_param * param,uint64_t val)26 static int assign_integer_param(const struct kernel_param *param, uint64_t val)
27 {
28     switch ( param->len )
29     {
30     case sizeof(uint8_t):
31         if ( val > UINT8_MAX && val < (uint64_t)INT8_MIN )
32             return -EOVERFLOW;
33         *(uint8_t *)param->par.var = val;
34         break;
35     case sizeof(uint16_t):
36         if ( val > UINT16_MAX && val < (uint64_t)INT16_MIN )
37             return -EOVERFLOW;
38         *(uint16_t *)param->par.var = val;
39         break;
40     case sizeof(uint32_t):
41         if ( val > UINT32_MAX && val < (uint64_t)INT32_MIN )
42             return -EOVERFLOW;
43         *(uint32_t *)param->par.var = val;
44         break;
45     case sizeof(uint64_t):
46         *(uint64_t *)param->par.var = val;
47         break;
48     default:
49         BUG();
50     }
51 
52     return 0;
53 }
54 
parse_params(const char * cmdline,const struct kernel_param * start,const struct kernel_param * end)55 static int parse_params(const char *cmdline, const struct kernel_param *start,
56                         const struct kernel_param *end)
57 {
58     char opt[128], *optval, *optkey, *q;
59     const char *p = cmdline, *key;
60     const struct kernel_param *param;
61     int rc, final_rc = 0;
62     bool bool_assert, found;
63 
64     for ( ; ; )
65     {
66         /* Skip whitespace. */
67         while ( *p == ' ' )
68             p++;
69         if ( *p == '\0' )
70             break;
71 
72         /* Grab the next whitespace-delimited option. */
73         q = optkey = opt;
74         while ( (*p != ' ') && (*p != '\0') )
75         {
76             if ( (q-opt) < (sizeof(opt)-1) ) /* avoid overflow */
77                 *q++ = *p;
78             p++;
79         }
80         *q = '\0';
81 
82         /* Search for value part of a key=value option. */
83         optval = strchr(opt, '=');
84         if ( optval != NULL )
85         {
86             *optval++ = '\0'; /* nul-terminate the option value */
87             q = strpbrk(opt, "([{<");
88         }
89         else
90         {
91             optval = q;       /* default option value is empty string */
92             q = NULL;
93         }
94 
95         /* Boolean parameters can be inverted with 'no-' prefix. */
96         key = optkey;
97         bool_assert = !!strncmp("no-", optkey, 3);
98         if ( !bool_assert )
99             optkey += 3;
100 
101         rc = 0;
102         found = false;
103         for ( param = start; param < end; param++ )
104         {
105             int rctmp;
106             const char *s;
107 
108             if ( strcmp(param->name, optkey) )
109             {
110                 if ( param->type == OPT_CUSTOM && q &&
111                      strlen(param->name) == q + 1 - opt &&
112                      !strncmp(param->name, opt, q + 1 - opt) )
113                 {
114                     found = true;
115                     optval[-1] = '=';
116                     rctmp = param->par.func(q);
117                     optval[-1] = '\0';
118                     if ( !rc )
119                         rc = rctmp;
120                 }
121                 continue;
122             }
123 
124             rctmp = 0;
125             found = true;
126             switch ( param->type )
127             {
128             case OPT_STR:
129                 strlcpy(param->par.var, optval, param->len);
130                 break;
131             case OPT_UINT:
132                 rctmp = assign_integer_param(
133                     param,
134                     simple_strtoll(optval, &s, 0));
135                 if ( *s )
136                     rctmp = -EINVAL;
137                 break;
138             case OPT_BOOL:
139                 rctmp = *optval ? parse_bool(optval, NULL) : 1;
140                 if ( rctmp < 0 )
141                     break;
142                 if ( !rctmp )
143                     bool_assert = !bool_assert;
144                 rctmp = 0;
145                 assign_integer_param(param, bool_assert);
146                 break;
147             case OPT_SIZE:
148                 rctmp = assign_integer_param(
149                     param,
150                     parse_size_and_unit(optval, &s));
151                 if ( *s )
152                     rctmp = -EINVAL;
153                 break;
154             case OPT_CUSTOM:
155                 rctmp = -EINVAL;
156                 if ( !bool_assert )
157                 {
158                     if ( *optval )
159                         break;
160                     safe_strcpy(opt, "no");
161                     optval = opt;
162                 }
163                 rctmp = param->par.func(optval);
164                 break;
165             default:
166                 BUG();
167                 break;
168             }
169 
170             if ( !rc )
171                 rc = rctmp;
172         }
173 
174         if ( rc )
175         {
176             printk("parameter \"%s\" has invalid value \"%s\", rc=%d!\n",
177                     key, optval, rc);
178             final_rc = rc;
179         }
180         if ( !found )
181         {
182             printk("parameter \"%s\" unknown!\n", key);
183             final_rc = -EINVAL;
184         }
185     }
186 
187     return final_rc;
188 }
189 
_cmdline_parse(const char * cmdline)190 static void __init _cmdline_parse(const char *cmdline)
191 {
192     parse_params(cmdline, __setup_start, __setup_end);
193 }
194 
runtime_parse(const char * line)195 int runtime_parse(const char *line)
196 {
197     return parse_params(line, __param_start, __param_end);
198 }
199 
200 /**
201  *    cmdline_parse -- parses the xen command line.
202  * If CONFIG_CMDLINE is set, it would be parsed prior to @cmdline.
203  * But if CONFIG_CMDLINE_OVERRIDE is set to y, @cmdline will be ignored.
204  */
cmdline_parse(const char * cmdline)205 void __init cmdline_parse(const char *cmdline)
206 {
207     if ( opt_builtin_cmdline[0] )
208     {
209         printk("Built-in command line: %s\n", opt_builtin_cmdline);
210         _cmdline_parse(opt_builtin_cmdline);
211     }
212 
213 #ifndef CONFIG_CMDLINE_OVERRIDE
214     if ( cmdline == NULL )
215         return;
216 
217     safe_strcpy(saved_cmdline, cmdline);
218     _cmdline_parse(cmdline);
219 #endif
220 }
221 
parse_bool(const char * s,const char * e)222 int parse_bool(const char *s, const char *e)
223 {
224     unsigned int len;
225 
226     len = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
227     if ( !len )
228         return -1;
229 
230     if ( !strncmp("no", s, len) ||
231          !strncmp("off", s, len) ||
232          !strncmp("false", s, len) ||
233          !strncmp("disable", s, len) ||
234          !strncmp("0", s, len) )
235         return 0;
236 
237     if ( !strncmp("yes", s, len) ||
238          !strncmp("on", s, len) ||
239          !strncmp("true", s, len) ||
240          !strncmp("enable", s, len) ||
241          !strncmp("1", s, len) )
242         return 1;
243 
244     return -1;
245 }
246 
247 unsigned int tainted;
248 
249 /**
250  *      print_tainted - return a string to represent the kernel taint state.
251  *
252  *  'C' - Console output is synchronous.
253  *  'E' - An error (e.g. a machine check exceptions) has been injected.
254  *  'H' - HVM forced emulation prefix is permitted.
255  *  'M' - Machine had a machine check experience.
256  *
257  *      The string is overwritten by the next call to print_taint().
258  */
print_tainted(char * str)259 char *print_tainted(char *str)
260 {
261     if ( tainted )
262     {
263         snprintf(str, TAINT_STRING_MAX_LEN, "Tainted: %c%c%c%c",
264                  tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
265                  tainted & TAINT_SYNC_CONSOLE ? 'C' : ' ',
266                  tainted & TAINT_ERROR_INJECT ? 'E' : ' ',
267                  tainted & TAINT_HVM_FEP ? 'H' : ' ');
268     }
269     else
270     {
271         snprintf(str, TAINT_STRING_MAX_LEN, "Not tainted");
272     }
273 
274     return str;
275 }
276 
add_taint(unsigned int flag)277 void add_taint(unsigned int flag)
278 {
279     tainted |= flag;
280 }
281 
282 extern const initcall_t __initcall_start[], __presmp_initcall_end[],
283     __initcall_end[];
284 
do_presmp_initcalls(void)285 void __init do_presmp_initcalls(void)
286 {
287     const initcall_t *call;
288     for ( call = __initcall_start; call < __presmp_initcall_end; call++ )
289         (*call)();
290 }
291 
do_initcalls(void)292 void __init do_initcalls(void)
293 {
294     const initcall_t *call;
295     for ( call = __presmp_initcall_end; call < __initcall_end; call++ )
296         (*call)();
297 }
298 
299 # define DO(fn) long do_##fn
300 
301 #endif
302 
303 /*
304  * Simple hypercalls.
305  */
306 
DO(xen_version)307 DO(xen_version)(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
308 {
309     bool_t deny = !!xsm_xen_version(XSM_OTHER, cmd);
310 
311     switch ( cmd )
312     {
313     case XENVER_version:
314         return (xen_major_version() << 16) | xen_minor_version();
315 
316     case XENVER_extraversion:
317     {
318         xen_extraversion_t extraversion;
319 
320         memset(extraversion, 0, sizeof(extraversion));
321         safe_strcpy(extraversion, deny ? xen_deny() : xen_extra_version());
322         if ( copy_to_guest(arg, extraversion, ARRAY_SIZE(extraversion)) )
323             return -EFAULT;
324         return 0;
325     }
326 
327     case XENVER_compile_info:
328     {
329         xen_compile_info_t info;
330 
331         memset(&info, 0, sizeof(info));
332         safe_strcpy(info.compiler,       deny ? xen_deny() : xen_compiler());
333         safe_strcpy(info.compile_by,     deny ? xen_deny() : xen_compile_by());
334         safe_strcpy(info.compile_domain, deny ? xen_deny() : xen_compile_domain());
335         safe_strcpy(info.compile_date,   deny ? xen_deny() : xen_compile_date());
336         if ( copy_to_guest(arg, &info, 1) )
337             return -EFAULT;
338         return 0;
339     }
340 
341     case XENVER_capabilities:
342     {
343         xen_capabilities_info_t info;
344 
345         memset(info, 0, sizeof(info));
346         if ( !deny )
347             arch_get_xen_caps(&info);
348 
349         if ( copy_to_guest(arg, info, ARRAY_SIZE(info)) )
350             return -EFAULT;
351         return 0;
352     }
353 
354     case XENVER_platform_parameters:
355     {
356         xen_platform_parameters_t params = {
357             .virt_start = HYPERVISOR_VIRT_START
358         };
359 
360         if ( copy_to_guest(arg, &params, 1) )
361             return -EFAULT;
362         return 0;
363 
364     }
365 
366     case XENVER_changeset:
367     {
368         xen_changeset_info_t chgset;
369 
370         memset(chgset, 0, sizeof(chgset));
371         safe_strcpy(chgset, deny ? xen_deny() : xen_changeset());
372         if ( copy_to_guest(arg, chgset, ARRAY_SIZE(chgset)) )
373             return -EFAULT;
374         return 0;
375     }
376 
377     case XENVER_get_features:
378     {
379         xen_feature_info_t fi;
380         struct domain *d = current->domain;
381 
382         if ( copy_from_guest(&fi, arg, 1) )
383             return -EFAULT;
384 
385         switch ( fi.submap_idx )
386         {
387         case 0:
388             fi.submap = (1U << XENFEAT_memory_op_vnode_supported);
389             if ( VM_ASSIST(d, pae_extended_cr3) )
390                 fi.submap |= (1U << XENFEAT_pae_pgdir_above_4gb);
391             if ( paging_mode_translate(d) )
392                 fi.submap |=
393                     (1U << XENFEAT_writable_page_tables) |
394                     (1U << XENFEAT_auto_translated_physmap);
395             if ( is_hardware_domain(d) )
396                 fi.submap |= 1U << XENFEAT_dom0;
397 #ifdef CONFIG_ARM
398             fi.submap |= (1U << XENFEAT_ARM_SMCCC_supported);
399 #endif
400 #ifdef CONFIG_X86
401             switch ( d->guest_type )
402             {
403             case guest_type_pv:
404                 fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
405                              (1U << XENFEAT_highmem_assist) |
406                              (1U << XENFEAT_gnttab_map_avail_bits);
407                 break;
408             case guest_type_hvm:
409                 fi.submap |= (1U << XENFEAT_hvm_safe_pvclock) |
410                              (1U << XENFEAT_hvm_callback_vector) |
411                              (has_pirq(d) ? (1U << XENFEAT_hvm_pirqs) : 0);
412                 break;
413             }
414 #endif
415             break;
416         default:
417             return -EINVAL;
418         }
419 
420         if ( __copy_to_guest(arg, &fi, 1) )
421             return -EFAULT;
422         return 0;
423     }
424 
425     case XENVER_pagesize:
426         if ( deny )
427             return 0;
428         return (!guest_handle_is_null(arg) ? -EINVAL : PAGE_SIZE);
429 
430     case XENVER_guest_handle:
431     {
432         xen_domain_handle_t hdl;
433 
434         if ( deny )
435             memset(&hdl, 0, ARRAY_SIZE(hdl));
436 
437         BUILD_BUG_ON(ARRAY_SIZE(current->domain->handle) != ARRAY_SIZE(hdl));
438 
439         if ( copy_to_guest(arg, deny ? hdl : current->domain->handle,
440                            ARRAY_SIZE(hdl) ) )
441             return -EFAULT;
442         return 0;
443     }
444 
445     case XENVER_commandline:
446     {
447         size_t len = ARRAY_SIZE(saved_cmdline);
448 
449         if ( deny )
450             len = strlen(xen_deny()) + 1;
451 
452         if ( copy_to_guest(arg, deny ? xen_deny() : saved_cmdline, len) )
453             return -EFAULT;
454         return 0;
455     }
456 
457     case XENVER_build_id:
458     {
459         xen_build_id_t build_id;
460         unsigned int sz;
461         int rc;
462         const void *p;
463 
464         if ( deny )
465             return -EPERM;
466 
467         /* Only return size. */
468         if ( !guest_handle_is_null(arg) )
469         {
470             if ( copy_from_guest(&build_id, arg, 1) )
471                 return -EFAULT;
472 
473             if ( build_id.len == 0 )
474                 return -EINVAL;
475         }
476 
477         rc = xen_build_id(&p, &sz);
478         if ( rc )
479             return rc;
480 
481         if ( guest_handle_is_null(arg) )
482             return sz;
483 
484         if ( sz > build_id.len )
485             return -ENOBUFS;
486 
487         if ( copy_to_guest_offset(arg, offsetof(xen_build_id_t, buf), p, sz) )
488             return -EFAULT;
489 
490         return sz;
491     }
492     }
493 
494     return -ENOSYS;
495 }
496 
497 #ifdef VM_ASSIST_VALID
DO(vm_assist)498 DO(vm_assist)(unsigned int cmd, unsigned int type)
499 {
500     return vm_assist(current->domain, cmd, type, VM_ASSIST_VALID);
501 }
502 #endif
503 
504 /*
505  * Local variables:
506  * mode: C
507  * c-file-style: "BSD"
508  * c-basic-offset: 4
509  * tab-width: 4
510  * indent-tabs-mode: nil
511  * End:
512  */
513