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, ¶ms, 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