ia64/linux-2.6.18-xen.hg

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