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, sub2_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 sub2_ie = null_ie; 369 370 /* 371 * Check this first because our wrapper will forcibly overwrite it. 372 */ 373 if (op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) { 374 error = -X_EACCES; 375 export_buffer(&op_ie, &error); 376 return (error); 377 } 378 379 switch (op.cmd) { 380 case XEN_SYSCTL_readconsole: { 381 error = import_handle(&sub_ie, &op.u.readconsole.buffer, 382 op.u.readconsole.count, IE_EXPORT); 383 break; 384 } 385 386 case XEN_SYSCTL_debug_keys: { 387 error = import_handle(&sub_ie, &op.u.debug_keys.keys, 388 op.u.debug_keys.nr_keys, IE_IMPORT); 389 break; 390 } 391 392 case XEN_SYSCTL_tbuf_op: 393 case XEN_SYSCTL_physinfo: 394 case XEN_SYSCTL_sched_id: 395 break; 396 397 case XEN_SYSCTL_perfc_op: { 398 xen_sysctl_perfc_desc_t *scdp; 399 /* 400 * If 'desc' is NULL, then the caller is asking for 401 * the number of counters. If 'desc' is non-NULL, 402 * then we need to know how many counters there are 403 * before wiring down the output buffer appropriately. 404 */ 405 /*LINTED: constant in conditional context*/ 406 get_xen_guest_handle_u(scdp, op.u.perfc_op.desc); 407 if (scdp != NULL) { 408 static int numcounters = -1; 409 static int numvals = -1; 410 411 if (numcounters == -1) { 412 xen_sysctl_t dop; 413 414 dop.cmd = XEN_SYSCTL_perfc_op; 415 dop.interface_version = 416 XEN_SYSCTL_INTERFACE_VERSION; 417 dop.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_query; 418 /*LINTED: constant in conditional context*/ 419 set_xen_guest_handle_u(dop.u.perfc_op.desc, 420 NULL); 421 /*LINTED: constant in conditional context*/ 422 set_xen_guest_handle_u(dop.u.perfc_op.val, 423 NULL); 424 425 error = HYPERVISOR_sysctl(&dop); 426 if (error != 0) 427 break; 428 numcounters = dop.u.perfc_op.nr_counters; 429 numvals = dop.u.perfc_op.nr_vals; 430 } 431 ASSERT(numcounters != -1); 432 ASSERT(numvals != -1); 433 error = import_handle(&sub_ie, &op.u.perfc_op.desc, 434 (sizeof (xen_sysctl_perfc_desc_t) * numcounters), 435 IE_EXPORT); 436 error = import_handle(&sub2_ie, &op.u.perfc_op.val, 437 (sizeof (xen_sysctl_perfc_val_t) * numvals), 438 IE_EXPORT); 439 } 440 break; 441 } 442 443 case XEN_SYSCTL_getdomaininfolist: { 444 error = import_handle(&sub_ie, &op.u.getdomaininfolist.buffer, 445 (op.u.getdomaininfolist.max_domains * 446 sizeof (xen_domctl_getdomaininfo_t)), IE_EXPORT); 447 break; 448 } 449 450 case XEN_SYSCTL_getcpuinfo: 451 error = import_handle(&sub_ie, &op.u.getcpuinfo.info, 452 op.u.getcpuinfo.max_cpus * 453 sizeof (xen_sysctl_cpuinfo_t), IE_EXPORT); 454 break; 455 default: 456 #ifdef DEBUG 457 printf("unrecognized HYPERVISOR_sysctl %d\n", op.cmd); 458 #endif 459 error = -X_EINVAL; 460 } 461 462 if (error == 0) 463 error = HYPERVISOR_sysctl(&op); 464 465 export_buffer(&op_ie, &error); 466 export_buffer(&sub_ie, &error); 467 export_buffer(&sub2_ie, &error); 468 469 return (error); 470 } 471 472 static int 473 privcmd_HYPERVISOR_platform_op(xen_platform_op_t *opp) 474 { 475 import_export_t op_ie, sub_ie; 476 xen_platform_op_t op; 477 int error; 478 479 if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0) 480 return (-X_EFAULT); 481 482 sub_ie = null_ie; 483 484 /* 485 * Check this first because our wrapper will forcibly overwrite it. 486 */ 487 if (op.interface_version != XENPF_INTERFACE_VERSION) { 488 error = -X_EACCES; 489 export_buffer(&op_ie, &error); 490 return (error); 491 } 492 493 /* 494 * Now handle any platform ops with embedded pointers elsewhere 495 * in the user address space that also need to be tacked down 496 * while the hypervisor futzes with them. 497 */ 498 switch (op.cmd) { 499 case XENPF_settime: 500 case XENPF_add_memtype: 501 case XENPF_del_memtype: 502 case XENPF_read_memtype: 503 case XENPF_platform_quirk: 504 break; 505 506 case XENPF_microcode_update: 507 error = import_handle(&sub_ie, &op.u.microcode.data, 508 op.u.microcode.length, IE_IMPORT); 509 break; 510 511 default: 512 #ifdef DEBUG 513 printf("unrecognized HYPERVISOR_platform_op %d\n", op.cmd); 514 #endif 515 return (-X_EINVAL); 516 } 517 518 if (error == 0) 519 error = HYPERVISOR_platform_op(&op); 520 521 export_buffer(&op_ie, &error); 522 export_buffer(&sub_ie, &error); 523 524 return (error); 525 } 526 527 static int 528 privcmd_HYPERVISOR_memory_op(int cmd, void *arg) 529 { 530 int error = 0; 531 import_export_t op_ie, sub_ie, gpfn_ie, mfn_ie; 532 union { 533 domid_t domid; 534 struct xen_memory_reservation resv; 535 struct xen_machphys_mfn_list xmml; 536 struct xen_add_to_physmap xatp; 537 struct xen_translate_gpfn_list tgl; 538 struct xen_memory_map mm; 539 struct xen_foreign_memory_map fmm; 540 } op_arg; 541 542 op_ie = sub_ie = gpfn_ie = mfn_ie = null_ie; 543 544 switch (cmd) { 545 case XENMEM_increase_reservation: 546 case XENMEM_decrease_reservation: 547 case XENMEM_populate_physmap: { 548 ulong_t *taddr; 549 550 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.resv), 551 IE_IMPEXP) != 0) 552 return (-X_EFAULT); 553 554 error = import_handle(&sub_ie, &op_arg.resv.extent_start, 555 (op_arg.resv.nr_extents * sizeof (ulong_t)), IE_IMPEXP); 556 557 if (error == -X_EFAULT) 558 /*LINTED: constant in conditional context*/ 559 get_xen_guest_handle(taddr, op_arg.resv.extent_start); 560 else 561 taddr = sub_ie.ie_kaddr; 562 563 switch (cmd) { 564 case XENMEM_increase_reservation: 565 DTRACE_XPV4(increase__reservation__start, 566 domid_t, op_arg.resv.domid, 567 ulong_t, op_arg.resv.nr_extents, 568 uint_t, op_arg.resv.extent_order, 569 ulong_t *, taddr); 570 break; 571 case XENMEM_decrease_reservation: 572 DTRACE_XPV4(decrease__reservation__start, 573 domid_t, op_arg.resv.domid, 574 ulong_t, op_arg.resv.nr_extents, 575 uint_t, op_arg.resv.extent_order, 576 ulong_t *, taddr); 577 break; 578 case XENMEM_populate_physmap: 579 DTRACE_XPV3(populate__physmap__start, 580 domid_t, op_arg.resv.domid, 581 ulong_t, op_arg.resv.nr_extents, 582 ulong_t *, taddr); 583 break; 584 } 585 586 break; 587 } 588 589 case XENMEM_maximum_ram_page: 590 break; 591 592 case XENMEM_current_reservation: 593 case XENMEM_maximum_reservation: 594 case XENMEM_maximum_gpfn: 595 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.domid), 596 IE_IMPEXP) != 0) 597 return (-X_EFAULT); 598 break; 599 600 case XENMEM_machphys_mfn_list: { 601 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xmml), 602 IE_IMPEXP) != 0) 603 return (-X_EFAULT); 604 605 error = import_handle(&sub_ie, &op_arg.xmml.extent_start, 606 (op_arg.xmml.max_extents * sizeof (ulong_t)), IE_IMPEXP); 607 break; 608 } 609 610 case XENMEM_add_to_physmap: 611 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xatp), 612 IE_IMPEXP) != 0) 613 return (-X_EFAULT); 614 DTRACE_XPV4(add__to__physmap__start, domid_t, 615 op_arg.xatp.domid, uint_t, op_arg.xatp.space, ulong_t, 616 op_arg.xatp.idx, ulong_t, op_arg.xatp.gpfn); 617 break; 618 619 case XENMEM_translate_gpfn_list: { 620 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.tgl), 621 IE_IMPEXP) != 0) 622 return (-X_EFAULT); 623 624 error = import_handle(&gpfn_ie, &op_arg.tgl.gpfn_list, 625 (op_arg.tgl.nr_gpfns * sizeof (long)), IE_IMPORT); 626 if (error == 0) 627 error = import_handle(&mfn_ie, &op_arg.tgl.mfn_list, 628 (op_arg.tgl.nr_gpfns * sizeof (long)), IE_EXPORT); 629 break; 630 } 631 632 case XENMEM_memory_map: 633 case XENMEM_machine_memory_map: { 634 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.mm), 635 IE_EXPORT) != 0) 636 return (-X_EFAULT); 637 638 /* 639 * XXPV: ugh. e820entry is packed, but not in the kernel, since 640 * we remove all attributes; seems like this is a nice way to 641 * break mysteriously. 642 */ 643 error = import_handle(&sub_ie, &op_arg.mm.buffer, 644 (op_arg.mm.nr_entries * 20), IE_IMPEXP); 645 break; 646 } 647 648 case XENMEM_set_memory_map: { 649 struct xen_memory_map *taddr; 650 if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.fmm), 651 IE_IMPORT) != 0) 652 return (-X_EFAULT); 653 654 /* 655 * As above. 656 */ 657 error = import_handle(&sub_ie, &op_arg.fmm.map.buffer, 658 (op_arg.fmm.map.nr_entries * 20), IE_IMPEXP); 659 660 if (error == -X_EFAULT) 661 /*LINTED: constant in conditional context*/ 662 get_xen_guest_handle(taddr, op_arg.fmm.map.buffer); 663 else 664 taddr = sub_ie.ie_kaddr; 665 DTRACE_XPV3(set__memory__map__start, domid_t, 666 op_arg.fmm.domid, int, op_arg.fmm.map.nr_entries, 667 struct xen_memory_map *, taddr); 668 break; 669 } 670 671 default: 672 #ifdef DEBUG 673 printf("unrecognized HYPERVISOR_memory_op %d\n", cmd); 674 #endif 675 return (-X_EINVAL); 676 } 677 678 if (error == 0) 679 error = HYPERVISOR_memory_op(cmd, 680 (arg == NULL) ? NULL: &op_arg); 681 682 export_buffer(&op_ie, &error); 683 export_buffer(&sub_ie, &error); 684 export_buffer(&gpfn_ie, &error); 685 export_buffer(&mfn_ie, &error); 686 687 switch (cmd) { 688 case XENMEM_increase_reservation: 689 DTRACE_XPV1(increase__reservation__end, int, error); 690 break; 691 case XENMEM_decrease_reservation: 692 DTRACE_XPV1(decrease__reservation__end, int, error); 693 break; 694 case XENMEM_populate_physmap: 695 DTRACE_XPV1(populate__physmap__end, int, error); 696 break; 697 case XENMEM_add_to_physmap: 698 DTRACE_XPV1(add__to__physmap__end, int, error); 699 break; 700 case XENMEM_set_memory_map: 701 DTRACE_XPV1(set__memory__map__end, int, error); 702 break; 703 } 704 return (error); 705 } 706 707 static int 708 privcmd_HYPERVISOR_event_channel_op(int cmd, void *arg) 709 { 710 int error; 711 size_t size; 712 import_export_t op_ie; 713 uint32_t flags; 714 715 switch (cmd) { 716 case EVTCHNOP_alloc_unbound: 717 size = sizeof (evtchn_alloc_unbound_t); 718 flags = IE_IMPEXP; 719 break; 720 case EVTCHNOP_bind_interdomain: 721 size = sizeof (evtchn_bind_interdomain_t); 722 flags = IE_IMPEXP; 723 break; 724 case EVTCHNOP_bind_virq: 725 size = sizeof (evtchn_bind_virq_t); 726 flags = IE_IMPEXP; 727 break; 728 case EVTCHNOP_bind_pirq: 729 size = sizeof (evtchn_bind_pirq_t); 730 flags = IE_IMPEXP; 731 break; 732 case EVTCHNOP_bind_ipi: 733 size = sizeof (evtchn_bind_ipi_t); 734 flags = IE_IMPEXP; 735 break; 736 case EVTCHNOP_close: 737 size = sizeof (evtchn_close_t); 738 flags = IE_IMPORT; 739 break; 740 case EVTCHNOP_send: 741 size = sizeof (evtchn_send_t); 742 flags = IE_IMPORT; 743 break; 744 case EVTCHNOP_status: 745 size = sizeof (evtchn_status_t); 746 flags = IE_IMPEXP; 747 break; 748 case EVTCHNOP_bind_vcpu: 749 size = sizeof (evtchn_bind_vcpu_t); 750 flags = IE_IMPORT; 751 break; 752 case EVTCHNOP_unmask: 753 size = sizeof (evtchn_unmask_t); 754 flags = IE_IMPORT; 755 break; 756 case EVTCHNOP_reset: 757 size = sizeof (evtchn_reset_t); 758 flags = IE_IMPORT; 759 break; 760 761 default: 762 #ifdef DEBUG 763 printf("unrecognized HYPERVISOR_event_channel op %d\n", cmd); 764 #endif 765 return (-X_EINVAL); 766 } 767 768 error = import_buffer(&op_ie, arg, NULL, size, flags); 769 770 /* 771 * If there is sufficient demand, we can replace this void * with 772 * the proper op structure pointer. 773 */ 774 DTRACE_XPV2(evtchn__op__start, int, cmd, void *, 775 ((error == -X_EFAULT) ? arg : op_ie.ie_kaddr)); 776 777 if (error == 0) 778 error = HYPERVISOR_event_channel_op(cmd, op_ie.ie_kaddr); 779 export_buffer(&op_ie, &error); 780 781 DTRACE_XPV1(evtchn__op__end, int, error); 782 783 return (error); 784 } 785 786 static int 787 privcmd_HYPERVISOR_xen_version(int cmd, void *arg) 788 { 789 int error; 790 int size = 0; 791 import_export_t op_ie; 792 uint32_t flags = IE_EXPORT; 793 794 switch (cmd) { 795 case XENVER_version: 796 break; 797 case XENVER_extraversion: 798 size = sizeof (xen_extraversion_t); 799 break; 800 case XENVER_compile_info: 801 size = sizeof (xen_compile_info_t); 802 break; 803 case XENVER_capabilities: 804 size = sizeof (xen_capabilities_info_t); 805 break; 806 case XENVER_changeset: 807 size = sizeof (xen_changeset_info_t); 808 break; 809 case XENVER_platform_parameters: 810 size = sizeof (xen_platform_parameters_t); 811 break; 812 case XENVER_get_features: 813 flags = IE_IMPEXP; 814 size = sizeof (xen_feature_info_t); 815 break; 816 case XENVER_pagesize: 817 break; 818 case XENVER_guest_handle: 819 size = sizeof (xen_domain_handle_t); 820 break; 821 822 default: 823 #ifdef DEBUG 824 printf("unrecognized HYPERVISOR_xen_version op %d\n", cmd); 825 #endif 826 return (-X_EINVAL); 827 } 828 829 error = import_buffer(&op_ie, arg, NULL, size, flags); 830 if (error == 0) 831 error = HYPERVISOR_xen_version(cmd, op_ie.ie_kaddr); 832 export_buffer(&op_ie, &error); 833 834 return (error); 835 } 836 837 static int 838 privcmd_HYPERVISOR_acm_op(void *uacmctl) 839 { 840 int error; 841 struct xen_acmctl *acmctl; 842 import_export_t op_ie; 843 844 error = import_buffer(&op_ie, uacmctl, NULL, sizeof (*acmctl), 845 IE_IMPEXP); 846 if (error != 0) 847 return (error); 848 849 acmctl = op_ie.ie_kaddr; 850 851 if (acmctl->interface_version != ACM_INTERFACE_VERSION) { 852 #ifdef DEBUG 853 printf("acm vers mismatch (cmd %d, found 0x%x, need 0x%x\n", 854 acmctl->cmd, acmctl->interface_version, 855 ACM_INTERFACE_VERSION); 856 #endif 857 error = -X_EACCES; 858 export_buffer(&op_ie, &error); 859 return (error); 860 } 861 862 switch (acmctl->cmd) { 863 case ACMOP_setpolicy: 864 case ACMOP_getpolicy: 865 case ACMOP_dumpstats: 866 case ACMOP_getssid: 867 case ACMOP_getdecision: 868 case ACMOP_chgpolicy: 869 case ACMOP_relabeldoms: 870 break; 871 default: 872 #ifdef DEBUG 873 printf("unrecognized HYPERVISOR_acm_op op %d\n", acmctl->cmd); 874 #endif 875 return (-X_EINVAL); 876 } 877 878 if (error == 0) 879 error = HYPERVISOR_acm_op(acmctl); 880 export_buffer(&op_ie, &error); 881 882 return (error); 883 } 884 885 static int 886 privcmd_HYPERVISOR_mmuext_op(struct mmuext_op *op, int count, uint_t *scount, 887 domid_t domid) 888 { 889 int error, bytes; 890 uint_t kscount; 891 struct mmuext_op *kop, single_kop; 892 import_export_t op_ie, scnt_ie; 893 894 op_ie = scnt_ie = null_ie; 895 error = 0; 896 897 if (count >= 1) { 898 bytes = count * sizeof (*kop); 899 kop = (count == 1) ? &single_kop : kmem_alloc(bytes, KM_SLEEP); 900 error = import_buffer(&op_ie, op, kop, bytes, IE_IMPORT); 901 } 902 903 DTRACE_XPV2(mmu__ext__op__start, int, count, struct mmuext_op *, 904 ((error == -X_EFAULT) ? op : kop)); 905 906 if (scount != NULL && error == 0) 907 error = import_buffer(&scnt_ie, scount, &kscount, 908 sizeof (kscount), IE_EXPORT); 909 910 if (error == 0) 911 error = HYPERVISOR_mmuext_op(kop, count, &kscount, domid); 912 export_buffer(&op_ie, &error); 913 export_buffer(&scnt_ie, &error); 914 915 DTRACE_XPV1(mmu__ext__op__end, int, error); 916 917 if (count > 1) 918 kmem_free(kop, bytes); 919 return (error); 920 } 921 922 static int 923 privcmd_HYPERVISOR_hvm_op(int cmd, void *arg) 924 { 925 int error; 926 int size = 0; 927 import_export_t arg_ie; 928 uint32_t flags = IE_IMPORT; 929 930 switch (cmd) { 931 case HVMOP_set_param: 932 case HVMOP_get_param: 933 size = sizeof (struct xen_hvm_param); 934 flags = IE_IMPEXP; 935 break; 936 case HVMOP_set_pci_intx_level: 937 size = sizeof (struct xen_hvm_set_pci_intx_level); 938 break; 939 case HVMOP_set_isa_irq_level: 940 size = sizeof (struct xen_hvm_set_isa_irq_level); 941 break; 942 case HVMOP_set_pci_link_route: 943 size = sizeof (struct xen_hvm_set_pci_link_route); 944 break; 945 946 default: 947 #ifdef DEBUG 948 printf("unrecognized HVM op 0x%x\n", cmd); 949 #endif 950 return (-X_EINVAL); 951 } 952 953 error = import_buffer(&arg_ie, arg, NULL, size, flags); 954 if (error == 0) 955 error = HYPERVISOR_hvm_op(cmd, arg_ie.ie_kaddr); 956 export_buffer(&arg_ie, &error); 957 958 return (error); 959 } 960 961 static int 962 privcmd_HYPERVISOR_sched_op(int cmd, void *arg) 963 { 964 int error; 965 int size = 0; 966 import_export_t op_ie; 967 struct sched_remote_shutdown op; 968 969 switch (cmd) { 970 case SCHEDOP_remote_shutdown: 971 size = sizeof (struct sched_remote_shutdown); 972 break; 973 default: 974 #ifdef DEBUG 975 printf("unrecognized sched op 0x%x\n", cmd); 976 #endif 977 return (-X_EINVAL); 978 } 979 980 error = import_buffer(&op_ie, arg, &op, size, IE_IMPORT); 981 if (error == 0) 982 error = HYPERVISOR_sched_op(cmd, (arg == NULL) ? NULL : &op); 983 export_buffer(&op_ie, &error); 984 985 return (error); 986 } 987 988 int allow_all_hypercalls = 0; 989 int privcmd_efault_debug = 0; 990 991 /*ARGSUSED*/ 992 int 993 do_privcmd_hypercall(void *uarg, int mode, cred_t *cr, int *rval) 994 { 995 privcmd_hypercall_t __hc, *hc = &__hc; 996 int error; 997 998 if (ddi_copyin(uarg, hc, sizeof (*hc), mode)) 999 return (EFAULT); 1000 1001 switch (hc->op) { 1002 case __HYPERVISOR_mmu_update: 1003 error = privcmd_HYPERVISOR_mmu_update( 1004 (mmu_update_t *)hc->arg[0], (int)hc->arg[1], 1005 (int *)hc->arg[2], (domid_t)hc->arg[3]); 1006 break; 1007 case __HYPERVISOR_domctl: 1008 error = privcmd_HYPERVISOR_domctl( 1009 (xen_domctl_t *)hc->arg[0]); 1010 break; 1011 case __HYPERVISOR_sysctl: 1012 error = privcmd_HYPERVISOR_sysctl( 1013 (xen_sysctl_t *)hc->arg[0]); 1014 break; 1015 case __HYPERVISOR_platform_op: 1016 error = privcmd_HYPERVISOR_platform_op( 1017 (xen_platform_op_t *)hc->arg[0]); 1018 break; 1019 case __HYPERVISOR_memory_op: 1020 error = privcmd_HYPERVISOR_memory_op( 1021 (int)hc->arg[0], (void *)hc->arg[1]); 1022 break; 1023 case __HYPERVISOR_event_channel_op: 1024 error = privcmd_HYPERVISOR_event_channel_op( 1025 (int)hc->arg[0], (void *)hc->arg[1]); 1026 break; 1027 case __HYPERVISOR_xen_version: 1028 error = privcmd_HYPERVISOR_xen_version( 1029 (int)hc->arg[0], (void *)hc->arg[1]); 1030 break; 1031 case __HYPERVISOR_mmuext_op: 1032 error = privcmd_HYPERVISOR_mmuext_op( 1033 (struct mmuext_op *)hc->arg[0], (int)hc->arg[1], 1034 (uint_t *)hc->arg[2], (domid_t)hc->arg[3]); 1035 break; 1036 case __HYPERVISOR_acm_op: 1037 error = privcmd_HYPERVISOR_acm_op((void *)hc->arg[0]); 1038 break; 1039 case __HYPERVISOR_hvm_op: 1040 error = privcmd_HYPERVISOR_hvm_op( 1041 (int)hc->arg[0], (void *)hc->arg[1]); 1042 break; 1043 case __HYPERVISOR_sched_op: 1044 error = privcmd_HYPERVISOR_sched_op( 1045 (int)hc->arg[0], (void *)hc->arg[1]); 1046 break; 1047 default: 1048 if (allow_all_hypercalls) 1049 error = __hypercall5(hc->op, hc->arg[0], hc->arg[1], 1050 hc->arg[2], hc->arg[3], hc->arg[4]); 1051 else { 1052 #ifdef DEBUG 1053 printf("unrecognized hypercall %ld\n", hc->op); 1054 #endif 1055 error = -X_EPERM; 1056 } 1057 break; 1058 } 1059 1060 if (error > 0) { 1061 *rval = error; 1062 error = 0; 1063 } else if (error != 0) 1064 error = xen_xlate_errcode(error); 1065 1066 return (error); 1067 } 1068