ia64/linux-2.6.18-xen.hg

view arch/ia64/xen/xcom_privcmd.c @ 782:9ab1c319531f

merge with linux-2.6.18-xen.hg
author Isaku Yamahata <yamahata@valinux.co.jp>
date Wed Jan 28 13:07:23 2009 +0900 (2009-01-28)
parents 4caff484c9f4 93ea69924241
children 5bb4e5dd1abc
line source
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
17 * Tristan Gingold <tristan.gingold@bull.net>
18 */
19 #include <linux/types.h>
20 #include <linux/errno.h>
21 #include <linux/kernel.h>
22 #include <linux/gfp.h>
23 #include <linux/module.h>
24 #include <xen/interface/xen.h>
25 #include <xen/interface/platform.h>
26 #define __XEN__
27 #include <xen/interface/domctl.h>
28 #include <xen/interface/sysctl.h>
29 #include <xen/interface/memory.h>
30 #include <xen/interface/version.h>
31 #include <xen/interface/event_channel.h>
32 #include <xen/interface/xsm/acm_ops.h>
33 #include <xen/interface/hvm/params.h>
34 #include <xen/interface/arch-ia64/debug_op.h>
35 #include <xen/public/privcmd.h>
36 #include <asm/hypercall.h>
37 #include <asm/page.h>
38 #include <asm/uaccess.h>
39 #include <asm/xen/xencomm.h>
41 #define ROUND_DIV(v,s) (((v) + (s) - 1) / (s))
43 static int
44 xencomm_privcmd_platform_op(privcmd_hypercall_t *hypercall)
45 {
46 struct xen_platform_op kern_op;
47 struct xen_platform_op __user *user_op = (struct xen_platform_op __user *)hypercall->arg[0];
48 struct xencomm_handle *op_desc;
49 struct xencomm_handle *desc = NULL;
50 int ret = 0;
52 if (copy_from_user(&kern_op, user_op, sizeof(struct xen_platform_op)))
53 return -EFAULT;
55 if (kern_op.interface_version != XENPF_INTERFACE_VERSION)
56 return -EACCES;
58 op_desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
60 switch (kern_op.cmd) {
61 default:
62 printk("%s: unknown platform cmd %d\n", __func__, kern_op.cmd);
63 return -ENOSYS;
64 }
66 if (ret) {
67 /* error mapping the nested pointer */
68 return ret;
69 }
71 ret = xencomm_arch_hypercall_platform_op(op_desc);
73 /* FIXME: should we restore the handle? */
74 if (copy_to_user(user_op, &kern_op, sizeof(struct xen_platform_op)))
75 ret = -EFAULT;
77 xencomm_free(desc);
78 return ret;
79 }
81 static int
82 xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall)
83 {
84 xen_sysctl_t kern_op;
85 xen_sysctl_t __user *user_op;
86 struct xencomm_handle *op_desc;
87 struct xencomm_handle *desc = NULL;
88 struct xencomm_handle *desc1 = NULL;
89 int ret = 0;
91 user_op = (xen_sysctl_t __user *)hypercall->arg[0];
93 if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t)))
94 return -EFAULT;
96 if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION)
97 return -EACCES;
99 op_desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
101 switch (kern_op.cmd) {
102 case XEN_SYSCTL_readconsole:
103 desc = xencomm_map(
104 xen_guest_handle(kern_op.u.readconsole.buffer),
105 kern_op.u.readconsole.count);
106 if (xen_guest_handle(kern_op.u.readconsole.buffer) != NULL &&
107 kern_op.u.readconsole.count > 0 && desc == NULL)
108 return -ENOMEM;
109 set_xen_guest_handle(kern_op.u.readconsole.buffer,
110 (void *)desc);
111 break;
112 case XEN_SYSCTL_tbuf_op:
113 case XEN_SYSCTL_sched_id:
114 case XEN_SYSCTL_availheap:
115 break;
116 case XEN_SYSCTL_perfc_op:
117 {
118 struct xencomm_handle *tmp_desc;
119 xen_sysctl_t tmp_op = {
120 .cmd = XEN_SYSCTL_perfc_op,
121 .interface_version = XEN_SYSCTL_INTERFACE_VERSION,
122 .u.perfc_op = {
123 .cmd = XEN_SYSCTL_PERFCOP_query,
124 /* .desc.p = NULL, */
125 /* .val.p = NULL, */
126 },
127 };
129 if (xen_guest_handle(kern_op.u.perfc_op.desc) == NULL) {
130 if (xen_guest_handle(kern_op.u.perfc_op.val) != NULL)
131 return -EINVAL;
132 break;
133 }
135 /* query the buffer size for xencomm */
136 tmp_desc = xencomm_map_no_alloc(&tmp_op, sizeof(tmp_op));
137 ret = xencomm_arch_hypercall_sysctl(tmp_desc);
138 if (ret)
139 return ret;
141 desc = xencomm_map(xen_guest_handle(kern_op.u.perfc_op.desc),
142 tmp_op.u.perfc_op.nr_counters *
143 sizeof(xen_sysctl_perfc_desc_t));
144 if (xen_guest_handle(kern_op.u.perfc_op.desc) != NULL &&
145 tmp_op.u.perfc_op.nr_counters > 0 && desc == NULL)
146 return -ENOMEM;
148 set_xen_guest_handle(kern_op.u.perfc_op.desc, (void *)desc);
150 desc1 = xencomm_map(xen_guest_handle(kern_op.u.perfc_op.val),
151 tmp_op.u.perfc_op.nr_vals *
152 sizeof(xen_sysctl_perfc_val_t));
153 if (xen_guest_handle(kern_op.u.perfc_op.val) != NULL &&
154 tmp_op.u.perfc_op.nr_vals > 0 && desc1 == NULL) {
155 xencomm_free(desc);
156 return -ENOMEM;
157 }
159 set_xen_guest_handle(kern_op.u.perfc_op.val, (void *)desc1);
160 break;
161 }
162 case XEN_SYSCTL_getdomaininfolist:
163 desc = xencomm_map(
164 xen_guest_handle(kern_op.u.getdomaininfolist.buffer),
165 kern_op.u.getdomaininfolist.max_domains *
166 sizeof(xen_domctl_getdomaininfo_t));
167 if (xen_guest_handle(kern_op.u.getdomaininfolist.buffer) !=
168 NULL && kern_op.u.getdomaininfolist.max_domains > 0 &&
169 desc == NULL)
170 return -ENOMEM;
171 set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer,
172 (void *)desc);
173 break;
174 case XEN_SYSCTL_debug_keys:
175 desc = xencomm_map(
176 xen_guest_handle(kern_op.u.debug_keys.keys),
177 kern_op.u.debug_keys.nr_keys);
178 if (xen_guest_handle(kern_op.u.debug_keys.keys) != NULL &&
179 kern_op.u.debug_keys.nr_keys > 0 && desc == NULL)
180 return -ENOMEM;
181 set_xen_guest_handle(kern_op.u.debug_keys.keys,
182 (void *)desc);
183 break;
185 case XEN_SYSCTL_physinfo:
186 desc = xencomm_map(
187 xen_guest_handle(kern_op.u.physinfo.cpu_to_node),
188 kern_op.u.physinfo.max_cpu_id * sizeof(uint32_t));
189 if (xen_guest_handle(kern_op.u.physinfo.cpu_to_node) != NULL &&
190 kern_op.u.physinfo.max_cpu_id > 0 && desc == NULL)
191 return -ENOMEM;
193 set_xen_guest_handle(kern_op.u.physinfo.cpu_to_node,
194 (void *)desc);
195 break;
197 case XEN_SYSCTL_get_pmstat:
198 if (kern_op.u.get_pmstat.type == PMSTAT_get_pxstat) {
199 struct pm_px_stat *getpx =
200 &kern_op.u.get_pmstat.u.getpx;
201 desc = xencomm_map(
202 xen_guest_handle(getpx->trans_pt),
203 getpx->total * getpx->total *
204 sizeof(uint64_t));
205 if (xen_guest_handle(getpx->trans_pt) != NULL &&
206 getpx->total > 0 && desc == NULL)
207 return -ENOMEM;
209 set_xen_guest_handle(getpx->trans_pt, (void *)desc);
211 desc1 = xencomm_map(xen_guest_handle(getpx->pt),
212 getpx->total * sizeof(pm_px_val_t));
213 if (xen_guest_handle(getpx->pt) != NULL &&
214 getpx->total > 0 && desc1 == NULL)
215 return -ENOMEM;
217 set_xen_guest_handle(getpx->pt, (void *)desc1);
218 }
219 break;
221 default:
222 printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd);
223 return -ENOSYS;
224 }
226 if (ret) {
227 /* error mapping the nested pointer */
228 return ret;
229 }
231 ret = xencomm_arch_hypercall_sysctl(op_desc);
233 /* FIXME: should we restore the handles? */
234 if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t)))
235 ret = -EFAULT;
237 xencomm_free(desc);
238 xencomm_free(desc1);
239 return ret;
240 }
242 static int
243 xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall)
244 {
245 xen_domctl_t kern_op;
246 xen_domctl_t __user *user_op;
247 struct xencomm_handle *op_desc;
248 struct xencomm_handle *desc = NULL;
249 int ret = 0;
251 user_op = (xen_domctl_t __user *)hypercall->arg[0];
253 if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t)))
254 return -EFAULT;
256 if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION)
257 return -EACCES;
259 op_desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
261 switch (kern_op.cmd) {
262 case XEN_DOMCTL_createdomain:
263 case XEN_DOMCTL_destroydomain:
264 case XEN_DOMCTL_pausedomain:
265 case XEN_DOMCTL_unpausedomain:
266 case XEN_DOMCTL_resumedomain:
267 case XEN_DOMCTL_getdomaininfo:
268 break;
269 case XEN_DOMCTL_getmemlist:
270 {
271 unsigned long nr_pages = kern_op.u.getmemlist.max_pfns;
273 desc = xencomm_map(
274 xen_guest_handle(kern_op.u.getmemlist.buffer),
275 nr_pages * sizeof(unsigned long));
276 if (xen_guest_handle(kern_op.u.getmemlist.buffer) != NULL &&
277 nr_pages > 0 && desc == NULL)
278 return -ENOMEM;
279 set_xen_guest_handle(kern_op.u.getmemlist.buffer,
280 (void *)desc);
281 break;
282 }
283 case XEN_DOMCTL_getpageframeinfo:
284 break;
285 case XEN_DOMCTL_getpageframeinfo2:
286 desc = xencomm_map(
287 xen_guest_handle(kern_op.u.getpageframeinfo2.array),
288 kern_op.u.getpageframeinfo2.num);
289 if (xen_guest_handle(kern_op.u.getpageframeinfo2.array) !=
290 NULL && kern_op.u.getpageframeinfo2.num > 0 &&
291 desc == NULL)
292 return -ENOMEM;
293 set_xen_guest_handle(kern_op.u.getpageframeinfo2.array,
294 (void *)desc);
295 break;
296 case XEN_DOMCTL_shadow_op:
297 desc = xencomm_map(
298 xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap),
299 ROUND_DIV(kern_op.u.shadow_op.pages, 8));
300 if (xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap) != NULL
301 && kern_op.u.shadow_op.pages > 0 && desc == NULL)
302 return -ENOMEM;
303 set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap,
304 (void *)desc);
305 break;
306 case XEN_DOMCTL_max_mem:
307 break;
308 case XEN_DOMCTL_setvcpucontext:
309 case XEN_DOMCTL_getvcpucontext:
310 desc = xencomm_map(
311 xen_guest_handle(kern_op.u.vcpucontext.ctxt),
312 sizeof(vcpu_guest_context_t));
313 if (xen_guest_handle(kern_op.u.vcpucontext.ctxt) != NULL &&
314 desc == NULL)
315 return -ENOMEM;
316 set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc);
317 break;
318 case XEN_DOMCTL_getvcpuinfo:
319 break;
320 case XEN_DOMCTL_setvcpuaffinity:
321 case XEN_DOMCTL_getvcpuaffinity:
322 desc = xencomm_map(
323 xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap),
324 ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8));
325 if (xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap) !=
326 NULL && kern_op.u.vcpuaffinity.cpumap.nr_cpus > 0 &&
327 desc == NULL)
328 return -ENOMEM;
329 set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap,
330 (void *)desc);
331 break;
332 case XEN_DOMCTL_gethvmcontext:
333 case XEN_DOMCTL_sethvmcontext:
334 if (kern_op.u.hvmcontext.size > 0)
335 desc = xencomm_map(
336 xen_guest_handle(kern_op.u.hvmcontext.buffer),
337 kern_op.u.hvmcontext.size);
338 if (xen_guest_handle(kern_op.u.hvmcontext.buffer) != NULL &&
339 kern_op.u.hvmcontext.size > 0 && desc == NULL)
340 return -ENOMEM;
341 set_xen_guest_handle(kern_op.u.hvmcontext.buffer, (void*)desc);
342 break;
343 case XEN_DOMCTL_get_device_group:
344 {
345 struct xen_domctl_get_device_group *get_device_group =
346 &kern_op.u.get_device_group;
347 desc = xencomm_map(
348 xen_guest_handle(get_device_group->sdev_array),
349 get_device_group->max_sdevs * sizeof(uint32_t));
350 if (xen_guest_handle(get_device_group->sdev_array) != NULL &&
351 get_device_group->max_sdevs > 0 && desc == NULL)
352 return -ENOMEM;
353 set_xen_guest_handle(kern_op.u.get_device_group.sdev_array,
354 (void*)desc);
355 break;
356 }
357 case XEN_DOMCTL_max_vcpus:
358 case XEN_DOMCTL_scheduler_op:
359 case XEN_DOMCTL_setdomainhandle:
360 case XEN_DOMCTL_setdebugging:
361 case XEN_DOMCTL_irq_permission:
362 case XEN_DOMCTL_iomem_permission:
363 case XEN_DOMCTL_ioport_permission:
364 case XEN_DOMCTL_hypercall_init:
365 case XEN_DOMCTL_arch_setup:
366 case XEN_DOMCTL_settimeoffset:
367 case XEN_DOMCTL_sendtrigger:
368 case XEN_DOMCTL_set_opt_feature:
369 case XEN_DOMCTL_assign_device:
370 case XEN_DOMCTL_subscribe:
371 case XEN_DOMCTL_test_assign_device:
372 case XEN_DOMCTL_deassign_device:
373 case XEN_DOMCTL_bind_pt_irq:
374 case XEN_DOMCTL_unbind_pt_irq:
375 case XEN_DOMCTL_memory_mapping:
376 case XEN_DOMCTL_ioport_mapping:
377 case XEN_DOMCTL_set_address_size:
378 case XEN_DOMCTL_get_address_size:
379 break;
380 case XEN_DOMCTL_pin_mem_cacheattr:
381 return -ENOSYS;
382 default:
383 printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd);
384 return -ENOSYS;
385 }
387 if (ret) {
388 /* error mapping the nested pointer */
389 return ret;
390 }
392 ret = xencomm_arch_hypercall_domctl (op_desc);
394 /* FIXME: should we restore the handle? */
395 if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t)))
396 ret = -EFAULT;
398 xencomm_free(desc);
399 return ret;
400 }
402 static int
403 xencomm_privcmd_xsm_op(privcmd_hypercall_t *hypercall)
404 {
405 void __user *arg = (void __user *)hypercall->arg[0];
406 xen_acmctl_t kern_arg;
407 struct xencomm_handle *op_desc;
408 struct xencomm_handle *desc = NULL;
409 int ret;
411 if (copy_from_user(&kern_arg, arg, sizeof(kern_arg)))
412 return -EFAULT;
413 if (kern_arg.interface_version != ACM_INTERFACE_VERSION)
414 return -ENOSYS;
416 switch (kern_arg.cmd) {
417 case ACMOP_getssid: {
418 op_desc = xencomm_map_no_alloc(&kern_arg, sizeof(kern_arg));
420 desc = xencomm_map(
421 xen_guest_handle(kern_arg.u.getssid.ssidbuf),
422 kern_arg.u.getssid.ssidbuf_size);
423 if (xen_guest_handle(kern_arg.u.getssid.ssidbuf) != NULL &&
424 kern_arg.u.getssid.ssidbuf_size > 0 && desc == NULL)
425 return -ENOMEM;
427 set_xen_guest_handle(kern_arg.u.getssid.ssidbuf, (void *)desc);
429 ret = xencomm_arch_hypercall_xsm_op(op_desc);
431 xencomm_free(desc);
433 if (copy_to_user(arg, &kern_arg, sizeof(kern_arg)))
434 return -EFAULT;
435 return ret;
436 }
437 default:
438 printk("%s: unknown acm_op cmd %d\n", __func__, kern_arg.cmd);
439 return -ENOSYS;
440 }
442 return ret;
443 }
445 static int
446 xencomm_privcmd_memory_reservation_op(privcmd_hypercall_t *hypercall)
447 {
448 const unsigned long cmd = hypercall->arg[0];
449 int ret = 0;
450 xen_memory_reservation_t kern_op;
451 xen_memory_reservation_t __user *user_op;
452 struct xencomm_handle *desc = NULL;
453 struct xencomm_handle *desc_op;
455 user_op = (xen_memory_reservation_t __user *)hypercall->arg[1];
456 if (copy_from_user(&kern_op, user_op,
457 sizeof(xen_memory_reservation_t)))
458 return -EFAULT;
459 desc_op = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
461 if (!xen_guest_handle(kern_op.extent_start)) {
462 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
463 if (ret < 0)
464 return ret;
465 } else {
466 xen_ulong_t nr_done = 0;
467 xen_ulong_t nr_extents = kern_op.nr_extents;
468 void *addr = xen_guest_handle(kern_op.extent_start);
470 /*
471 * Work around.
472 * Xencomm has single page size limit caused
473 * by xencomm_alloc()/xencomm_free() so that
474 * we have to repeat the hypercall.
475 * This limitation can be removed.
476 */
477 #define MEMORYOP_XENCOMM_LIMIT \
478 (((((PAGE_SIZE - sizeof(struct xencomm_desc)) / \
479 sizeof(uint64_t)) - 2) * PAGE_SIZE) / \
480 sizeof(*xen_guest_handle(kern_op.extent_start)))
482 /*
483 * Work around.
484 * Even if the above limitation is removed,
485 * the hypercall with large number of extents
486 * may cause the soft lockup warning.
487 * In order to avoid the warning, we limit
488 * the number of extents and repeat the hypercall.
489 * The following value is determined by evaluation.
490 * Time of one hypercall should be smaller than
491 * a vcpu time slice. The time with current
492 * MEMORYOP_MAX_EXTENTS is around 5 msec.
493 * If the following limit causes some issues,
494 * we should decrease this value.
495 *
496 * Another way would be that start with small value and
497 * increase adoptively measuring hypercall time.
498 * It might be over-kill.
499 */
500 #define MEMORYOP_MAX_EXTENTS (MEMORYOP_XENCOMM_LIMIT / 512)
502 while (nr_extents > 0) {
503 xen_ulong_t nr_tmp = nr_extents;
504 if (nr_tmp > MEMORYOP_MAX_EXTENTS)
505 nr_tmp = MEMORYOP_MAX_EXTENTS;
507 kern_op.nr_extents = nr_tmp;
508 desc = xencomm_map
509 (addr + nr_done * sizeof(*xen_guest_handle(kern_op.extent_start)),
510 nr_tmp * sizeof(*xen_guest_handle(kern_op.extent_start)));
511 if (addr != NULL && nr_tmp > 0 && desc == NULL)
512 return nr_done > 0 ? nr_done : -ENOMEM;
514 set_xen_guest_handle(kern_op.extent_start,
515 (void *)desc);
517 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
518 xencomm_free(desc);
519 if (ret < 0)
520 return nr_done > 0 ? nr_done : ret;
522 nr_done += ret;
523 nr_extents -= ret;
524 if (ret < nr_tmp)
525 break;
527 /*
528 * prevent softlock up message.
529 * give cpu to soft lockup kernel thread.
530 */
531 if (nr_extents > 0)
532 schedule();
533 }
534 ret = nr_done;
535 set_xen_guest_handle(kern_op.extent_start, addr);
536 }
538 if (copy_to_user(user_op, &kern_op, sizeof(xen_memory_reservation_t)))
539 return -EFAULT;
541 return ret;
542 }
544 static int
545 xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall)
546 {
547 const unsigned long cmd = hypercall->arg[0];
548 int ret = 0;
550 switch (cmd) {
551 case XENMEM_increase_reservation:
552 case XENMEM_decrease_reservation:
553 case XENMEM_populate_physmap:
554 return xencomm_privcmd_memory_reservation_op(hypercall);
555 case XENMEM_maximum_gpfn:
556 {
557 domid_t kern_domid;
558 domid_t __user *user_domid;
559 struct xencomm_handle *desc;
561 user_domid = (domid_t __user *)hypercall->arg[1];
562 if (copy_from_user(&kern_domid, user_domid, sizeof(domid_t)))
563 return -EFAULT;
564 desc = xencomm_map_no_alloc(&kern_domid, sizeof(kern_domid));
566 ret = xencomm_arch_hypercall_memory_op(cmd, desc);
568 return ret;
569 }
570 case XENMEM_add_to_physmap:
571 {
572 void __user *arg = (void __user *)hypercall->arg[1];
573 struct xencomm_handle *desc;
575 desc = xencomm_map(arg, sizeof(struct xen_add_to_physmap));
576 if (desc == NULL)
577 return -ENOMEM;
579 ret = xencomm_arch_hypercall_memory_op(cmd, desc);
581 xencomm_free(desc);
582 return ret;
583 }
584 default:
585 printk("%s: unknown memory op %lu\n", __func__, cmd);
586 ret = -ENOSYS;
587 }
588 return ret;
589 }
591 static int
592 xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall)
593 {
594 int cmd = hypercall->arg[0];
595 void __user *arg = (void __user *)hypercall->arg[1];
596 struct xencomm_handle *desc;
597 size_t argsize;
598 int rc;
600 switch (cmd) {
601 case XENVER_version:
602 /* do not actually pass an argument */
603 return xencomm_arch_hypercall_xen_version(cmd, 0);
604 case XENVER_extraversion:
605 argsize = sizeof(xen_extraversion_t);
606 break;
607 case XENVER_compile_info:
608 argsize = sizeof(xen_compile_info_t);
609 break;
610 case XENVER_capabilities:
611 argsize = sizeof(xen_capabilities_info_t);
612 break;
613 case XENVER_changeset:
614 argsize = sizeof(xen_changeset_info_t);
615 break;
616 case XENVER_platform_parameters:
617 argsize = sizeof(xen_platform_parameters_t);
618 break;
619 case XENVER_pagesize:
620 argsize = (arg == NULL) ? 0 : sizeof(void *);
621 break;
622 case XENVER_get_features:
623 argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
624 break;
626 default:
627 printk("%s: unknown version op %d\n", __func__, cmd);
628 return -ENOSYS;
629 }
631 desc = xencomm_map(arg, argsize);
632 if (arg != NULL && argsize > 0 && desc == NULL)
633 return -ENOMEM;
635 rc = xencomm_arch_hypercall_xen_version(cmd, desc);
637 xencomm_free(desc);
639 return rc;
640 }
642 static int
643 xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall)
644 {
645 int cmd = hypercall->arg[0];
646 struct xencomm_handle *desc;
647 unsigned int argsize;
648 int ret;
650 switch (cmd) {
651 case EVTCHNOP_alloc_unbound:
652 argsize = sizeof(evtchn_alloc_unbound_t);
653 break;
655 case EVTCHNOP_status:
656 argsize = sizeof(evtchn_status_t);
657 break;
659 default:
660 printk("%s: unknown EVTCHNOP %d\n", __func__, cmd);
661 return -EINVAL;
662 }
664 desc = xencomm_map((void *)hypercall->arg[1], argsize);
665 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
666 return -ENOMEM;
668 ret = xencomm_arch_hypercall_event_channel_op(cmd, desc);
670 xencomm_free(desc);
671 return ret;
672 }
674 static int
675 xencomm_privcmd_hvm_op_track_dirty_vram(privcmd_hypercall_t *hypercall)
676 {
677 #if 1
678 /*
679 * At this moment HVMOP_track_dirty_vram isn't implemented
680 * on xen/ia64 so that it just returns -ENOSYS.
681 * Don't issue hypercall to get -ENOSYS.
682 * When the hypercall is implemented, enable the following codes.
683 */
684 return -ENOSYS;
685 #else
686 int cmd = hypercall->arg[0];
687 struct xen_hvm_track_dirty_vram *user_op = (void*)hypercall->arg[1];
688 struct xen_hvm_track_dirty_vram kern_op;
689 struct xencomm_handle *desc;
690 struct xencomm_handle *bitmap_desc;
691 int ret;
693 BUG_ON(cmd != HVMOP_track_dirty_vram);
694 if (copy_from_user(&kern_op, user_op, sizeof(kern_op)))
695 return -EFAULT;
696 desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
697 bitmap_desc = xencomm_map(xen_guest_handle(kern_op.dirty_bitmap),
698 kern_op.nr * sizeof(uint8_t));
699 if (bitmap_desc == NULL)
700 return -ENOMEM;
701 set_xen_guest_handle(kern_op.dirty_bitmap, (void*)bitmap_desc);
702 ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
703 xencomm_free(bitmap_desc);
705 return ret;
706 #endif
707 }
709 static int
710 xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall)
711 {
712 int cmd = hypercall->arg[0];
713 struct xencomm_handle *desc;
714 unsigned int argsize;
715 int ret;
717 switch (cmd) {
718 case HVMOP_get_param:
719 case HVMOP_set_param:
720 argsize = sizeof(xen_hvm_param_t);
721 break;
722 case HVMOP_set_pci_intx_level:
723 argsize = sizeof(xen_hvm_set_pci_intx_level_t);
724 break;
725 case HVMOP_set_isa_irq_level:
726 argsize = sizeof(xen_hvm_set_isa_irq_level_t);
727 break;
728 case HVMOP_set_pci_link_route:
729 argsize = sizeof(xen_hvm_set_pci_link_route_t);
730 break;
731 case HVMOP_set_mem_type:
732 argsize = sizeof(xen_hvm_set_mem_type_t);
733 break;
735 case HVMOP_track_dirty_vram:
736 return xencomm_privcmd_hvm_op_track_dirty_vram(hypercall);
738 default:
739 printk("%s: unknown HVMOP %d\n", __func__, cmd);
740 return -EINVAL;
741 }
743 desc = xencomm_map((void *)hypercall->arg[1], argsize);
744 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
745 return -ENOMEM;
747 ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
749 xencomm_free(desc);
750 return ret;
751 }
753 static int
754 xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall)
755 {
756 int cmd = hypercall->arg[0];
757 struct xencomm_handle *desc;
758 unsigned int argsize;
759 int ret;
761 switch (cmd) {
762 case SCHEDOP_remote_shutdown:
763 argsize = sizeof(sched_remote_shutdown_t);
764 break;
765 default:
766 printk("%s: unknown SCHEDOP %d\n", __func__, cmd);
767 return -EINVAL;
768 }
770 desc = xencomm_map((void *)hypercall->arg[1], argsize);
771 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
772 return -ENOMEM;
774 ret = xencomm_arch_hypercall_sched_op(cmd, desc);
776 xencomm_free(desc);
777 return ret;
778 }
780 static int
781 xencomm_privcmd_dom0vp_get_memmap(domid_t domid,
782 char* __user buf, unsigned long bufsize)
783 {
784 int ret;
785 struct xencomm_handle *desc;
787 desc = xencomm_map(buf, bufsize);
788 if (bufsize > 0 && desc == NULL)
789 return -ENOMEM;
791 ret = xencomm_arch_hypercall_get_memmap((domid_t)domid, desc);
793 xencomm_free(desc);
794 return ret;
795 }
797 static int
798 xencomm_privcmd_ia64_dom0vp_op(privcmd_hypercall_t *hypercall)
799 {
800 int cmd = hypercall->arg[0];
801 int ret;
803 switch (cmd) {
804 case IA64_DOM0VP_fpswa_revision: {
805 unsigned int revision;
806 unsigned int __user *revision_user =
807 (unsigned int* __user)hypercall->arg[1];
808 struct xencomm_handle *desc;
809 desc = xencomm_map(&revision, sizeof(revision));
810 if (desc == NULL)
811 return -ENOMEM;
813 ret = xencomm_arch_hypercall_fpswa_revision(desc);
814 xencomm_free(desc);
815 if (ret)
816 break;
817 if (copy_to_user(revision_user, &revision, sizeof(revision)))
818 ret = -EFAULT;
819 break;
820 }
821 #ifdef CONFIG_XEN_IA64_EXPOSE_P2M
822 case IA64_DOM0VP_expose_foreign_p2m:
823 ret = xen_foreign_p2m_expose(hypercall);
824 break;
825 #endif
826 case IA64_DOM0VP_get_memmap:
827 ret = xencomm_privcmd_dom0vp_get_memmap(
828 (domid_t)hypercall->arg[1],
829 (char* __user)hypercall->arg[2], hypercall->arg[3]);
830 break;
831 default:
832 printk("%s: unknown IA64 DOM0VP op %d\n", __func__, cmd);
833 ret = -EINVAL;
834 break;
835 }
836 return ret;
837 }
839 static int
840 xencomm_privcmd_ia64_debug_op(privcmd_hypercall_t *hypercall)
841 {
842 int cmd = hypercall->arg[0];
843 unsigned long domain = hypercall->arg[1];
844 struct xencomm_handle *desc;
845 int ret;
847 switch (cmd) {
848 case XEN_IA64_DEBUG_OP_SET_FLAGS:
849 case XEN_IA64_DEBUG_OP_GET_FLAGS:
850 break;
851 default:
852 printk("%s: unknown IA64 DEBUGOP %d\n", __func__, cmd);
853 return -EINVAL;
854 }
856 desc = xencomm_map((void *)hypercall->arg[2],
857 sizeof(xen_ia64_debug_op_t));
858 if (desc == NULL)
859 return -ENOMEM;
861 ret = xencomm_arch_hypercall_ia64_debug_op(cmd, domain, desc);
863 xencomm_free(desc);
864 return ret;
865 }
867 static int
868 xencomm_privcmd_ia64_physdev_op(privcmd_hypercall_t *hypercall)
869 {
870 int cmd = hypercall->arg[0];
871 struct xencomm_handle *desc;
872 unsigned int argsize;
873 int ret;
875 switch (cmd) {
876 case PHYSDEVOP_map_pirq:
877 argsize = sizeof(physdev_map_pirq_t);
878 break;
879 case PHYSDEVOP_unmap_pirq:
880 argsize = sizeof(physdev_unmap_pirq_t);
881 break;
882 default:
883 printk("%s: unknown PHYSDEVOP %d\n", __func__, cmd);
884 return -EINVAL;
885 }
887 desc = xencomm_map((void *)hypercall->arg[1], argsize);
888 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
889 return -ENOMEM;
891 ret = xencomm_arch_hypercall_physdev_op(cmd, desc);
893 xencomm_free(desc);
894 return ret;
895 }
897 int
898 privcmd_hypercall(privcmd_hypercall_t *hypercall)
899 {
900 switch (hypercall->op) {
901 case __HYPERVISOR_platform_op:
902 return xencomm_privcmd_platform_op(hypercall);
903 case __HYPERVISOR_domctl:
904 return xencomm_privcmd_domctl(hypercall);
905 case __HYPERVISOR_sysctl:
906 return xencomm_privcmd_sysctl(hypercall);
907 case __HYPERVISOR_xsm_op:
908 return xencomm_privcmd_xsm_op(hypercall);
909 case __HYPERVISOR_xen_version:
910 return xencomm_privcmd_xen_version(hypercall);
911 case __HYPERVISOR_memory_op:
912 return xencomm_privcmd_memory_op(hypercall);
913 case __HYPERVISOR_event_channel_op:
914 return xencomm_privcmd_event_channel_op(hypercall);
915 case __HYPERVISOR_hvm_op:
916 return xencomm_privcmd_hvm_op(hypercall);
917 case __HYPERVISOR_sched_op:
918 return xencomm_privcmd_sched_op(hypercall);
919 case __HYPERVISOR_ia64_dom0vp_op:
920 return xencomm_privcmd_ia64_dom0vp_op(hypercall);
921 case __HYPERVISOR_ia64_debug_op:
922 return xencomm_privcmd_ia64_debug_op(hypercall);
923 case __HYPERVISOR_physdev_op:
924 return xencomm_privcmd_ia64_physdev_op(hypercall);
925 default:
926 printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op);
927 return -ENOSYS;
928 }
929 }