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