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