ia64/xen-unstable

view linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c @ 11724:4786a0b3d6c5

[IA64] remove getmeminfo.nr_pages trick from xencomm

getmeminfo nr_page trick is not anymore necessary.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Wed Oct 04 22:12:01 2006 -0600 (2006-10-04)
parents 49bf2381e009
children fd1d742487f8
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/dom0_ops.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/acm_ops.h>
33 #include <xen/interface/hvm/params.h>
34 #include <xen/public/privcmd.h>
35 #include <asm/hypercall.h>
36 #include <asm/page.h>
37 #include <asm/uaccess.h>
38 #include <asm/xen/xencomm.h>
40 #define ROUND_DIV(v,s) (((v) + (s) - 1) / (s))
42 static int
43 xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall)
44 {
45 dom0_op_t kern_op;
46 dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0];
47 struct xencomm_handle *op_desc;
48 struct xencomm_handle *desc = NULL;
49 int ret = 0;
51 if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t)))
52 return -EFAULT;
54 if (kern_op.interface_version != DOM0_INTERFACE_VERSION)
55 return -EACCES;
57 op_desc = xencomm_create_inline(&kern_op);
59 switch (kern_op.cmd) {
60 default:
61 printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd);
62 return -ENOSYS;
63 }
65 if (ret) {
66 /* error mapping the nested pointer */
67 return ret;
68 }
70 ret = xencomm_arch_hypercall_dom0_op(op_desc);
72 /* FIXME: should we restore the handle? */
73 if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t)))
74 ret = -EFAULT;
76 if (desc)
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_create_inline(&kern_op);
101 switch (kern_op.cmd) {
102 case XEN_SYSCTL_readconsole:
103 ret = xencomm_create(
104 xen_guest_handle(kern_op.u.readconsole.buffer),
105 kern_op.u.readconsole.count,
106 &desc, GFP_KERNEL);
107 set_xen_guest_handle(kern_op.u.readconsole.buffer,
108 (void *)desc);
109 break;
110 case XEN_SYSCTL_tbuf_op:
111 case XEN_SYSCTL_physinfo:
112 case XEN_SYSCTL_sched_id:
113 break;
114 case XEN_SYSCTL_perfc_op:
115 ret = xencomm_create(
116 xen_guest_handle(kern_op.u.perfc_op.desc),
117 kern_op.u.perfc_op.nr_counters *
118 sizeof(xen_sysctl_perfc_desc_t),
119 &desc, GFP_KERNEL);
120 if (ret)
121 return ret;
122 set_xen_guest_handle(kern_op.u.perfc_op.val,
123 (void *)desc);
124 ret = xencomm_create(
125 xen_guest_handle(kern_op.u.perfc_op.val),
126 kern_op.u.perfc_op.nr_vals *
127 sizeof(xen_sysctl_perfc_desc_t),
128 &desc1, GFP_KERNEL);
129 if (ret)
130 xencomm_free(desc);
131 set_xen_guest_handle(kern_op.u.perfc_op.val,
132 (void *)desc1);
133 break;
134 case XEN_SYSCTL_getdomaininfolist:
135 ret = xencomm_create(
136 xen_guest_handle(kern_op.u.getdomaininfolist.buffer),
137 kern_op.u.getdomaininfolist.max_domains *
138 sizeof(xen_domctl_getdomaininfo_t),
139 &desc, GFP_KERNEL);
140 set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer,
141 (void *)desc);
142 break;
143 default:
144 printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd);
145 return -ENOSYS;
146 }
148 if (ret) {
149 /* error mapping the nested pointer */
150 return ret;
151 }
153 ret = xencomm_arch_hypercall_sysctl(op_desc);
155 /* FIXME: should we restore the handle? */
156 if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t)))
157 ret = -EFAULT;
159 if (desc)
160 xencomm_free(desc);
161 if (desc1)
162 xencomm_free(desc1);
163 return ret;
164 }
166 static int
167 xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall)
168 {
169 xen_domctl_t kern_op;
170 xen_domctl_t __user *user_op;
171 struct xencomm_handle *op_desc;
172 struct xencomm_handle *desc = NULL;
173 int ret = 0;
175 user_op = (xen_domctl_t __user *)hypercall->arg[0];
177 if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t)))
178 return -EFAULT;
180 if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION)
181 return -EACCES;
183 op_desc = xencomm_create_inline(&kern_op);
185 switch (kern_op.cmd) {
186 case XEN_DOMCTL_createdomain:
187 case XEN_DOMCTL_destroydomain:
188 case XEN_DOMCTL_pausedomain:
189 case XEN_DOMCTL_unpausedomain:
190 case XEN_DOMCTL_getdomaininfo:
191 break;
192 case XEN_DOMCTL_getmemlist:
193 {
194 unsigned long nr_pages = kern_op.u.getmemlist.max_pfns;
196 ret = xencomm_create(
197 xen_guest_handle(kern_op.u.getmemlist.buffer),
198 nr_pages * sizeof(unsigned long),
199 &desc, GFP_KERNEL);
200 set_xen_guest_handle(kern_op.u.getmemlist.buffer,
201 (void *)desc);
202 break;
203 }
204 case XEN_DOMCTL_getpageframeinfo:
205 break;
206 case XEN_DOMCTL_getpageframeinfo2:
207 ret = xencomm_create(
208 xen_guest_handle(kern_op.u.getpageframeinfo2.array),
209 kern_op.u.getpageframeinfo2.num,
210 &desc, GFP_KERNEL);
211 set_xen_guest_handle(kern_op.u.getpageframeinfo2.array,
212 (void *)desc);
213 break;
214 case XEN_DOMCTL_shadow_op:
215 ret = xencomm_create(
216 xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap),
217 ROUND_DIV(kern_op.u.shadow_op.pages, 8),
218 &desc, GFP_KERNEL);
219 set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap,
220 (void *)desc);
221 break;
222 case XEN_DOMCTL_max_mem:
223 break;
224 case XEN_DOMCTL_setvcpucontext:
225 case XEN_DOMCTL_getvcpucontext:
226 ret = xencomm_create(
227 xen_guest_handle(kern_op.u.vcpucontext.ctxt),
228 sizeof(vcpu_guest_context_t),
229 &desc, GFP_KERNEL);
230 set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc);
231 break;
232 case XEN_DOMCTL_getvcpuinfo:
233 break;
234 case XEN_DOMCTL_setvcpuaffinity:
235 case XEN_DOMCTL_getvcpuaffinity:
236 ret = xencomm_create(
237 xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap),
238 ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8),
239 &desc, GFP_KERNEL);
240 set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap,
241 (void *)desc);
242 break;
243 case XEN_DOMCTL_max_vcpus:
244 case XEN_DOMCTL_scheduler_op:
245 case XEN_DOMCTL_setdomainhandle:
246 case XEN_DOMCTL_setdebugging:
247 case XEN_DOMCTL_irq_permission:
248 case XEN_DOMCTL_iomem_permission:
249 case XEN_DOMCTL_ioport_permission:
250 case XEN_DOMCTL_hypercall_init:
251 case XEN_DOMCTL_arch_setup:
252 case XEN_DOMCTL_settimeoffset:
253 break;
254 default:
255 printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd);
256 return -ENOSYS;
257 }
259 if (ret) {
260 /* error mapping the nested pointer */
261 return ret;
262 }
264 ret = xencomm_arch_hypercall_domctl (op_desc);
266 /* FIXME: should we restore the handle? */
267 if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t)))
268 ret = -EFAULT;
270 if (desc)
271 xencomm_free(desc);
272 return ret;
273 }
275 static int
276 xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall)
277 {
278 int cmd = hypercall->arg[0];
279 void __user *arg = (void __user *)hypercall->arg[1];
280 struct xencomm_handle *op_desc;
281 struct xencomm_handle *desc = NULL;
282 int ret;
284 switch (cmd) {
285 case ACMOP_getssid:
286 {
287 struct acm_getssid kern_arg;
289 if (copy_from_user(&kern_arg, arg, sizeof (kern_arg)))
290 return -EFAULT;
292 op_desc = xencomm_create_inline(&kern_arg);
294 ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf),
295 kern_arg.ssidbuf_size, &desc, GFP_KERNEL);
296 if (ret)
297 return ret;
299 set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc);
301 ret = xencomm_arch_hypercall_acm_op(cmd, op_desc);
303 xencomm_free(desc);
305 if (copy_to_user(arg, &kern_arg, sizeof (kern_arg)))
306 return -EFAULT;
308 return ret;
309 }
310 default:
311 printk("%s: unknown acm_op cmd %d\n", __func__, cmd);
312 return -ENOSYS;
313 }
315 return ret;
316 }
318 static int
319 xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall)
320 {
321 const unsigned long cmd = hypercall->arg[0];
322 int ret = 0;
324 switch (cmd) {
325 case XENMEM_increase_reservation:
326 case XENMEM_decrease_reservation:
327 case XENMEM_populate_physmap:
328 {
329 xen_memory_reservation_t kern_op;
330 xen_memory_reservation_t __user *user_op;
331 struct xencomm_handle *desc = NULL;
332 struct xencomm_handle *desc_op;
334 user_op = (xen_memory_reservation_t __user *)hypercall->arg[1];
335 if (copy_from_user(&kern_op, user_op,
336 sizeof(xen_memory_reservation_t)))
337 return -EFAULT;
338 desc_op = xencomm_create_inline(&kern_op);
340 if (xen_guest_handle(kern_op.extent_start)) {
341 void * addr;
343 addr = xen_guest_handle(kern_op.extent_start);
344 ret = xencomm_create
345 (addr,
346 kern_op.nr_extents *
347 sizeof(*xen_guest_handle
348 (kern_op.extent_start)),
349 &desc, GFP_KERNEL);
350 if (ret)
351 return ret;
352 set_xen_guest_handle(kern_op.extent_start,
353 (void *)desc);
354 }
356 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
358 if (desc)
359 xencomm_free(desc);
361 if (ret != 0)
362 return ret;
364 if (copy_to_user(user_op, &kern_op,
365 sizeof(xen_memory_reservation_t)))
366 return -EFAULT;
368 return ret;
369 }
370 case XENMEM_translate_gpfn_list:
371 {
372 xen_translate_gpfn_list_t kern_op;
373 xen_translate_gpfn_list_t __user *user_op;
374 struct xencomm_handle *desc_gpfn = NULL;
375 struct xencomm_handle *desc_mfn = NULL;
376 struct xencomm_handle *desc_op;
377 void *addr;
379 user_op = (xen_translate_gpfn_list_t __user *)
380 hypercall->arg[1];
381 if (copy_from_user(&kern_op, user_op,
382 sizeof(xen_translate_gpfn_list_t)))
383 return -EFAULT;
384 desc_op = xencomm_create_inline(&kern_op);
386 if (kern_op.nr_gpfns) {
387 /* gpfn_list. */
388 addr = xen_guest_handle(kern_op.gpfn_list);
390 ret = xencomm_create(addr, kern_op.nr_gpfns *
391 sizeof(*xen_guest_handle
392 (kern_op.gpfn_list)),
393 &desc_gpfn, GFP_KERNEL);
394 if (ret)
395 return ret;
396 set_xen_guest_handle(kern_op.gpfn_list,
397 (void *)desc_gpfn);
399 /* mfn_list. */
400 addr = xen_guest_handle(kern_op.mfn_list);
402 ret = xencomm_create(addr, kern_op.nr_gpfns *
403 sizeof(*xen_guest_handle
404 (kern_op.mfn_list)),
405 &desc_mfn, GFP_KERNEL);
406 if (ret)
407 return ret;
408 set_xen_guest_handle(kern_op.mfn_list,
409 (void *)desc_mfn);
410 }
412 ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
414 if (desc_gpfn)
415 xencomm_free(desc_gpfn);
417 if (desc_mfn)
418 xencomm_free(desc_mfn);
420 if (ret != 0)
421 return ret;
423 return ret;
424 }
425 default:
426 printk("%s: unknown memory op %lu\n", __func__, cmd);
427 ret = -ENOSYS;
428 }
429 return ret;
430 }
432 static int
433 xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall)
434 {
435 int cmd = hypercall->arg[0];
436 void __user *arg = (void __user *)hypercall->arg[1];
437 struct xencomm_handle *desc;
438 size_t argsize;
439 int rc;
441 switch (cmd) {
442 case XENVER_version:
443 /* do not actually pass an argument */
444 return xencomm_arch_hypercall_xen_version(cmd, 0);
445 case XENVER_extraversion:
446 argsize = sizeof(xen_extraversion_t);
447 break;
448 case XENVER_compile_info:
449 argsize = sizeof(xen_compile_info_t);
450 break;
451 case XENVER_capabilities:
452 argsize = sizeof(xen_capabilities_info_t);
453 break;
454 case XENVER_changeset:
455 argsize = sizeof(xen_changeset_info_t);
456 break;
457 case XENVER_platform_parameters:
458 argsize = sizeof(xen_platform_parameters_t);
459 break;
460 case XENVER_pagesize:
461 argsize = (arg == NULL) ? 0 : sizeof(void *);
462 break;
463 case XENVER_get_features:
464 argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
465 break;
467 default:
468 printk("%s: unknown version op %d\n", __func__, cmd);
469 return -ENOSYS;
470 }
472 rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL);
473 if (rc)
474 return rc;
476 rc = xencomm_arch_hypercall_xen_version(cmd, desc);
478 xencomm_free(desc);
480 return rc;
481 }
483 static int
484 xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall)
485 {
486 int cmd = hypercall->arg[0];
487 struct xencomm_handle *desc;
488 unsigned int argsize;
489 int ret;
491 switch (cmd) {
492 case EVTCHNOP_alloc_unbound:
493 argsize = sizeof(evtchn_alloc_unbound_t);
494 break;
496 case EVTCHNOP_status:
497 argsize = sizeof(evtchn_status_t);
498 break;
500 default:
501 printk("%s: unknown EVTCHNOP %d\n", __func__, cmd);
502 return -EINVAL;
503 }
505 ret = xencomm_create((void *)hypercall->arg[1], argsize,
506 &desc, GFP_KERNEL);
507 if (ret)
508 return ret;
510 ret = xencomm_arch_hypercall_event_channel_op(cmd, desc);
512 xencomm_free(desc);
513 return ret;
514 }
516 static int
517 xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall)
518 {
519 int cmd = hypercall->arg[0];
520 struct xencomm_handle *desc;
521 unsigned int argsize;
522 int ret;
524 switch (cmd) {
525 case HVMOP_get_param:
526 case HVMOP_set_param:
527 argsize = sizeof(xen_hvm_param_t);
528 break;
529 default:
530 printk("%s: unknown HVMOP %d\n", __func__, cmd);
531 return -EINVAL;
532 }
534 ret = xencomm_create((void *)hypercall->arg[1], argsize,
535 &desc, GFP_KERNEL);
536 if (ret)
537 return ret;
539 ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
541 xencomm_free(desc);
542 return ret;
543 }
545 static int
546 xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall)
547 {
548 int cmd = hypercall->arg[0];
549 struct xencomm_handle *desc;
550 unsigned int argsize;
551 int ret;
553 switch (cmd) {
554 case SCHEDOP_remote_shutdown:
555 argsize = sizeof(sched_remote_shutdown_t);
556 break;
557 default:
558 printk("%s: unknown SCHEDOP %d\n", __func__, cmd);
559 return -EINVAL;
560 }
562 ret = xencomm_create((void *)hypercall->arg[1], argsize,
563 &desc, GFP_KERNEL);
564 if (ret)
565 return ret;
567 ret = xencomm_arch_hypercall_sched_op(cmd, desc);
569 xencomm_free(desc);
570 return ret;
571 }
573 int
574 privcmd_hypercall(privcmd_hypercall_t *hypercall)
575 {
576 switch (hypercall->op) {
577 case __HYPERVISOR_dom0_op:
578 return xencomm_privcmd_dom0_op(hypercall);
579 case __HYPERVISOR_domctl:
580 return xencomm_privcmd_domctl(hypercall);
581 case __HYPERVISOR_sysctl:
582 return xencomm_privcmd_sysctl(hypercall);
583 case __HYPERVISOR_acm_op:
584 return xencomm_privcmd_acm_op(hypercall);
585 case __HYPERVISOR_xen_version:
586 return xencomm_privcmd_xen_version(hypercall);
587 case __HYPERVISOR_memory_op:
588 return xencomm_privcmd_memory_op(hypercall);
589 case __HYPERVISOR_event_channel_op:
590 return xencomm_privcmd_event_channel_op(hypercall);
591 case __HYPERVISOR_hvm_op:
592 return xencomm_privcmd_hvm_op(hypercall);
593 case __HYPERVISOR_sched_op:
594 return xencomm_privcmd_sched_op(hypercall);
595 default:
596 printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op);
597 return -ENOSYS;
598 }
599 }