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