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