ia64/linux-2.6.18-xen.hg

view arch/ia64/xen/xcom_privcmd.c @ 673:3161879fdf22

[IA64] xencomm: support XENMEM_add_to_physmap and XENMEM_remove_from_phsymap

support XENMEM_add_to_physmap and XENMEM_remove_from_phsymap.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Isaku Yamahata <yamahata@valinux.co.jp>
date Tue Sep 16 21:26:15 2008 +0900 (2008-09-16)
parents 3440919f29f2
children 7d2d7b1deda4
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;
196 default:
197 printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd);
198 return -ENOSYS;
199 }
201 if (ret) {
202 /* error mapping the nested pointer */
203 return ret;
204 }
206 ret = xencomm_arch_hypercall_sysctl(op_desc);
208 /* FIXME: should we restore the handles? */
209 if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t)))
210 ret = -EFAULT;
212 xencomm_free(desc);
213 xencomm_free(desc1);
214 return ret;
215 }
217 static int
218 xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall)
219 {
220 xen_domctl_t kern_op;
221 xen_domctl_t __user *user_op;
222 struct xencomm_handle *op_desc;
223 struct xencomm_handle *desc = NULL;
224 int ret = 0;
226 user_op = (xen_domctl_t __user *)hypercall->arg[0];
228 if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t)))
229 return -EFAULT;
231 if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION)
232 return -EACCES;
234 op_desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
236 switch (kern_op.cmd) {
237 case XEN_DOMCTL_createdomain:
238 case XEN_DOMCTL_destroydomain:
239 case XEN_DOMCTL_pausedomain:
240 case XEN_DOMCTL_unpausedomain:
241 case XEN_DOMCTL_resumedomain:
242 case XEN_DOMCTL_getdomaininfo:
243 break;
244 case XEN_DOMCTL_getmemlist:
245 {
246 unsigned long nr_pages = kern_op.u.getmemlist.max_pfns;
248 desc = xencomm_map(
249 xen_guest_handle(kern_op.u.getmemlist.buffer),
250 nr_pages * sizeof(unsigned long));
251 if (xen_guest_handle(kern_op.u.getmemlist.buffer) != NULL &&
252 nr_pages > 0 && desc == NULL)
253 return -ENOMEM;
254 set_xen_guest_handle(kern_op.u.getmemlist.buffer,
255 (void *)desc);
256 break;
257 }
258 case XEN_DOMCTL_getpageframeinfo:
259 break;
260 case XEN_DOMCTL_getpageframeinfo2:
261 desc = xencomm_map(
262 xen_guest_handle(kern_op.u.getpageframeinfo2.array),
263 kern_op.u.getpageframeinfo2.num);
264 if (xen_guest_handle(kern_op.u.getpageframeinfo2.array) !=
265 NULL && kern_op.u.getpageframeinfo2.num > 0 &&
266 desc == NULL)
267 return -ENOMEM;
268 set_xen_guest_handle(kern_op.u.getpageframeinfo2.array,
269 (void *)desc);
270 break;
271 case XEN_DOMCTL_shadow_op:
272 desc = xencomm_map(
273 xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap),
274 ROUND_DIV(kern_op.u.shadow_op.pages, 8));
275 if (xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap) != NULL
276 && kern_op.u.shadow_op.pages > 0 && desc == NULL)
277 return -ENOMEM;
278 set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap,
279 (void *)desc);
280 break;
281 case XEN_DOMCTL_max_mem:
282 break;
283 case XEN_DOMCTL_setvcpucontext:
284 case XEN_DOMCTL_getvcpucontext:
285 desc = xencomm_map(
286 xen_guest_handle(kern_op.u.vcpucontext.ctxt),
287 sizeof(vcpu_guest_context_t));
288 if (xen_guest_handle(kern_op.u.vcpucontext.ctxt) != NULL &&
289 desc == NULL)
290 return -ENOMEM;
291 set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc);
292 break;
293 case XEN_DOMCTL_getvcpuinfo:
294 break;
295 case XEN_DOMCTL_setvcpuaffinity:
296 case XEN_DOMCTL_getvcpuaffinity:
297 desc = xencomm_map(
298 xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap),
299 ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8));
300 if (xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap) !=
301 NULL && kern_op.u.vcpuaffinity.cpumap.nr_cpus > 0 &&
302 desc == NULL)
303 return -ENOMEM;
304 set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap,
305 (void *)desc);
306 break;
307 case XEN_DOMCTL_gethvmcontext:
308 case XEN_DOMCTL_sethvmcontext:
309 if (kern_op.u.hvmcontext.size > 0)
310 desc = xencomm_map(
311 xen_guest_handle(kern_op.u.hvmcontext.buffer),
312 kern_op.u.hvmcontext.size);
313 if (xen_guest_handle(kern_op.u.hvmcontext.buffer) != NULL &&
314 kern_op.u.hvmcontext.size > 0 && desc == NULL)
315 return -ENOMEM;
316 set_xen_guest_handle(kern_op.u.hvmcontext.buffer, (void*)desc);
317 break;
318 case XEN_DOMCTL_max_vcpus:
319 case XEN_DOMCTL_scheduler_op:
320 case XEN_DOMCTL_setdomainhandle:
321 case XEN_DOMCTL_setdebugging:
322 case XEN_DOMCTL_irq_permission:
323 case XEN_DOMCTL_iomem_permission:
324 case XEN_DOMCTL_ioport_permission:
325 case XEN_DOMCTL_hypercall_init:
326 case XEN_DOMCTL_arch_setup:
327 case XEN_DOMCTL_settimeoffset:
328 case XEN_DOMCTL_sendtrigger:
329 case XEN_DOMCTL_set_opt_feature:
330 case XEN_DOMCTL_assign_device:
331 case XEN_DOMCTL_subscribe:
332 break;
333 case XEN_DOMCTL_pin_mem_cacheattr:
334 return -ENOSYS;
335 default:
336 printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd);
337 return -ENOSYS;
338 }
340 if (ret) {
341 /* error mapping the nested pointer */
342 return ret;
343 }
345 ret = xencomm_arch_hypercall_domctl (op_desc);
347 /* FIXME: should we restore the handle? */
348 if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t)))
349 ret = -EFAULT;
351 xencomm_free(desc);
352 return ret;
353 }
355 static int
356 xencomm_privcmd_xsm_op(privcmd_hypercall_t *hypercall)
357 {
358 void __user *arg = (void __user *)hypercall->arg[0];
359 xen_acmctl_t kern_arg;
360 struct xencomm_handle *op_desc;
361 struct xencomm_handle *desc = NULL;
362 int ret;
364 if (copy_from_user(&kern_arg, arg, sizeof(kern_arg)))
365 return -EFAULT;
366 if (kern_arg.interface_version != ACM_INTERFACE_VERSION)
367 return -ENOSYS;
369 switch (kern_arg.cmd) {
370 case ACMOP_getssid: {
371 op_desc = xencomm_map_no_alloc(&kern_arg, sizeof(kern_arg));
373 desc = xencomm_map(
374 xen_guest_handle(kern_arg.u.getssid.ssidbuf),
375 kern_arg.u.getssid.ssidbuf_size);
376 if (xen_guest_handle(kern_arg.u.getssid.ssidbuf) != NULL &&
377 kern_arg.u.getssid.ssidbuf_size > 0 && desc == NULL)
378 return -ENOMEM;
380 set_xen_guest_handle(kern_arg.u.getssid.ssidbuf, (void *)desc);
382 ret = xencomm_arch_hypercall_xsm_op(op_desc);
384 xencomm_free(desc);
386 if (copy_to_user(arg, &kern_arg, sizeof(kern_arg)))
387 return -EFAULT;
388 return ret;
389 }
390 default:
391 printk("%s: unknown acm_op cmd %d\n", __func__, kern_arg.cmd);
392 return -ENOSYS;
393 }
395 return ret;
396 }
398 static int
399 xencomm_privcmd_memory_reservation_op(privcmd_hypercall_t *hypercall)
400 {
401 const unsigned long cmd = hypercall->arg[0];
402 int ret = 0;
403 xen_memory_reservation_t kern_op;
404 xen_memory_reservation_t __user *user_op;
405 struct xencomm_handle *desc = NULL;
406 struct xencomm_handle *desc_op;
408 user_op = (xen_memory_reservation_t __user *)hypercall->arg[1];
409 if (copy_from_user(&kern_op, user_op,
410 sizeof(xen_memory_reservation_t)))
411 return -EFAULT;
412 desc_op = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
414 if (!xen_guest_handle(kern_op.extent_start)) {
415 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
416 if (ret < 0)
417 return ret;
418 } else {
419 xen_ulong_t nr_done = 0;
420 xen_ulong_t nr_extents = kern_op.nr_extents;
421 void *addr = xen_guest_handle(kern_op.extent_start);
423 /*
424 * Work around.
425 * Xencomm has single page size limit caused
426 * by xencomm_alloc()/xencomm_free() so that
427 * we have to repeat the hypercall.
428 * This limitation can be removed.
429 */
430 #define MEMORYOP_XENCOMM_LIMIT \
431 (((((PAGE_SIZE - sizeof(struct xencomm_desc)) / \
432 sizeof(uint64_t)) - 2) * PAGE_SIZE) / \
433 sizeof(*xen_guest_handle(kern_op.extent_start)))
435 /*
436 * Work around.
437 * Even if the above limitation is removed,
438 * the hypercall with large number of extents
439 * may cause the soft lockup warning.
440 * In order to avoid the warning, we limit
441 * the number of extents and repeat the hypercall.
442 * The following value is determined by evaluation.
443 * Time of one hypercall should be smaller than
444 * a vcpu time slice. The time with current
445 * MEMORYOP_MAX_EXTENTS is around 5 msec.
446 * If the following limit causes some issues,
447 * we should decrease this value.
448 *
449 * Another way would be that start with small value and
450 * increase adoptively measuring hypercall time.
451 * It might be over-kill.
452 */
453 #define MEMORYOP_MAX_EXTENTS (MEMORYOP_XENCOMM_LIMIT / 512)
455 while (nr_extents > 0) {
456 xen_ulong_t nr_tmp = nr_extents;
457 if (nr_tmp > MEMORYOP_MAX_EXTENTS)
458 nr_tmp = MEMORYOP_MAX_EXTENTS;
460 kern_op.nr_extents = nr_tmp;
461 desc = xencomm_map
462 (addr + nr_done * sizeof(*xen_guest_handle(kern_op.extent_start)),
463 nr_tmp * sizeof(*xen_guest_handle(kern_op.extent_start)));
464 if (addr != NULL && nr_tmp > 0 && desc == NULL)
465 return nr_done > 0 ? nr_done : -ENOMEM;
467 set_xen_guest_handle(kern_op.extent_start,
468 (void *)desc);
470 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
471 xencomm_free(desc);
472 if (ret < 0)
473 return nr_done > 0 ? nr_done : ret;
475 nr_done += ret;
476 nr_extents -= ret;
477 if (ret < nr_tmp)
478 break;
480 /*
481 * prevent softlock up message.
482 * give cpu to soft lockup kernel thread.
483 */
484 if (nr_extents > 0)
485 schedule();
486 }
487 ret = nr_done;
488 set_xen_guest_handle(kern_op.extent_start, addr);
489 }
491 if (copy_to_user(user_op, &kern_op, sizeof(xen_memory_reservation_t)))
492 return -EFAULT;
494 return ret;
495 }
497 static int
498 xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall)
499 {
500 const unsigned long cmd = hypercall->arg[0];
501 int ret = 0;
503 switch (cmd) {
504 case XENMEM_increase_reservation:
505 case XENMEM_decrease_reservation:
506 case XENMEM_populate_physmap:
507 return xencomm_privcmd_memory_reservation_op(hypercall);
508 case XENMEM_maximum_gpfn:
509 {
510 domid_t kern_domid;
511 domid_t __user *user_domid;
512 struct xencomm_handle *desc;
514 user_domid = (domid_t __user *)hypercall->arg[1];
515 if (copy_from_user(&kern_domid, user_domid, sizeof(domid_t)))
516 return -EFAULT;
517 desc = xencomm_map_no_alloc(&kern_domid, sizeof(kern_domid));
519 ret = xencomm_arch_hypercall_memory_op(cmd, desc);
521 return ret;
522 }
523 case XENMEM_translate_gpfn_list:
524 {
525 xen_translate_gpfn_list_t kern_op;
526 xen_translate_gpfn_list_t __user *user_op;
527 struct xencomm_handle *desc_gpfn = NULL;
528 struct xencomm_handle *desc_mfn = NULL;
529 struct xencomm_handle *desc_op;
530 void *addr;
532 user_op = (xen_translate_gpfn_list_t __user *)
533 hypercall->arg[1];
534 if (copy_from_user(&kern_op, user_op,
535 sizeof(xen_translate_gpfn_list_t)))
536 return -EFAULT;
537 desc_op = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
539 if (kern_op.nr_gpfns) {
540 /* gpfn_list. */
541 addr = xen_guest_handle(kern_op.gpfn_list);
543 desc_gpfn = xencomm_map(addr, kern_op.nr_gpfns *
544 sizeof(*xen_guest_handle
545 (kern_op.gpfn_list)));
546 if (addr != NULL && kern_op.nr_gpfns > 0 &&
547 desc_gpfn == NULL)
548 return -ENOMEM;
549 set_xen_guest_handle(kern_op.gpfn_list,
550 (void *)desc_gpfn);
552 /* mfn_list. */
553 addr = xen_guest_handle(kern_op.mfn_list);
555 desc_mfn = xencomm_map(addr, kern_op.nr_gpfns *
556 sizeof(*xen_guest_handle
557 (kern_op.mfn_list)));
558 if (addr != NULL && kern_op.nr_gpfns > 0 &&
559 desc_mfn == NULL) {
560 xencomm_free(desc_gpfn);
561 return -ENOMEM;
562 }
564 set_xen_guest_handle(kern_op.mfn_list,
565 (void *)desc_mfn);
566 }
568 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
570 xencomm_free(desc_gpfn);
571 xencomm_free(desc_mfn);
573 if (ret != 0)
574 return ret;
576 return ret;
577 }
578 case XENMEM_add_to_physmap:
579 case XENMEM_remove_from_physmap:
580 {
581 void __user *arg = (void __user *)hypercall->arg[1];
582 size_t argsize;
583 struct xencomm_handle *desc;
585 switch (cmd) {
586 case XENMEM_add_to_physmap:
587 argsize = sizeof(struct xen_add_to_physmap);
588 break;
589 case XENMEM_remove_from_physmap:
590 argsize = sizeof(struct xen_remove_from_physmap);
591 break;
592 default:
593 BUG();
594 }
596 desc = xencomm_map(arg, argsize);
597 if (desc == NULL)
598 return -ENOMEM;
600 ret = xencomm_arch_hypercall_memory_op(cmd, desc);
602 xencomm_free(desc);
603 return ret;
604 }
605 default:
606 printk("%s: unknown memory op %lu\n", __func__, cmd);
607 ret = -ENOSYS;
608 }
609 return ret;
610 }
612 static int
613 xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall)
614 {
615 int cmd = hypercall->arg[0];
616 void __user *arg = (void __user *)hypercall->arg[1];
617 struct xencomm_handle *desc;
618 size_t argsize;
619 int rc;
621 switch (cmd) {
622 case XENVER_version:
623 /* do not actually pass an argument */
624 return xencomm_arch_hypercall_xen_version(cmd, 0);
625 case XENVER_extraversion:
626 argsize = sizeof(xen_extraversion_t);
627 break;
628 case XENVER_compile_info:
629 argsize = sizeof(xen_compile_info_t);
630 break;
631 case XENVER_capabilities:
632 argsize = sizeof(xen_capabilities_info_t);
633 break;
634 case XENVER_changeset:
635 argsize = sizeof(xen_changeset_info_t);
636 break;
637 case XENVER_platform_parameters:
638 argsize = sizeof(xen_platform_parameters_t);
639 break;
640 case XENVER_pagesize:
641 argsize = (arg == NULL) ? 0 : sizeof(void *);
642 break;
643 case XENVER_get_features:
644 argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
645 break;
647 default:
648 printk("%s: unknown version op %d\n", __func__, cmd);
649 return -ENOSYS;
650 }
652 desc = xencomm_map(arg, argsize);
653 if (arg != NULL && argsize > 0 && desc == NULL)
654 return -ENOMEM;
656 rc = xencomm_arch_hypercall_xen_version(cmd, desc);
658 xencomm_free(desc);
660 return rc;
661 }
663 static int
664 xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall)
665 {
666 int cmd = hypercall->arg[0];
667 struct xencomm_handle *desc;
668 unsigned int argsize;
669 int ret;
671 switch (cmd) {
672 case EVTCHNOP_alloc_unbound:
673 argsize = sizeof(evtchn_alloc_unbound_t);
674 break;
676 case EVTCHNOP_status:
677 argsize = sizeof(evtchn_status_t);
678 break;
680 default:
681 printk("%s: unknown EVTCHNOP %d\n", __func__, cmd);
682 return -EINVAL;
683 }
685 desc = xencomm_map((void *)hypercall->arg[1], argsize);
686 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
687 return -ENOMEM;
689 ret = xencomm_arch_hypercall_event_channel_op(cmd, desc);
691 xencomm_free(desc);
692 return ret;
693 }
695 static int
696 xencomm_privcmd_hvm_op_track_dirty_vram(privcmd_hypercall_t *hypercall)
697 {
698 #if 1
699 /*
700 * At this moment HVMOP_track_dirty_vram isn't implemented
701 * on xen/ia64 so that it just returns -ENOSYS.
702 * Don't issue hypercall to get -ENOSYS.
703 * When the hypercall is implemented, enable the following codes.
704 */
705 return -ENOSYS;
706 #else
707 int cmd = hypercall->arg[0];
708 struct xen_hvm_track_dirty_vram *user_op = (void*)hypercall->arg[1];
709 struct xen_hvm_track_dirty_vram kern_op;
710 struct xencomm_handle *desc;
711 struct xencomm_handle *bitmap_desc;
712 int ret;
714 BUG_ON(cmd != HVMOP_track_dirty_vram);
715 if (copy_from_user(&kern_op, user_op, sizeof(kern_op)))
716 return -EFAULT;
717 desc = xencomm_map_no_alloc(&kern_op, sizeof(kern_op));
718 bitmap_desc = xencomm_map(xen_guest_handle(kern_op.dirty_bitmap),
719 kern_op.nr * sizeof(uint8_t));
720 if (bitmap_desc == NULL)
721 return -ENOMEM;
722 set_xen_guest_handle(kern_op.dirty_bitmap, (void*)bitmap_desc);
723 ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
724 xencomm_free(bitmap_desc);
726 return ret;
727 #endif
728 }
730 static int
731 xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall)
732 {
733 int cmd = hypercall->arg[0];
734 struct xencomm_handle *desc;
735 unsigned int argsize;
736 int ret;
738 switch (cmd) {
739 case HVMOP_get_param:
740 case HVMOP_set_param:
741 argsize = sizeof(xen_hvm_param_t);
742 break;
743 case HVMOP_set_pci_intx_level:
744 argsize = sizeof(xen_hvm_set_pci_intx_level_t);
745 break;
746 case HVMOP_set_isa_irq_level:
747 argsize = sizeof(xen_hvm_set_isa_irq_level_t);
748 break;
749 case HVMOP_set_pci_link_route:
750 argsize = sizeof(xen_hvm_set_pci_link_route_t);
751 break;
752 case HVMOP_set_mem_type:
753 argsize = sizeof(xen_hvm_set_mem_type_t);
754 break;
756 case HVMOP_track_dirty_vram:
757 return xencomm_privcmd_hvm_op_track_dirty_vram(hypercall);
759 default:
760 printk("%s: unknown HVMOP %d\n", __func__, cmd);
761 return -EINVAL;
762 }
764 desc = xencomm_map((void *)hypercall->arg[1], argsize);
765 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
766 return -ENOMEM;
768 ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
770 xencomm_free(desc);
771 return ret;
772 }
774 static int
775 xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall)
776 {
777 int cmd = hypercall->arg[0];
778 struct xencomm_handle *desc;
779 unsigned int argsize;
780 int ret;
782 switch (cmd) {
783 case SCHEDOP_remote_shutdown:
784 argsize = sizeof(sched_remote_shutdown_t);
785 break;
786 default:
787 printk("%s: unknown SCHEDOP %d\n", __func__, cmd);
788 return -EINVAL;
789 }
791 desc = xencomm_map((void *)hypercall->arg[1], argsize);
792 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
793 return -ENOMEM;
795 ret = xencomm_arch_hypercall_sched_op(cmd, desc);
797 xencomm_free(desc);
798 return ret;
799 }
801 static int
802 xencomm_privcmd_ia64_dom0vp_op(privcmd_hypercall_t *hypercall)
803 {
804 int cmd = hypercall->arg[0];
805 int ret;
807 switch (cmd) {
808 case IA64_DOM0VP_fpswa_revision: {
809 unsigned int revision;
810 unsigned int __user *revision_user =
811 (unsigned int* __user)hypercall->arg[1];
812 struct xencomm_handle *desc;
813 desc = xencomm_map(&revision, sizeof(revision));
814 if (desc == NULL)
815 return -ENOMEM;
817 ret = xencomm_arch_hypercall_fpswa_revision(desc);
818 xencomm_free(desc);
819 if (ret)
820 break;
821 if (copy_to_user(revision_user, &revision, sizeof(revision)))
822 ret = -EFAULT;
823 break;
824 }
825 #ifdef CONFIG_XEN_IA64_EXPOSE_P2M
826 case IA64_DOM0VP_expose_foreign_p2m:
827 ret = xen_foreign_p2m_expose(hypercall);
828 break;
829 #endif
830 default:
831 printk("%s: unknown IA64 DOM0VP op %d\n", __func__, cmd);
832 ret = -EINVAL;
833 break;
834 }
835 return ret;
836 }
838 static int
839 xencomm_privcmd_ia64_debug_op(privcmd_hypercall_t *hypercall)
840 {
841 int cmd = hypercall->arg[0];
842 unsigned long domain = hypercall->arg[1];
843 struct xencomm_handle *desc;
844 int ret;
846 switch (cmd) {
847 case XEN_IA64_DEBUG_OP_SET_FLAGS:
848 case XEN_IA64_DEBUG_OP_GET_FLAGS:
849 break;
850 default:
851 printk("%s: unknown IA64 DEBUGOP %d\n", __func__, cmd);
852 return -EINVAL;
853 }
855 desc = xencomm_map((void *)hypercall->arg[2],
856 sizeof(xen_ia64_debug_op_t));
857 if (desc == NULL)
858 return -ENOMEM;
860 ret = xencomm_arch_hypercall_ia64_debug_op(cmd, domain, desc);
862 xencomm_free(desc);
863 return ret;
864 }
866 static int
867 xencomm_privcmd_ia64_physdev_op(privcmd_hypercall_t *hypercall)
868 {
869 int cmd = hypercall->arg[0];
870 struct xencomm_handle *desc;
871 unsigned int argsize;
872 int ret;
874 switch (cmd) {
875 case PHYSDEVOP_map_pirq:
876 argsize = sizeof(physdev_map_pirq_t);
877 break;
878 case PHYSDEVOP_unmap_pirq:
879 argsize = sizeof(physdev_unmap_pirq_t);
880 break;
881 default:
882 printk("%s: unknown PHYSDEVOP %d\n", __func__, cmd);
883 return -EINVAL;
884 }
886 desc = xencomm_map((void *)hypercall->arg[1], argsize);
887 if ((void *)hypercall->arg[1] != NULL && argsize > 0 && desc == NULL)
888 return -ENOMEM;
890 ret = xencomm_arch_hypercall_physdev_op(cmd, desc);
892 xencomm_free(desc);
893 return ret;
894 }
896 int
897 privcmd_hypercall(privcmd_hypercall_t *hypercall)
898 {
899 switch (hypercall->op) {
900 case __HYPERVISOR_platform_op:
901 return xencomm_privcmd_platform_op(hypercall);
902 case __HYPERVISOR_domctl:
903 return xencomm_privcmd_domctl(hypercall);
904 case __HYPERVISOR_sysctl:
905 return xencomm_privcmd_sysctl(hypercall);
906 case __HYPERVISOR_xsm_op:
907 return xencomm_privcmd_xsm_op(hypercall);
908 case __HYPERVISOR_xen_version:
909 return xencomm_privcmd_xen_version(hypercall);
910 case __HYPERVISOR_memory_op:
911 return xencomm_privcmd_memory_op(hypercall);
912 case __HYPERVISOR_event_channel_op:
913 return xencomm_privcmd_event_channel_op(hypercall);
914 case __HYPERVISOR_hvm_op:
915 return xencomm_privcmd_hvm_op(hypercall);
916 case __HYPERVISOR_sched_op:
917 return xencomm_privcmd_sched_op(hypercall);
918 case __HYPERVISOR_ia64_dom0vp_op:
919 return xencomm_privcmd_ia64_dom0vp_op(hypercall);
920 case __HYPERVISOR_ia64_debug_op:
921 return xencomm_privcmd_ia64_debug_op(hypercall);
922 case __HYPERVISOR_physdev_op:
923 return xencomm_privcmd_ia64_physdev_op(hypercall);
924 default:
925 printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op);
926 return -ENOSYS;
927 }
928 }