1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/file.h> 30 #include <sys/errno.h> 31 #include <sys/open.h> 32 #include <sys/cred.h> 33 #include <sys/conf.h> 34 #include <sys/stat.h> 35 #include <sys/modctl.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/vmsystm.h> 39 #include <sys/hypervisor.h> 40 #include <sys/xen_errno.h> 41 #include <sys/sysmacros.h> 42 #include <sys/sdt.h> 43 44 #include <xen/sys/privcmd.h> 45 #include <sys/privcmd_impl.h> 46 47 typedef struct import_export { 48 void * ie_uaddr; 49 void * ie_kaddr; 50 size_t ie_size; 51 uint32_t ie_flags; 52 } import_export_t; 53 54 static import_export_t null_ie = {NULL, NULL, 0, 0}; 55 56 #define IE_IMPORT 0x0001 /* Data needs to be copied in */ 57 #define IE_EXPORT 0x0002 /* Data needs to be copied out */ 58 #define IE_FREE 0x0004 59 #define IE_IMPEXP (IE_IMPORT | IE_EXPORT) 60 61 /* 62 * Import a buffer from user-space. If the caller provides a kernel 63 * address, we import to that address. If not, we kmem_alloc() the space 64 * ourselves. 65 */ 66 static int 67 import_buffer(import_export_t *iep, void *uaddr, void *kaddr, size_t size, 68 uint32_t flags) 69 { 70 iep->ie_uaddr = uaddr; 71 iep->ie_size = size; 72 iep->ie_flags = flags & IE_EXPORT; 73 74 if (size == 0 || uaddr == NULL) { 75 *iep = null_ie; 76 return (0); 77 } 78 79 if (kaddr == NULL) { 80 iep->ie_kaddr = kmem_alloc(size, KM_SLEEP); 81 iep->ie_flags |= IE_FREE; 82 } else { 83 iep->ie_kaddr = kaddr; 84 } 85 86 if ((flags & IE_IMPORT) && 87 (ddi_copyin(uaddr, iep->ie_kaddr, size, 0) != 0)) { 88 if (iep->ie_flags & IE_FREE) 89 kmem_free(iep->ie_kaddr, iep->ie_size); 90 return (-X_EFAULT); 91 } 92 93 return (0); 94 } 95 96 static void 97 export_buffer(import_export_t *iep, int *error) 98 { 99 int copy_err = 0; 100 101 if (iep->ie_size == 0 || iep->ie_uaddr == NULL) 102 return; 103 104 /* 105 * If the buffer was marked for export initially, and if the 106 * hypercall completed successfully, resync the user-space buffer 107 * with our in-kernel buffer. 108 */ 109 if ((iep->ie_flags & IE_EXPORT) && (*error >= 0) && 110 (ddi_copyout(iep->ie_kaddr, iep->ie_uaddr, iep->ie_size, 0) != 0)) 111 copy_err = -X_EFAULT; 112 if (iep->ie_flags & IE_FREE) 113 kmem_free(iep->ie_kaddr, iep->ie_size); 114 115 if (copy_err != 0 && *error >= 0) 116 *error = copy_err; 117 } 118 119 /* 120 * Xen 'op' structures often include pointers disguised as 'handles', which 121 * refer to addresses in user space. This routine copies a buffer 122 * associated with an embedded pointer into kernel space, and replaces the 123 * pointer to userspace with a pointer to the new kernel buffer. 124 * 125 * Note: if Xen ever redefines the structure of a 'handle', this routine 126 * (specifically the definition of 'hdl') will need to be updated. 127 */ 128 static int 129 import_handle(import_export_t *iep, void *field, size_t size, int flags) 130 { 131 struct { void *p; } *hdl = field; 132 void *ptr; 133 int err; 134 135 /*LINTED: constant in conditional context*/ 136 get_xen_guest_handle(ptr, (*hdl)); 137 err = import_buffer(iep, ptr, NULL, size, (flags)); 138 /*LINTED: constant in conditional context*/ 139 set_xen_guest_handle((*hdl), (void *)((iep)->ie_kaddr)); 140 return (err); 141 } 142 143 static int 144 privcmd_HYPERVISOR_mmu_update(mmu_update_t *ureq, int count, int *scount, 145 domid_t domid) 146 { 147 mmu_update_t *kreq, single_kreq; 148 import_export_t cnt_ie, req_ie; 149 int error, kscount, bytes; 150 151 bytes = count * sizeof (*kreq); 152 kreq = (count == 1) ? &single_kreq : kmem_alloc(bytes, KM_SLEEP); 153 154 error = import_buffer(&cnt_ie, scount, &kscount, sizeof (kscount), 155 IE_IMPEXP); 156 if (error != 0) 157 req_ie = null_ie; 158 else 159 error = import_buffer(&req_ie, ureq, kreq, bytes, IE_IMPEXP); 160 161 DTRACE_XPV3(mmu__update__start, int, domid, int, count, mmu_update_t *, 162 ((error == -X_EFAULT) ? ureq : kreq)); 163 164 if (error == 0) 165 error = HYPERVISOR_mmu_update(kreq, count, &kscount, domid); 166 export_buffer(&cnt_ie, &error); 167 export_buffer(&req_ie, &error); 168 if (count != 1) 169 kmem_free(kreq, bytes); 170 171 DTRACE_XPV1(mmu__update__end, int, error); 172 return (error); 173 } 174 175 static int 176 privcmd_HYPERVISOR_domctl(xen_domctl_t *opp) 177 { 178 xen_domctl_t op; 179 import_export_t op_ie, sub_ie; 180 int error = 0; 181 182 if ((error = import_buffer(&op_ie, opp, &op, sizeof (op), 183 IE_IMPEXP)) != 0) 184 return (error); 185 186 sub_ie = null_ie; 187 188 /* 189 * Check this first because our wrapper will forcibly overwrite it. 190 */ 191 if (op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) { 192 error = -X_EACCES; 193 export_buffer(&op_ie, &error); 194 return (error); 195 } 196 197 /* 198 * Now handle any domctl ops with embedded pointers elsewhere 199 * in the user address space that also need to be tacked down 200 * while the hypervisor futzes with them. 201 */ 202 switch (op.cmd) { 203 case XEN_DOMCTL_createdomain: 204 DTRACE_XPV1(dom__create__start, xen_domctl_t *, 205 &op.u.createdomain); 206 break; 207 208 case XEN_DOMCTL_destroydomain: 209 DTRACE_XPV1(dom__destroy__start, domid_t, op.domain); 210 break; 211 212 case XEN_DOMCTL_pausedomain: 213 DTRACE_XPV1(dom__pause__start, domid_t, op.domain); 214 break; 215 216 case XEN_DOMCTL_unpausedomain: 217 DTRACE_XPV1(dom__unpause__start, domid_t, op.domain); 218 break; 219 220 case XEN_DOMCTL_getdomaininfo: 221 break; 222 223 case XEN_DOMCTL_getmemlist: { 224 error = import_handle(&sub_ie, &op.u.getmemlist.buffer, 225 op.u.getmemlist.max_pfns * sizeof (xen_pfn_t), IE_EXPORT); 226 break; 227 } 228 229 case XEN_DOMCTL_getpageframeinfo: 230 break; 231 232 case XEN_DOMCTL_getpageframeinfo2: { 233 error = import_handle(&sub_ie, &op.u.getpageframeinfo2.array, 234 op.u.getpageframeinfo2.num * sizeof (ulong_t), IE_IMPEXP); 235 break; 236 } 237 238 case XEN_DOMCTL_shadow_op: { 239 size_t size; 240 241 size = roundup(howmany(op.u.shadow_op.pages, NBBY), 242 sizeof (ulong_t)); 243 error = import_handle(&sub_ie, &op.u.shadow_op.dirty_bitmap, 244 size, IE_IMPEXP); 245 break; 246 } 247 248 case XEN_DOMCTL_max_mem: 249 break; 250 251 case XEN_DOMCTL_setvcpucontext: { 252 vcpu_guest_context_t *taddr; 253 error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt, 254 sizeof (vcpu_guest_context_t), IE_IMPORT); 255 if (error == -X_EFAULT) 256 /*LINTED: constant in conditional context*/ 257 get_xen_guest_handle(taddr, op.u.vcpucontext.ctxt); 258 else 259 taddr = sub_ie.ie_kaddr; 260 DTRACE_XPV2(setvcpucontext__start, domid_t, op.domain, 261 vcpu_guest_context_t *, taddr); 262 break; 263 } 264 265 case XEN_DOMCTL_getvcpucontext: { 266 error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt, 267 sizeof (vcpu_guest_context_t), IE_EXPORT); 268 break; 269 } 270 271 case XEN_DOMCTL_getvcpuinfo: 272 case XEN_DOMCTL_setvcpuaffinity: 273 case XEN_DOMCTL_getvcpuaffinity: 274 case XEN_DOMCTL_max_vcpus: 275 case XEN_DOMCTL_scheduler_op: 276 case XEN_DOMCTL_setdomainhandle: 277 case XEN_DOMCTL_setdebugging: 278 case XEN_DOMCTL_irq_permission: 279 case XEN_DOMCTL_iomem_permission: 280 case XEN_DOMCTL_ioport_permission: 281 case XEN_DOMCTL_hypercall_init: 282 case XEN_DOMCTL_arch_setup: 283 case XEN_DOMCTL_settimeoffset: 284 case XEN_DOMCTL_real_mode_area: 285 break; 286 287 default: 288 #ifdef DEBUG 289 printf("unrecognized HYPERVISOR_domctl %d\n", op.cmd); 290 #endif 291 error = -X_EINVAL; 292 } 293 294 if (error == 0) 295 error = HYPERVISOR_domctl(&op); 296 297 export_buffer(&op_ie, &error); 298 export_buffer(&sub_ie, &error); 299 300 switch (op.cmd) { 301 case XEN_DOMCTL_createdomain: 302 DTRACE_XPV1(dom__create__end, int, error); 303 break; 304 case XEN_DOMCTL_destroydomain: 305 DTRACE_XPV1(dom__destroy__end, int, error); 306 break; 307 case XEN_DOMCTL_pausedomain: 308 DTRACE_XPV1(dom__pause__end, int, error); 309 break; 310 case XEN_DOMCTL_unpausedomain: 311 DTRACE_XPV1(dom__unpause__end, int, error); 312 break; 313 case XEN_DOMCTL_setvcpucontext: 314 DTRACE_XPV1(setvcpucontext__end, int, error); 315 break; 316 default: 317 ; 318 } 319 320 return (error); 321 } 322 323 static int 324 privcmd_HYPERVISOR_sysctl(xen_sysctl_t *opp) 325 { 326 xen_sysctl_t op; 327 import_export_t op_ie, sub_ie; 328 int error = 0; 329 330 if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0) 331 return (-X_EFAULT); 332 333 sub_ie = null_ie; 334 335 /* 336 * Check this first because our wrapper will forcibly overwrite it. 337 */ 338 if (op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) { 339 error = -X_EACCES; 340 export_buffer(&op_ie, &error); 341 return (error); 342 } 343 344 switch (op.cmd) { 345 case XEN_SYSCTL_readconsole: { 346 error = import_handle(&sub_ie, &op.u.readconsole.buffer, 347 op.u.readconsole.count, IE_EXPORT); 348 break; 349 } 350 351 case XEN_SYSCTL_tbuf_op: 352 case XEN_SYSCTL_physinfo: 353 case XEN_SYSCTL_sched_id: 354 break; 355 356 case XEN_SYSCTL_perfc_op: { 357 xen_sysctl_perfc_desc_t *scdp; 358 /* 359 * If 'desc' is NULL, then the caller is asking for 360 * the number of counters. If 'desc' is non-NULL, 361 * then we need to know how many counters there are 362 * before wiring down the output buffer appropriately. 363 */ 364 /*LINTED: constant in conditional context*/ 365 get_xen_guest_handle(scdp, op.u.perfc_op.desc); 366 if (scdp != NULL) { 367 static int numcounters = -1; 368 369 if (numcounters == -1) { 370 xen_sysctl_t dop; 371 372 dop.cmd = XEN_SYSCTL_perfc_op; 373 dop.interface_version = 374 XEN_SYSCTL_INTERFACE_VERSION; 375 dop.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_query; 376 377 error = HYPERVISOR_sysctl(&dop); 378 if (error != 0) 379 break; 380 numcounters = dop.u.perfc_op.nr_counters; 381 } 382 ASSERT(numcounters != -1); 383 error = import_handle(&sub_ie, &op.u.perfc_op.desc, 384 (sizeof (xen_sysctl_perfc_desc_t) * numcounters), 385 IE_EXPORT); 386 } 387 break; 388 } 389 390 case XEN_SYSCTL_getdomaininfolist: { 391 error = import_handle(&sub_ie, &op.u.getdomaininfolist.buffer, 392 (op.u.getdomaininfolist.max_domains * 393 sizeof (xen_domctl_getdomaininfo_t)), IE_EXPORT); 394 break; 395 } 396 397 default: 398 #ifdef DEBUG 399 printf("unrecognized HYPERVISOR_sysctl %d\n", op.cmd); 400 #endif 401 error = -X_EINVAL; 402 } 403 404 if (error == 0) 405 error = HYPERVISOR_sysctl(&op); 406 407 export_buffer(&op_ie, &error); 408 export_buffer(&sub_ie, &error); 409 410 return (error); 411 } 412 413 static int 414 privcmd_HYPERVISOR_platform_op(xen_platform_op_t *opp) 415 { 416 import_export_t op_ie, sub_ie; 417 xen_platform_op_t op; 418 int error; 419 420 if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0) 421 return (-X_EFAULT); 422 423 sub_ie = null_ie; 424 425 /* 426 * Check this first because our wrapper will forcibly overwrite it. 427 */ 428 if (op.interface_version != XENPF_INTERFACE_VERSION) { 429 error = -X_EACCES; 430 export_buffer(&op_ie, &error); 431 return (error); 432 } 433 434 /* 435 * Now handle any platform ops with embedded pointers elsewhere 436 * in the user address space that also need to be tacked down 437 * while the hypervisor futzes with them. 438 */ 439 switch (op.cmd) { 440 case XENPF_settime: 441 case XENPF_add_memtype: 442 case XENPF_del_memtype: 443 case XENPF_read_memtype: 444 case XENPF_platform_quirk: 445 break; 446 447 case XENPF_microcode_update: 448 error = import_handle(&sub_ie, &op.u.microcode.data, 449 op.u.microcode.length, IE_IMPORT); 450 break; 451 452 default: 453 #ifdef DEBUG 454 printf("unrecognized HYPERVISOR_platform_op %d\n", op.cmd); 455 #endif 456 return (-X_EINVAL); 457 } 458 459 if (error == 0) 460 error = HYPERVISOR_platform_op(&op); 461 462 export_buffer(&op_ie, &error); 463 export_buffer(&sub_ie, &error); 464 465 return (error); 466 } 467 468 static int 469 privcmd_HYPERVISOR_memory_op(int cmd, void *arg) 470 { 471 int error = 0; 472 import_export_t op_ie, sub_ie, gpfn_ie, mfn_ie; 473 union { 474 domid_t domid; 475 struct xen_memory_reservation resv; 476 struct xen_machphys_mfn_list xmml; 477 struct xen_add_to_physmap xatp; 478 struct xen_translate_gpfn_list tgl; 479 struct xen_memory_map mm; 480 struct xen_foreign_memory_map fmm; 481 } op_arg; 482 483 op_ie = sub_ie = gpfn_ie = mfn_ie = null_ie; 484 485 switch (cmd) { 486 case XENMEM_increase_reservation: 487 case XENMEM_decrease_reservation: 488 case XENMEM_populate_physmap: { 489 ulong_t *taddr; 490 491 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.resv), 492 IE_IMPEXP) != 0) 493 return (-X_EFAULT); 494 495 error = import_handle(&sub_ie, &op_arg.resv.extent_start, 496 (op_arg.resv.nr_extents * sizeof (ulong_t)), IE_IMPEXP); 497 498 if (error == -X_EFAULT) 499 /*LINTED: constant in conditional context*/ 500 get_xen_guest_handle(taddr, op_arg.resv.extent_start); 501 else 502 taddr = sub_ie.ie_kaddr; 503 504 switch (cmd) { 505 case XENMEM_increase_reservation: 506 DTRACE_XPV4(increase__reservation__start, 507 domid_t, op_arg.resv.domid, 508 ulong_t, op_arg.resv.nr_extents, 509 uint_t, op_arg.resv.extent_order, 510 ulong_t *, taddr); 511 break; 512 case XENMEM_decrease_reservation: 513 DTRACE_XPV4(decrease__reservation__start, 514 domid_t, op_arg.resv.domid, 515 ulong_t, op_arg.resv.nr_extents, 516 uint_t, op_arg.resv.extent_order, 517 ulong_t *, taddr); 518 break; 519 case XENMEM_populate_physmap: 520 DTRACE_XPV3(populate__physmap__start, 521 domid_t, op_arg.resv.domid, 522 ulong_t, op_arg.resv.nr_extents, 523 ulong_t *, taddr); 524 break; 525 } 526 527 break; 528 } 529 530 case XENMEM_maximum_ram_page: 531 break; 532 533 case XENMEM_current_reservation: 534 case XENMEM_maximum_reservation: 535 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.domid), 536 IE_IMPEXP) != 0) 537 return (-X_EFAULT); 538 break; 539 540 case XENMEM_machphys_mfn_list: { 541 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xmml), 542 IE_IMPEXP) != 0) 543 return (-X_EFAULT); 544 545 error = import_handle(&sub_ie, &op_arg.xmml.extent_start, 546 (op_arg.xmml.max_extents * sizeof (ulong_t)), IE_IMPEXP); 547 break; 548 } 549 550 case XENMEM_add_to_physmap: 551 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xatp), 552 IE_IMPEXP) != 0) 553 return (-X_EFAULT); 554 DTRACE_XPV4(add__to__physmap__start, domid_t, 555 op_arg.xatp.domid, uint_t, op_arg.xatp.space, ulong_t, 556 op_arg.xatp.idx, ulong_t, op_arg.xatp.gpfn); 557 break; 558 559 case XENMEM_translate_gpfn_list: { 560 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.tgl), 561 IE_IMPEXP) != 0) 562 return (-X_EFAULT); 563 564 error = import_handle(&gpfn_ie, &op_arg.tgl.gpfn_list, 565 (op_arg.tgl.nr_gpfns * sizeof (long)), IE_IMPORT); 566 if (error == 0) 567 error = import_handle(&mfn_ie, &op_arg.tgl.mfn_list, 568 (op_arg.tgl.nr_gpfns * sizeof (long)), IE_EXPORT); 569 break; 570 } 571 572 case XENMEM_memory_map: 573 case XENMEM_machine_memory_map: { 574 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.mm), 575 IE_EXPORT) != 0) 576 return (-X_EFAULT); 577 578 /* 579 * XXPV: ugh. e820entry is packed, but not in the kernel, since 580 * we remove all attributes; seems like this is a nice way to 581 * break mysteriously. 582 */ 583 error = import_handle(&sub_ie, &op_arg.mm.buffer, 584 (op_arg.mm.nr_entries * 20), IE_IMPEXP); 585 break; 586 } 587 588 case XENMEM_set_memory_map: { 589 struct xen_memory_map *taddr; 590 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.fmm), 591 IE_IMPORT) != 0) 592 return (-X_EFAULT); 593 594 /* 595 * As above. 596 */ 597 error = import_handle(&sub_ie, &op_arg.fmm.map.buffer, 598 (op_arg.fmm.map.nr_entries * 20), IE_IMPEXP); 599 600 if (error == -X_EFAULT) 601 /*LINTED: constant in conditional context*/ 602 get_xen_guest_handle(taddr, op_arg.fmm.map.buffer); 603 else 604 taddr = sub_ie.ie_kaddr; 605 DTRACE_XPV3(set__memory__map__start, domid_t, 606 op_arg.fmm.domid, int, op_arg.fmm.map.nr_entries, 607 struct xen_memory_map *, taddr); 608 break; 609 } 610 611 default: 612 #ifdef DEBUG 613 printf("unrecognized HYPERVISOR_memory_op %d\n", cmd); 614 #endif 615 return (-X_EINVAL); 616 } 617 618 if (error == 0) 619 error = HYPERVISOR_memory_op(cmd, 620 (arg == NULL) ? NULL: &op_arg); 621 622 export_buffer(&op_ie, &error); 623 export_buffer(&sub_ie, &error); 624 export_buffer(&gpfn_ie, &error); 625 export_buffer(&mfn_ie, &error); 626 627 switch (cmd) { 628 case XENMEM_increase_reservation: 629 DTRACE_XPV1(increase__reservation__end, int, error); 630 break; 631 case XENMEM_decrease_reservation: 632 DTRACE_XPV1(decrease__reservation__end, int, error); 633 break; 634 case XENMEM_populate_physmap: 635 DTRACE_XPV1(populate__physmap__end, int, error); 636 break; 637 case XENMEM_add_to_physmap: 638 DTRACE_XPV1(add__to__physmap__end, int, error); 639 break; 640 case XENMEM_set_memory_map: 641 DTRACE_XPV1(set__memory__map__end, int, error); 642 break; 643 } 644 return (error); 645 } 646 647 static int 648 privcmd_HYPERVISOR_event_channel_op(int cmd, void *arg) 649 { 650 int error; 651 size_t size; 652 import_export_t op_ie; 653 uint32_t flags; 654 655 switch (cmd) { 656 case EVTCHNOP_alloc_unbound: 657 size = sizeof (evtchn_alloc_unbound_t); 658 flags = IE_IMPEXP; 659 break; 660 case EVTCHNOP_bind_interdomain: 661 size = sizeof (evtchn_bind_interdomain_t); 662 flags = IE_IMPEXP; 663 break; 664 case EVTCHNOP_bind_virq: 665 size = sizeof (evtchn_bind_virq_t); 666 flags = IE_IMPEXP; 667 break; 668 case EVTCHNOP_bind_pirq: 669 size = sizeof (evtchn_bind_pirq_t); 670 flags = IE_IMPEXP; 671 break; 672 case EVTCHNOP_bind_ipi: 673 size = sizeof (evtchn_bind_ipi_t); 674 flags = IE_IMPEXP; 675 break; 676 case EVTCHNOP_close: 677 size = sizeof (evtchn_close_t); 678 flags = IE_IMPORT; 679 break; 680 case EVTCHNOP_send: 681 size = sizeof (evtchn_send_t); 682 flags = IE_IMPORT; 683 break; 684 case EVTCHNOP_status: 685 size = sizeof (evtchn_status_t); 686 flags = IE_IMPEXP; 687 break; 688 case EVTCHNOP_bind_vcpu: 689 size = sizeof (evtchn_bind_vcpu_t); 690 flags = IE_IMPORT; 691 break; 692 case EVTCHNOP_unmask: 693 size = sizeof (evtchn_unmask_t); 694 flags = IE_IMPORT; 695 break; 696 697 default: 698 #ifdef DEBUG 699 printf("unrecognized HYPERVISOR_event_channel op %d\n", cmd); 700 #endif 701 return (-X_EINVAL); 702 } 703 704 error = import_buffer(&op_ie, arg, NULL, size, flags); 705 706 /* 707 * If there is sufficient demand, we can replace this void * with 708 * the proper op structure pointer. 709 */ 710 DTRACE_XPV2(evtchn__op__start, int, cmd, void *, 711 ((error == -X_EFAULT) ? arg : op_ie.ie_kaddr)); 712 713 if (error == 0) 714 error = HYPERVISOR_event_channel_op(cmd, op_ie.ie_kaddr); 715 export_buffer(&op_ie, &error); 716 717 DTRACE_XPV1(evtchn__op__end, int, error); 718 719 return (error); 720 } 721 722 static int 723 privcmd_HYPERVISOR_xen_version(int cmd, void *arg) 724 { 725 int error; 726 int size = 0; 727 import_export_t op_ie; 728 uint32_t flags = IE_EXPORT; 729 730 switch (cmd) { 731 case XENVER_version: 732 break; 733 case XENVER_extraversion: 734 size = sizeof (xen_extraversion_t); 735 break; 736 case XENVER_compile_info: 737 size = sizeof (xen_compile_info_t); 738 break; 739 case XENVER_capabilities: 740 size = sizeof (xen_capabilities_info_t); 741 break; 742 case XENVER_changeset: 743 size = sizeof (xen_changeset_info_t); 744 break; 745 case XENVER_platform_parameters: 746 size = sizeof (xen_platform_parameters_t); 747 break; 748 case XENVER_get_features: 749 flags = IE_IMPEXP; 750 size = sizeof (xen_feature_info_t); 751 break; 752 case XENVER_pagesize: 753 break; 754 case XENVER_guest_handle: 755 size = sizeof (xen_domain_handle_t); 756 break; 757 758 default: 759 #ifdef DEBUG 760 printf("unrecognized HYPERVISOR_xen_version op %d\n", cmd); 761 #endif 762 return (-X_EINVAL); 763 } 764 765 error = import_buffer(&op_ie, arg, NULL, size, flags); 766 if (error == 0) 767 error = HYPERVISOR_xen_version(cmd, op_ie.ie_kaddr); 768 export_buffer(&op_ie, &error); 769 770 return (error); 771 } 772 773 static int 774 privcmd_HYPERVISOR_acm_op(int cmd, void *arg) 775 { 776 int error; 777 int size = 0; 778 import_export_t op_ie; 779 uint32_t flags; 780 781 switch (cmd) { 782 case ACMOP_setpolicy: 783 size = sizeof (struct acm_setpolicy); 784 flags = IE_IMPORT; 785 break; 786 case ACMOP_getpolicy: 787 size = sizeof (struct acm_getpolicy); 788 flags = IE_IMPORT; 789 break; 790 case ACMOP_dumpstats: 791 size = sizeof (struct acm_dumpstats); 792 flags = IE_IMPORT; 793 break; 794 case ACMOP_getssid: 795 size = sizeof (struct acm_getssid); 796 flags = IE_IMPORT; 797 break; 798 case ACMOP_getdecision: 799 size = sizeof (struct acm_getdecision); 800 flags = IE_IMPEXP; 801 break; 802 default: 803 #ifdef DEBUG 804 printf("unrecognized HYPERVISOR_acm_op op %d\n", cmd); 805 #endif 806 return (-X_EINVAL); 807 } 808 809 error = import_buffer(&op_ie, arg, NULL, size, flags); 810 if (error == 0) 811 error = HYPERVISOR_acm_op(cmd, op_ie.ie_kaddr); 812 export_buffer(&op_ie, &error); 813 814 return (error); 815 } 816 817 static int 818 privcmd_HYPERVISOR_mmuext_op(struct mmuext_op *op, int count, uint_t *scount, 819 domid_t domid) 820 { 821 int error, bytes; 822 uint_t kscount; 823 struct mmuext_op *kop, single_kop; 824 import_export_t op_ie, scnt_ie; 825 826 op_ie = scnt_ie = null_ie; 827 error = 0; 828 829 if (count >= 1) { 830 bytes = count * sizeof (*kop); 831 kop = (count == 1) ? &single_kop : kmem_alloc(bytes, KM_SLEEP); 832 error = import_buffer(&op_ie, op, kop, bytes, IE_IMPORT); 833 } 834 835 DTRACE_XPV2(mmu__ext__op__start, int, count, struct mmuext_op *, 836 ((error == -X_EFAULT) ? op : kop)); 837 838 if (scount != NULL && error == 0) 839 error = import_buffer(&scnt_ie, scount, &kscount, 840 sizeof (kscount), IE_EXPORT); 841 842 if (error == 0) 843 error = HYPERVISOR_mmuext_op(kop, count, &kscount, domid); 844 export_buffer(&op_ie, &error); 845 export_buffer(&scnt_ie, &error); 846 847 DTRACE_XPV1(mmu__ext__op__end, int, error); 848 849 if (count > 1) 850 kmem_free(kop, bytes); 851 return (error); 852 } 853 854 static int 855 privcmd_HYPERVISOR_hvm_op(int cmd, void *arg) 856 { 857 int error; 858 int size = 0; 859 import_export_t arg_ie; 860 uint32_t flags = IE_IMPORT; 861 862 switch (cmd) { 863 case HVMOP_set_param: 864 case HVMOP_get_param: 865 size = sizeof (struct xen_hvm_param); 866 flags = IE_IMPEXP; 867 break; 868 case HVMOP_set_pci_intx_level: 869 size = sizeof (struct xen_hvm_set_pci_intx_level); 870 break; 871 case HVMOP_set_isa_irq_level: 872 size = sizeof (struct xen_hvm_set_isa_irq_level); 873 break; 874 case HVMOP_set_pci_link_route: 875 size = sizeof (struct xen_hvm_set_pci_link_route); 876 break; 877 878 default: 879 #ifdef DEBUG 880 printf("unrecognized HVM op 0x%x\n", cmd); 881 #endif 882 return (-X_EINVAL); 883 } 884 885 error = import_buffer(&arg_ie, arg, NULL, size, flags); 886 if (error == 0) 887 error = HYPERVISOR_hvm_op(cmd, arg_ie.ie_kaddr); 888 export_buffer(&arg_ie, &error); 889 890 return (error); 891 } 892 893 static int 894 privcmd_HYPERVISOR_sched_op(int cmd, void *arg) 895 { 896 int error; 897 int size = 0; 898 import_export_t op_ie; 899 struct sched_remote_shutdown op; 900 901 switch (cmd) { 902 case SCHEDOP_remote_shutdown: 903 size = sizeof (struct sched_remote_shutdown); 904 break; 905 default: 906 #ifdef DEBUG 907 printf("unrecognized sched op 0x%x\n", cmd); 908 #endif 909 return (-X_EINVAL); 910 } 911 912 error = import_buffer(&op_ie, arg, &op, size, IE_IMPORT); 913 if (error == 0) 914 error = HYPERVISOR_sched_op(cmd, (arg == NULL) ? NULL : &op); 915 export_buffer(&op_ie, &error); 916 917 return (error); 918 } 919 920 int allow_all_hypercalls = 0; 921 int privcmd_efault_debug = 0; 922 923 /*ARGSUSED*/ 924 int 925 do_privcmd_hypercall(void *uarg, int mode, cred_t *cr, int *rval) 926 { 927 privcmd_hypercall_t __hc, *hc = &__hc; 928 int error; 929 930 if (ddi_copyin(uarg, hc, sizeof (*hc), mode)) 931 return (EFAULT); 932 933 switch (hc->op) { 934 case __HYPERVISOR_mmu_update: 935 error = privcmd_HYPERVISOR_mmu_update( 936 (mmu_update_t *)hc->arg[0], (int)hc->arg[1], 937 (int *)hc->arg[2], (domid_t)hc->arg[3]); 938 break; 939 case __HYPERVISOR_domctl: 940 error = privcmd_HYPERVISOR_domctl( 941 (xen_domctl_t *)hc->arg[0]); 942 break; 943 case __HYPERVISOR_sysctl: 944 error = privcmd_HYPERVISOR_sysctl( 945 (xen_sysctl_t *)hc->arg[0]); 946 break; 947 case __HYPERVISOR_platform_op: 948 error = privcmd_HYPERVISOR_platform_op( 949 (xen_platform_op_t *)hc->arg[0]); 950 break; 951 case __HYPERVISOR_memory_op: 952 error = privcmd_HYPERVISOR_memory_op( 953 (int)hc->arg[0], (void *)hc->arg[1]); 954 break; 955 case __HYPERVISOR_event_channel_op: 956 error = privcmd_HYPERVISOR_event_channel_op( 957 (int)hc->arg[0], (void *)hc->arg[1]); 958 break; 959 case __HYPERVISOR_xen_version: 960 error = privcmd_HYPERVISOR_xen_version( 961 (int)hc->arg[0], (void *)hc->arg[1]); 962 break; 963 case __HYPERVISOR_mmuext_op: 964 error = privcmd_HYPERVISOR_mmuext_op( 965 (struct mmuext_op *)hc->arg[0], (int)hc->arg[1], 966 (uint_t *)hc->arg[2], (domid_t)hc->arg[3]); 967 break; 968 case __HYPERVISOR_acm_op: 969 error = privcmd_HYPERVISOR_acm_op( 970 (int)hc->arg[0], (void *)hc->arg[1]); 971 break; 972 case __HYPERVISOR_hvm_op: 973 error = privcmd_HYPERVISOR_hvm_op( 974 (int)hc->arg[0], (void *)hc->arg[1]); 975 break; 976 case __HYPERVISOR_sched_op: 977 error = privcmd_HYPERVISOR_sched_op( 978 (int)hc->arg[0], (void *)hc->arg[1]); 979 break; 980 default: 981 if (allow_all_hypercalls) 982 error = __hypercall5(hc->op, hc->arg[0], hc->arg[1], 983 hc->arg[2], hc->arg[3], hc->arg[4]); 984 else { 985 #ifdef DEBUG 986 printf("unrecognized hypercall %ld\n", hc->op); 987 #endif 988 error = -X_EPERM; 989 } 990 break; 991 } 992 993 if (error > 0) { 994 *rval = error; 995 error = 0; 996 } else if (error != 0) 997 error = xen_xlate_errcode(error); 998 999 return (error); 1000 } 1001