ia64/linux-2.6.18-xen.hg

view arch/ia64/xen/xcom_privcmd.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 9ab1c319531f
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 }