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 /*
  23  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * System call I/F to doors (outside of vnodes I/F) and misc support
  28  * routines
  29  */
  30 #include <sys/types.h>
  31 #include <sys/systm.h>
  32 #include <sys/door.h>
  33 #include <sys/door_data.h>
  34 #include <sys/proc.h>
  35 #include <sys/thread.h>
  36 #include <sys/prsystm.h>
  37 #include <sys/procfs.h>
  38 #include <sys/class.h>
  39 #include <sys/cred.h>
  40 #include <sys/kmem.h>
  41 #include <sys/cmn_err.h>
  42 #include <sys/stack.h>
  43 #include <sys/debug.h>
  44 #include <sys/cpuvar.h>
  45 #include <sys/file.h>
  46 #include <sys/fcntl.h>
  47 #include <sys/vnode.h>
  48 #include <sys/vfs.h>
  49 #include <sys/vfs_opreg.h>
  50 #include <sys/sobject.h>
  51 #include <sys/schedctl.h>
  52 #include <sys/callb.h>
  53 #include <sys/ucred.h>
  54 
  55 #include <sys/mman.h>
  56 #include <sys/sysmacros.h>
  57 #include <sys/vmsystm.h>
  58 #include <vm/as.h>
  59 #include <vm/hat.h>
  60 #include <vm/page.h>
  61 #include <vm/seg.h>
  62 #include <vm/seg_vn.h>
  63 #include <vm/seg_vn.h>
  64 #include <vm/seg_kpm.h>
  65 
  66 #include <sys/modctl.h>
  67 #include <sys/syscall.h>
  68 #include <sys/pathname.h>
  69 #include <sys/rctl.h>
  70 
  71 /*
  72  * The maximum amount of data (in bytes) that will be transferred using
  73  * an intermediate kernel buffer.  For sizes greater than this we map
  74  * in the destination pages and perform a 1-copy transfer.
  75  */
  76 size_t  door_max_arg = 16 * 1024;
  77 
  78 /*
  79  * Maximum amount of data that will be transferred in a reply to a
  80  * door_upcall.  Need to guard against a process returning huge amounts
  81  * of data and getting the kernel stuck in kmem_alloc.
  82  */
  83 size_t  door_max_upcall_reply = 1024 * 1024;
  84 
  85 /*
  86  * Maximum number of descriptors allowed to be passed in a single
  87  * door_call or door_return.  We need to allocate kernel memory
  88  * for all of them at once, so we can't let it scale without limit.
  89  */
  90 uint_t door_max_desc = 1024;
  91 
  92 /*
  93  * Definition of a door handle, used by other kernel subsystems when
  94  * calling door functions.  This is really a file structure but we
  95  * want to hide that fact.
  96  */
  97 struct __door_handle {
  98         file_t dh_file;
  99 };
 100 
 101 #define DHTOF(dh) ((file_t *)(dh))
 102 #define FTODH(fp) ((door_handle_t)(fp))
 103 
 104 static int doorfs(long, long, long, long, long, long);
 105 
 106 static struct sysent door_sysent = {
 107         6,
 108         SE_ARGC | SE_NOUNLOAD,
 109         (int (*)())doorfs,
 110 };
 111 
 112 static struct modlsys modlsys = {
 113         &mod_syscallops, "doors", &door_sysent
 114 };
 115 
 116 #ifdef _SYSCALL32_IMPL
 117 
 118 static int
 119 doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
 120     int32_t arg5, int32_t subcode);
 121 
 122 static struct sysent door_sysent32 = {
 123         6,
 124         SE_ARGC | SE_NOUNLOAD,
 125         (int (*)())doorfs32,
 126 };
 127 
 128 static struct modlsys modlsys32 = {
 129         &mod_syscallops32,
 130         "32-bit door syscalls",
 131         &door_sysent32
 132 };
 133 #endif
 134 
 135 static struct modlinkage modlinkage = {
 136         MODREV_1,
 137         &modlsys,
 138 #ifdef _SYSCALL32_IMPL
 139         &modlsys32,
 140 #endif
 141         NULL
 142 };
 143 
 144 dev_t   doordev;
 145 
 146 extern  struct vfs door_vfs;
 147 extern  struct vnodeops *door_vnodeops;
 148 
 149 int
 150 _init(void)
 151 {
 152         static const fs_operation_def_t door_vfsops_template[] = {
 153                 NULL, NULL
 154         };
 155         extern const fs_operation_def_t door_vnodeops_template[];
 156         vfsops_t *door_vfsops;
 157         major_t major;
 158         int error;
 159 
 160         mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
 161         if ((major = getudev()) == (major_t)-1)
 162                 return (ENXIO);
 163         doordev = makedevice(major, 0);
 164 
 165         /* Create a dummy vfs */
 166         error = vfs_makefsops(door_vfsops_template, &door_vfsops);
 167         if (error != 0) {
 168                 cmn_err(CE_WARN, "door init: bad vfs ops");
 169                 return (error);
 170         }
 171         VFS_INIT(&door_vfs, door_vfsops, NULL);
 172         door_vfs.vfs_flag = VFS_RDONLY;
 173         door_vfs.vfs_dev = doordev;
 174         vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
 175 
 176         error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
 177         if (error != 0) {
 178                 vfs_freevfsops(door_vfsops);
 179                 cmn_err(CE_WARN, "door init: bad vnode ops");
 180                 return (error);
 181         }
 182         return (mod_install(&modlinkage));
 183 }
 184 
 185 int
 186 _info(struct modinfo *modinfop)
 187 {
 188         return (mod_info(&modlinkage, modinfop));
 189 }
 190 
 191 /* system call functions */
 192 static int door_call(int, void *);
 193 static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
 194 static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
 195     uint_t), void *data_cookie, uint_t);
 196 static int door_revoke(int);
 197 static int door_info(int, struct door_info *);
 198 static int door_ucred(struct ucred_s *);
 199 static int door_bind(int);
 200 static int door_unbind(void);
 201 static int door_unref(void);
 202 static int door_getparam(int, int, size_t *);
 203 static int door_setparam(int, int, size_t);
 204 
 205 #define DOOR_RETURN_OLD 4               /* historic value, for s10 */
 206 
 207 /*
 208  * System call wrapper for all door related system calls
 209  */
 210 static int
 211 doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
 212 {
 213         switch (subcode) {
 214         case DOOR_CALL:
 215                 return (door_call(arg1, (void *)arg2));
 216         case DOOR_RETURN: {
 217                 door_return_desc_t *drdp = (door_return_desc_t *)arg3;
 218 
 219                 if (drdp != NULL) {
 220                         door_return_desc_t drd;
 221                         if (copyin(drdp, &drd, sizeof (drd)))
 222                                 return (EFAULT);
 223                         return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
 224                             drd.desc_num, (caddr_t)arg4, arg5));
 225                 }
 226                 return (door_return((caddr_t)arg1, arg2, NULL,
 227                     0, (caddr_t)arg4, arg5));
 228         }
 229         case DOOR_RETURN_OLD:
 230                 /*
 231                  * In order to support the S10 runtime environment, we
 232                  * still respond to the old syscall subcode for door_return.
 233                  * We treat it as having no stack limits.  This code should
 234                  * be removed when such support is no longer needed.
 235                  */
 236                 return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
 237                     arg4, (caddr_t)arg5, 0));
 238         case DOOR_CREATE:
 239                 return (door_create((void (*)())arg1, (void *)arg2, arg3));
 240         case DOOR_REVOKE:
 241                 return (door_revoke(arg1));
 242         case DOOR_INFO:
 243                 return (door_info(arg1, (struct door_info *)arg2));
 244         case DOOR_BIND:
 245                 return (door_bind(arg1));
 246         case DOOR_UNBIND:
 247                 return (door_unbind());
 248         case DOOR_UNREFSYS:
 249                 return (door_unref());
 250         case DOOR_UCRED:
 251                 return (door_ucred((struct ucred_s *)arg1));
 252         case DOOR_GETPARAM:
 253                 return (door_getparam(arg1, arg2, (size_t *)arg3));
 254         case DOOR_SETPARAM:
 255                 return (door_setparam(arg1, arg2, arg3));
 256         default:
 257                 return (set_errno(EINVAL));
 258         }
 259 }
 260 
 261 #ifdef _SYSCALL32_IMPL
 262 /*
 263  * System call wrapper for all door related system calls from 32-bit programs.
 264  * Needed at the moment because of the casts - they undo some damage
 265  * that truss causes (sign-extending the stack pointer) when truss'ing
 266  * a 32-bit program using doors.
 267  */
 268 static int
 269 doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
 270     int32_t arg4, int32_t arg5, int32_t subcode)
 271 {
 272         switch (subcode) {
 273         case DOOR_CALL:
 274                 return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
 275         case DOOR_RETURN: {
 276                 door_return_desc32_t *drdp =
 277                     (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
 278                 if (drdp != NULL) {
 279                         door_return_desc32_t drd;
 280                         if (copyin(drdp, &drd, sizeof (drd)))
 281                                 return (EFAULT);
 282                         return (door_return(
 283                             (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
 284                             (door_desc_t *)(uintptr_t)drd.desc_ptr,
 285                             drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
 286                             (size_t)(uintptr_t)(size32_t)arg5));
 287                 }
 288                 return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
 289                     arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
 290                     (size_t)(uintptr_t)(size32_t)arg5));
 291         }
 292         case DOOR_RETURN_OLD:
 293                 /*
 294                  * In order to support the S10 runtime environment, we
 295                  * still respond to the old syscall subcode for door_return.
 296                  * We treat it as having no stack limits.  This code should
 297                  * be removed when such support is no longer needed.
 298                  */
 299                 return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
 300                     (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
 301                     (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
 302         case DOOR_CREATE:
 303                 return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
 304                     (void *)(uintptr_t)(caddr32_t)arg2, arg3));
 305         case DOOR_REVOKE:
 306                 return (door_revoke(arg1));
 307         case DOOR_INFO:
 308                 return (door_info(arg1,
 309                     (struct door_info *)(uintptr_t)(caddr32_t)arg2));
 310         case DOOR_BIND:
 311                 return (door_bind(arg1));
 312         case DOOR_UNBIND:
 313                 return (door_unbind());
 314         case DOOR_UNREFSYS:
 315                 return (door_unref());
 316         case DOOR_UCRED:
 317                 return (door_ucred(
 318                     (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
 319         case DOOR_GETPARAM:
 320                 return (door_getparam(arg1, arg2,
 321                     (size_t *)(uintptr_t)(caddr32_t)arg3));
 322         case DOOR_SETPARAM:
 323                 return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
 324 
 325         default:
 326                 return (set_errno(EINVAL));
 327         }
 328 }
 329 #endif
 330 
 331 void shuttle_resume(kthread_t *, kmutex_t *);
 332 void shuttle_swtch(kmutex_t *);
 333 void shuttle_sleep(kthread_t *);
 334 
 335 /*
 336  * Support routines
 337  */
 338 static int door_create_common(void (*)(), void *, uint_t, int, int *,
 339     file_t **);
 340 static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
 341 static int door_args(kthread_t *, int);
 342 static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
 343 static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
 344 static void     door_server_exit(proc_t *, kthread_t *);
 345 static void     door_release_server(door_node_t *, kthread_t *);
 346 static kthread_t        *door_get_server(door_node_t *);
 347 static door_node_t      *door_lookup(int, file_t **);
 348 static int      door_translate_in(void);
 349 static int      door_translate_out(void);
 350 static void     door_fd_rele(door_desc_t *, uint_t, int);
 351 static void     door_list_insert(door_node_t *);
 352 static void     door_info_common(door_node_t *, door_info_t *, file_t *);
 353 static int      door_release_fds(door_desc_t *, uint_t);
 354 static void     door_fd_close(door_desc_t *, uint_t);
 355 static void     door_fp_close(struct file **, uint_t);
 356 
 357 static door_data_t *
 358 door_my_data(int create_if_missing)
 359 {
 360         door_data_t *ddp;
 361 
 362         ddp = curthread->t_door;
 363         if (create_if_missing && ddp == NULL)
 364                 ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
 365 
 366         return (ddp);
 367 }
 368 
 369 static door_server_t *
 370 door_my_server(int create_if_missing)
 371 {
 372         door_data_t *ddp = door_my_data(create_if_missing);
 373 
 374         return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
 375 }
 376 
 377 static door_client_t *
 378 door_my_client(int create_if_missing)
 379 {
 380         door_data_t *ddp = door_my_data(create_if_missing);
 381 
 382         return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
 383 }
 384 
 385 /*
 386  * System call to create a door
 387  */
 388 int
 389 door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
 390 {
 391         int fd;
 392         int err;
 393 
 394         if ((attributes & ~DOOR_CREATE_MASK) ||
 395             ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
 396             (DOOR_UNREF | DOOR_UNREF_MULTI)))
 397                 return (set_errno(EINVAL));
 398 
 399         if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
 400             &fd, NULL)) != 0)
 401                 return (set_errno(err));
 402 
 403         f_setfd(fd, FD_CLOEXEC);
 404         return (fd);
 405 }
 406 
 407 /*
 408  * Common code for creating user and kernel doors.  If a door was
 409  * created, stores a file structure pointer in the location pointed
 410  * to by fpp (if fpp is non-NULL) and returns 0.  Also, if a non-NULL
 411  * pointer to a file descriptor is passed in as fdp, allocates a file
 412  * descriptor representing the door.  If a door could not be created,
 413  * returns an error.
 414  */
 415 static int
 416 door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
 417     int from_kernel, int *fdp, file_t **fpp)
 418 {
 419         door_node_t     *dp;
 420         vnode_t         *vp;
 421         struct file     *fp;
 422         static door_id_t index = 0;
 423         proc_t          *p = (from_kernel)? &p0 : curproc;
 424 
 425         dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
 426 
 427         dp->door_vnode = vn_alloc(KM_SLEEP);
 428         dp->door_target = p;
 429         dp->door_data = data_cookie;
 430         dp->door_pc = pc_cookie;
 431         dp->door_flags = attributes;
 432 #ifdef _SYSCALL32_IMPL
 433         if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
 434                 dp->door_data_max = UINT32_MAX;
 435         else
 436 #endif
 437                 dp->door_data_max = SIZE_MAX;
 438         dp->door_data_min = 0UL;
 439         dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
 440 
 441         vp = DTOV(dp);
 442         vn_setops(vp, door_vnodeops);
 443         vp->v_type = VDOOR;
 444         vp->v_vfsp = &door_vfs;
 445         vp->v_data = (caddr_t)dp;
 446         mutex_enter(&door_knob);
 447         dp->door_index = index++;
 448         /* add to per-process door list */
 449         door_list_insert(dp);
 450         mutex_exit(&door_knob);
 451 
 452         if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
 453                 /*
 454                  * If the file table is full, remove the door from the
 455                  * per-process list, free the door, and return NULL.
 456                  */
 457                 mutex_enter(&door_knob);
 458                 door_list_delete(dp);
 459                 mutex_exit(&door_knob);
 460                 vn_free(vp);
 461                 kmem_free(dp, sizeof (door_node_t));
 462                 return (EMFILE);
 463         }
 464         vn_exists(vp);
 465         if (fdp != NULL)
 466                 setf(*fdp, fp);
 467         mutex_exit(&fp->f_tlock);
 468 
 469         if (fpp != NULL)
 470                 *fpp = fp;
 471         return (0);
 472 }
 473 
 474 static int
 475 door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
 476 {
 477         ASSERT(MUTEX_HELD(&door_knob));
 478 
 479         /* we allow unref upcalls through, despite any minimum */
 480         if (da->data_size < dp->door_data_min &&
 481             !(upcall && da->data_ptr == DOOR_UNREF_DATA))
 482                 return (ENOBUFS);
 483 
 484         if (da->data_size > dp->door_data_max)
 485                 return (ENOBUFS);
 486 
 487         if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
 488                 return (ENOTSUP);
 489 
 490         if (da->desc_num > dp->door_desc_max)
 491                 return (ENFILE);
 492 
 493         return (0);
 494 }
 495 
 496 /*
 497  * Door invocation.
 498  */
 499 int
 500 door_call(int did, void *args)
 501 {
 502         /* Locals */
 503         door_node_t     *dp;
 504         kthread_t       *server_thread;
 505         int             error = 0;
 506         klwp_t          *lwp;
 507         door_client_t   *ct;            /* curthread door_data */
 508         door_server_t   *st;            /* server thread door_data */
 509         door_desc_t     *start = NULL;
 510         uint_t          ncopied = 0;
 511         size_t          dsize;
 512         /* destructor for data returned by a kernel server */
 513         void            (*destfn)() = NULL;
 514         void            *destarg;
 515         model_t         datamodel;
 516         int             gotresults = 0;
 517         int             needcleanup = 0;
 518         int             cancel_pending;
 519 
 520         lwp = ttolwp(curthread);
 521         datamodel = lwp_getdatamodel(lwp);
 522 
 523         ct = door_my_client(1);
 524 
 525         /*
 526          * Get the arguments
 527          */
 528         if (args) {
 529                 if (datamodel == DATAMODEL_NATIVE) {
 530                         if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
 531                                 return (set_errno(EFAULT));
 532                 } else {
 533                         door_arg32_t    da32;
 534 
 535                         if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
 536                                 return (set_errno(EFAULT));
 537                         ct->d_args.data_ptr =
 538                             (char *)(uintptr_t)da32.data_ptr;
 539                         ct->d_args.data_size = da32.data_size;
 540                         ct->d_args.desc_ptr =
 541                             (door_desc_t *)(uintptr_t)da32.desc_ptr;
 542                         ct->d_args.desc_num = da32.desc_num;
 543                         ct->d_args.rbuf =
 544                             (char *)(uintptr_t)da32.rbuf;
 545                         ct->d_args.rsize = da32.rsize;
 546                 }
 547         } else {
 548                 /* No arguments, and no results allowed */
 549                 ct->d_noresults = 1;
 550                 ct->d_args.data_size = 0;
 551                 ct->d_args.desc_num = 0;
 552                 ct->d_args.rsize = 0;
 553         }
 554 
 555         if ((dp = door_lookup(did, NULL)) == NULL)
 556                 return (set_errno(EBADF));
 557 
 558         /*
 559          * We don't want to hold the door FD over the entire operation;
 560          * instead, we put a hold on the door vnode and release the FD
 561          * immediately
 562          */
 563         VN_HOLD(DTOV(dp));
 564         releasef(did);
 565 
 566         /*
 567          * This should be done in shuttle_resume(), just before going to
 568          * sleep, but we want to avoid overhead while holding door_knob.
 569          * prstop() is just a no-op if we don't really go to sleep.
 570          * We test not-kernel-address-space for the sake of clustering code.
 571          */
 572         if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
 573                 prstop(PR_REQUESTED, 0);
 574 
 575         mutex_enter(&door_knob);
 576         if (DOOR_INVALID(dp)) {
 577                 mutex_exit(&door_knob);
 578                 error = EBADF;
 579                 goto out;
 580         }
 581 
 582         /*
 583          * before we do anything, check that we are not overflowing the
 584          * required limits.
 585          */
 586         error = door_check_limits(dp, &ct->d_args, 0);
 587         if (error != 0) {
 588                 mutex_exit(&door_knob);
 589                 goto out;
 590         }
 591 
 592         /*
 593          * Check for in-kernel door server.
 594          */
 595         if (dp->door_target == &p0) {
 596                 caddr_t rbuf = ct->d_args.rbuf;
 597                 size_t rsize = ct->d_args.rsize;
 598 
 599                 dp->door_active++;
 600                 ct->d_kernel = 1;
 601                 ct->d_error = DOOR_WAIT;
 602                 mutex_exit(&door_knob);
 603                 /* translate file descriptors to vnodes */
 604                 if (ct->d_args.desc_num) {
 605                         error = door_translate_in();
 606                         if (error)
 607                                 goto out;
 608                 }
 609                 /*
 610                  * Call kernel door server.  Arguments are passed and
 611                  * returned as a door_arg pointer.  When called, data_ptr
 612                  * points to user data and desc_ptr points to a kernel list
 613                  * of door descriptors that have been converted to file
 614                  * structure pointers.  It's the server function's
 615                  * responsibility to copyin the data pointed to by data_ptr
 616                  * (this avoids extra copying in some cases).  On return,
 617                  * data_ptr points to a user buffer of data, and desc_ptr
 618                  * points to a kernel list of door descriptors representing
 619                  * files.  When a reference is passed to a kernel server,
 620                  * it is the server's responsibility to release the reference
 621                  * (by calling closef).  When the server includes a
 622                  * reference in its reply, it is released as part of the
 623                  * the call (the server must duplicate the reference if
 624                  * it wants to retain a copy).  The destfn, if set to
 625                  * non-NULL, is a destructor to be called when the returned
 626                  * kernel data (if any) is no longer needed (has all been
 627                  * translated and copied to user level).
 628                  */
 629                 (*(dp->door_pc))(dp->door_data, &ct->d_args,
 630                     &destfn, &destarg, &error);
 631                 mutex_enter(&door_knob);
 632                 /* not implemented yet */
 633                 if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
 634                         door_deliver_unref(dp);
 635                 mutex_exit(&door_knob);
 636                 if (error)
 637                         goto out;
 638 
 639                 /* translate vnodes to files */
 640                 if (ct->d_args.desc_num) {
 641                         error = door_translate_out();
 642                         if (error)
 643                                 goto out;
 644                 }
 645                 ct->d_buf = ct->d_args.rbuf;
 646                 ct->d_bufsize = ct->d_args.rsize;
 647                 if (rsize < (ct->d_args.data_size +
 648                     (ct->d_args.desc_num * sizeof (door_desc_t)))) {
 649                         /* handle overflow */
 650                         error = door_overflow(curthread, ct->d_args.data_ptr,
 651                             ct->d_args.data_size, ct->d_args.desc_ptr,
 652                             ct->d_args.desc_num);
 653                         if (error)
 654                                 goto out;
 655                         /* door_overflow sets d_args rbuf and rsize */
 656                 } else {
 657                         ct->d_args.rbuf = rbuf;
 658                         ct->d_args.rsize = rsize;
 659                 }
 660                 goto results;
 661         }
 662 
 663         /*
 664          * Get a server thread from the target domain
 665          */
 666         if ((server_thread = door_get_server(dp)) == NULL) {
 667                 if (DOOR_INVALID(dp))
 668                         error = EBADF;
 669                 else
 670                         error = EAGAIN;
 671                 mutex_exit(&door_knob);
 672                 goto out;
 673         }
 674 
 675         st = DOOR_SERVER(server_thread->t_door);
 676         if (ct->d_args.desc_num || ct->d_args.data_size) {
 677                 int is_private = (dp->door_flags & DOOR_PRIVATE);
 678                 /*
 679                  * Move data from client to server
 680                  */
 681                 DOOR_T_HOLD(st);
 682                 mutex_exit(&door_knob);
 683                 error = door_args(server_thread, is_private);
 684                 mutex_enter(&door_knob);
 685                 DOOR_T_RELEASE(st);
 686                 if (error) {
 687                         /*
 688                          * We're not going to resume this thread after all
 689                          */
 690                         door_release_server(dp, server_thread);
 691                         shuttle_sleep(server_thread);
 692                         mutex_exit(&door_knob);
 693                         goto out;
 694                 }
 695         }
 696 
 697         dp->door_active++;
 698         ct->d_error = DOOR_WAIT;
 699         ct->d_args_done = 0;
 700         st->d_caller = curthread;
 701         st->d_active = dp;
 702 
 703         shuttle_resume(server_thread, &door_knob);
 704 
 705         mutex_enter(&door_knob);
 706 shuttle_return:
 707         if ((error = ct->d_error) < 0) {  /* DOOR_WAIT or DOOR_EXIT */
 708                 /*
 709                  * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
 710                  */
 711                 mutex_exit(&door_knob);             /* May block in ISSIG */
 712                 cancel_pending = 0;
 713                 if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
 714                     MUSTRETURN(curproc, curthread) ||
 715                     (cancel_pending = schedctl_cancel_pending()) != 0) {
 716                         /* Signal, forkall, ... */
 717                         lwp->lwp_sysabort = 0;
 718                         if (cancel_pending)
 719                                 schedctl_cancel_eintr();
 720                         mutex_enter(&door_knob);
 721                         error = EINTR;
 722                         /*
 723                          * If the server has finished processing our call,
 724                          * or exited (calling door_slam()), then d_error
 725                          * will have changed.  If the server hasn't finished
 726                          * yet, d_error will still be DOOR_WAIT, and we
 727                          * let it know we are not interested in any
 728                          * results by sending a SIGCANCEL, unless the door
 729                          * is marked with DOOR_NO_CANCEL.
 730                          */
 731                         if (ct->d_error == DOOR_WAIT &&
 732                             st->d_caller == curthread) {
 733                                 proc_t  *p = ttoproc(server_thread);
 734 
 735                                 st->d_active = NULL;
 736                                 st->d_caller = NULL;
 737 
 738                                 if (!(dp->door_flags & DOOR_NO_CANCEL)) {
 739                                         DOOR_T_HOLD(st);
 740                                         mutex_exit(&door_knob);
 741 
 742                                         mutex_enter(&p->p_lock);
 743                                         sigtoproc(p, server_thread, SIGCANCEL);
 744                                         mutex_exit(&p->p_lock);
 745 
 746                                         mutex_enter(&door_knob);
 747                                         DOOR_T_RELEASE(st);
 748                                 }
 749                         }
 750                 } else {
 751                         /*
 752                          * Return from stop(), server exit...
 753                          *
 754                          * Note that the server could have done a
 755                          * door_return while the client was in stop state
 756                          * (ISSIG), in which case the error condition
 757                          * is updated by the server.
 758                          */
 759                         mutex_enter(&door_knob);
 760                         if (ct->d_error == DOOR_WAIT) {
 761                                 /* Still waiting for a reply */
 762                                 shuttle_swtch(&door_knob);
 763                                 mutex_enter(&door_knob);
 764                                 lwp->lwp_asleep = 0;
 765                                 goto    shuttle_return;
 766                         } else if (ct->d_error == DOOR_EXIT) {
 767                                 /* Server exit */
 768                                 error = EINTR;
 769                         } else {
 770                                 /* Server did a door_return during ISSIG */
 771                                 error = ct->d_error;
 772                         }
 773                 }
 774                 /*
 775                  * Can't exit if the server is currently copying
 776                  * results for me.
 777                  */
 778                 while (DOOR_T_HELD(ct))
 779                         cv_wait(&ct->d_cv, &door_knob);
 780 
 781                 /*
 782                  * If the server has not processed our message, free the
 783                  * descriptors.
 784                  */
 785                 if (!ct->d_args_done) {
 786                         needcleanup = 1;
 787                         ct->d_args_done = 1;
 788                 }
 789 
 790                 /*
 791                  * Find out if results were successfully copied.
 792                  */
 793                 if (ct->d_error == 0)
 794                         gotresults = 1;
 795         }
 796         ASSERT(ct->d_args_done);
 797         lwp->lwp_asleep = 0;         /* /proc */
 798         lwp->lwp_sysabort = 0;               /* /proc */
 799         if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
 800                 door_deliver_unref(dp);
 801         mutex_exit(&door_knob);
 802 
 803         if (needcleanup)
 804                 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
 805 
 806 results:
 807         /*
 808          * Move the results to userland (if any)
 809          */
 810 
 811         if (ct->d_noresults)
 812                 goto out;
 813 
 814         if (error) {
 815                 /*
 816                  * If server returned results successfully, then we've
 817                  * been interrupted and may need to clean up.
 818                  */
 819                 if (gotresults) {
 820                         ASSERT(error == EINTR);
 821                         door_fp_close(ct->d_fpp, ct->d_args.desc_num);
 822                 }
 823                 goto out;
 824         }
 825 
 826         /*
 827          * Copy back data if we haven't caused an overflow (already
 828          * handled) and we are using a 2 copy transfer, or we are
 829          * returning data from a kernel server.
 830          */
 831         if (ct->d_args.data_size) {
 832                 ct->d_args.data_ptr = ct->d_args.rbuf;
 833                 if (ct->d_kernel || (!ct->d_overflow &&
 834                     ct->d_args.data_size <= door_max_arg)) {
 835                         if (copyout_nowatch(ct->d_buf, ct->d_args.rbuf,
 836                             ct->d_args.data_size)) {
 837                                 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
 838                                 error = EFAULT;
 839                                 goto out;
 840                         }
 841                 }
 842         }
 843 
 844         /*
 845          * stuff returned doors into our proc, copyout the descriptors
 846          */
 847         if (ct->d_args.desc_num) {
 848                 struct file     **fpp;
 849                 door_desc_t     *didpp;
 850                 uint_t          n = ct->d_args.desc_num;
 851 
 852                 dsize = n * sizeof (door_desc_t);
 853                 start = didpp = kmem_alloc(dsize, KM_SLEEP);
 854                 fpp = ct->d_fpp;
 855 
 856                 while (n--) {
 857                         if (door_insert(*fpp, didpp) == -1) {
 858                                 /* Close remaining files */
 859                                 door_fp_close(fpp, n + 1);
 860                                 error = EMFILE;
 861                                 goto out;
 862                         }
 863                         fpp++; didpp++; ncopied++;
 864                 }
 865 
 866                 ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
 867                     roundup(ct->d_args.data_size, sizeof (door_desc_t)));
 868 
 869                 if (copyout_nowatch(start, ct->d_args.desc_ptr, dsize)) {
 870                         error = EFAULT;
 871                         goto out;
 872                 }
 873         }
 874 
 875         /*
 876          * Return the results
 877          */
 878         if (datamodel == DATAMODEL_NATIVE) {
 879                 if (copyout_nowatch(&ct->d_args, args,
 880                     sizeof (door_arg_t)) != 0)
 881                         error = EFAULT;
 882         } else {
 883                 door_arg32_t    da32;
 884 
 885                 da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr;
 886                 da32.data_size = ct->d_args.data_size;
 887                 da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr;
 888                 da32.desc_num = ct->d_args.desc_num;
 889                 da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf;
 890                 da32.rsize = ct->d_args.rsize;
 891                 if (copyout_nowatch(&da32, args, sizeof (door_arg32_t)) != 0) {
 892                         error = EFAULT;
 893                 }
 894         }
 895 
 896 out:
 897         ct->d_noresults = 0;
 898 
 899         /* clean up the overflow buffer if an error occurred */
 900         if (error != 0 && ct->d_overflow) {
 901                 (void) as_unmap(curproc->p_as, ct->d_args.rbuf,
 902                     ct->d_args.rsize);
 903         }
 904         ct->d_overflow = 0;
 905 
 906         /* call destructor */
 907         if (destfn) {
 908                 ASSERT(ct->d_kernel);
 909                 (*destfn)(dp->door_data, destarg);
 910                 ct->d_buf = NULL;
 911                 ct->d_bufsize = 0;
 912         }
 913 
 914         if (dp)
 915                 VN_RELE(DTOV(dp));
 916 
 917         if (ct->d_buf) {
 918                 ASSERT(!ct->d_kernel);
 919                 kmem_free(ct->d_buf, ct->d_bufsize);
 920                 ct->d_buf = NULL;
 921                 ct->d_bufsize = 0;
 922         }
 923         ct->d_kernel = 0;
 924 
 925         /* clean up the descriptor copyout buffer */
 926         if (start != NULL) {
 927                 if (error != 0)
 928                         door_fd_close(start, ncopied);
 929                 kmem_free(start, dsize);
 930         }
 931 
 932         if (ct->d_fpp) {
 933                 kmem_free(ct->d_fpp, ct->d_fpp_size);
 934                 ct->d_fpp = NULL;
 935                 ct->d_fpp_size = 0;
 936         }
 937 
 938         if (error)
 939                 return (set_errno(error));
 940 
 941         return (0);
 942 }
 943 
 944 static int
 945 door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val)
 946 {
 947         int error = 0;
 948 
 949         mutex_enter(&door_knob);
 950 
 951         if (DOOR_INVALID(dp)) {
 952                 mutex_exit(&door_knob);
 953                 return (EBADF);
 954         }
 955 
 956         /*
 957          * door_ki_setparam() can only affect kernel doors.
 958          * door_setparam() can only affect doors attached to the current
 959          * process.
 960          */
 961         if ((from_kernel && dp->door_target != &p0) ||
 962             (!from_kernel && dp->door_target != curproc)) {
 963                 mutex_exit(&door_knob);
 964                 return (EPERM);
 965         }
 966 
 967         switch (type) {
 968         case DOOR_PARAM_DESC_MAX:
 969                 if (val > INT_MAX)
 970                         error = ERANGE;
 971                 else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0)
 972                         error = ENOTSUP;
 973                 else
 974                         dp->door_desc_max = (uint_t)val;
 975                 break;
 976 
 977         case DOOR_PARAM_DATA_MIN:
 978                 if (val > dp->door_data_max)
 979                         error = EINVAL;
 980                 else
 981                         dp->door_data_min = val;
 982                 break;
 983 
 984         case DOOR_PARAM_DATA_MAX:
 985                 if (val < dp->door_data_min)
 986                         error = EINVAL;
 987                 else
 988                         dp->door_data_max = val;
 989                 break;
 990 
 991         default:
 992                 error = EINVAL;
 993                 break;
 994         }
 995 
 996         mutex_exit(&door_knob);
 997         return (error);
 998 }
 999 
1000 static int
1001 door_getparam_common(door_node_t *dp, int type, size_t *out)
1002 {
1003         int error = 0;
1004 
1005         mutex_enter(&door_knob);
1006         switch (type) {
1007         case DOOR_PARAM_DESC_MAX:
1008                 *out = (size_t)dp->door_desc_max;
1009                 break;
1010         case DOOR_PARAM_DATA_MIN:
1011                 *out = dp->door_data_min;
1012                 break;
1013         case DOOR_PARAM_DATA_MAX:
1014                 *out = dp->door_data_max;
1015                 break;
1016         default:
1017                 error = EINVAL;
1018                 break;
1019         }
1020         mutex_exit(&door_knob);
1021         return (error);
1022 }
1023 
1024 int
1025 door_setparam(int did, int type, size_t val)
1026 {
1027         door_node_t *dp;
1028         int error = 0;
1029 
1030         if ((dp = door_lookup(did, NULL)) == NULL)
1031                 return (set_errno(EBADF));
1032 
1033         error = door_setparam_common(dp, 0, type, val);
1034 
1035         releasef(did);
1036 
1037         if (error)
1038                 return (set_errno(error));
1039 
1040         return (0);
1041 }
1042 
1043 int
1044 door_getparam(int did, int type, size_t *out)
1045 {
1046         door_node_t *dp;
1047         size_t val = 0;
1048         int error = 0;
1049 
1050         if ((dp = door_lookup(did, NULL)) == NULL)
1051                 return (set_errno(EBADF));
1052 
1053         error = door_getparam_common(dp, type, &val);
1054 
1055         releasef(did);
1056 
1057         if (error)
1058                 return (set_errno(error));
1059 
1060         if (get_udatamodel() == DATAMODEL_NATIVE) {
1061                 if (copyout(&val, out, sizeof (val)))
1062                         return (set_errno(EFAULT));
1063 #ifdef _SYSCALL32_IMPL
1064         } else {
1065                 size32_t val32 = (size32_t)val;
1066 
1067                 if (val != val32)
1068                         return (set_errno(EOVERFLOW));
1069 
1070                 if (copyout(&val32, out, sizeof (val32)))
1071                         return (set_errno(EFAULT));
1072 #endif /* _SYSCALL32_IMPL */
1073         }
1074 
1075         return (0);
1076 }
1077 
1078 /*
1079  * A copyout() which proceeds from high addresses to low addresses.  This way,
1080  * stack guard pages are effective.
1081  *
1082  * Note that we use copyout_nowatch();  this is called while the client is
1083  * held.
1084  */
1085 static int
1086 door_stack_copyout(const void *kaddr, void *uaddr, size_t count)
1087 {
1088         const char *kbase = (const char *)kaddr;
1089         uintptr_t ubase = (uintptr_t)uaddr;
1090         size_t pgsize = PAGESIZE;
1091 
1092         if (count <= pgsize)
1093                 return (copyout_nowatch(kaddr, uaddr, count));
1094 
1095         while (count > 0) {
1096                 uintptr_t start, end, offset, amount;
1097 
1098                 end = ubase + count;
1099                 start = P2ALIGN(end - 1, pgsize);
1100                 if (P2ALIGN(ubase, pgsize) == start)
1101                         start = ubase;
1102 
1103                 offset = start - ubase;
1104                 amount = end - start;
1105 
1106                 ASSERT(amount > 0 && amount <= count && amount <= pgsize);
1107 
1108                 if (copyout_nowatch(kbase + offset, (void *)start, amount))
1109                         return (1);
1110                 count -= amount;
1111         }
1112         return (0);
1113 }
1114 
1115 /*
1116  * Writes the stack layout for door_return() into the door_server_t of the
1117  * server thread.
1118  */
1119 static int
1120 door_layout(kthread_t *tp, size_t data_size, uint_t ndesc, int info_needed)
1121 {
1122         door_server_t *st = DOOR_SERVER(tp->t_door);
1123         door_layout_t *out = &st->d_layout;
1124         uintptr_t base_sp = (uintptr_t)st->d_sp;
1125         size_t ssize = st->d_ssize;
1126         size_t descsz;
1127         uintptr_t descp, datap, infop, resultsp, finalsp;
1128         size_t align = STACK_ALIGN;
1129         size_t results_sz = sizeof (struct door_results);
1130         model_t datamodel = lwp_getdatamodel(ttolwp(tp));
1131 
1132         ASSERT(!st->d_layout_done);
1133 
1134 #ifndef _STACK_GROWS_DOWNWARD
1135 #error stack does not grow downward, door_layout() must change
1136 #endif
1137 
1138 #ifdef _SYSCALL32_IMPL
1139         if (datamodel != DATAMODEL_NATIVE) {
1140                 align = STACK_ALIGN32;
1141                 results_sz = sizeof (struct door_results32);
1142         }
1143 #endif
1144 
1145         descsz = ndesc * sizeof (door_desc_t);
1146 
1147         /*
1148          * To speed up the overflow checking, we do an initial check
1149          * that the passed in data size won't cause us to wrap past
1150          * base_sp.  Since door_max_desc limits descsz, we can
1151          * safely use it here.  65535 is an arbitrary 'bigger than
1152          * we need, small enough to not cause trouble' constant;
1153          * the only constraint is that it must be > than:
1154          *
1155          *      5 * STACK_ALIGN +
1156          *          sizeof (door_info_t) +
1157          *          sizeof (door_results_t) +
1158          *          (max adjustment from door_final_sp())
1159          *
1160          * After we compute the layout, we can safely do a "did we wrap
1161          * around" check, followed by a check against the recorded
1162          * stack size.
1163          */
1164         if (data_size >= SIZE_MAX - (size_t)65535UL - descsz)
1165                 return (E2BIG);         /* overflow */
1166 
1167         descp = P2ALIGN(base_sp - descsz, align);
1168         datap = P2ALIGN(descp - data_size, align);
1169 
1170         if (info_needed)
1171                 infop = P2ALIGN(datap - sizeof (door_info_t), align);
1172         else
1173                 infop = datap;
1174 
1175         resultsp = P2ALIGN(infop - results_sz, align);
1176         finalsp = door_final_sp(resultsp, align, datamodel);
1177 
1178         if (finalsp > base_sp)
1179                 return (E2BIG);         /* overflow */
1180 
1181         if (ssize != 0 && (base_sp - finalsp) > ssize)
1182                 return (E2BIG);         /* doesn't fit in stack */
1183 
1184         out->dl_descp = (ndesc != 0)? (caddr_t)descp : 0;
1185         out->dl_datap = (data_size != 0)? (caddr_t)datap : 0;
1186         out->dl_infop = info_needed? (caddr_t)infop : 0;
1187         out->dl_resultsp = (caddr_t)resultsp;
1188         out->dl_sp = (caddr_t)finalsp;
1189 
1190         st->d_layout_done = 1;
1191         return (0);
1192 }
1193 
1194 static int
1195 door_server_dispatch(door_client_t *ct, door_node_t *dp)
1196 {
1197         door_server_t *st = DOOR_SERVER(curthread->t_door);
1198         door_layout_t *layout = &st->d_layout;
1199         int error = 0;
1200 
1201         int is_private = (dp->door_flags & DOOR_PRIVATE);
1202 
1203         door_pool_t *pool = (is_private)? &dp->door_servers :
1204             &curproc->p_server_threads;
1205 
1206         int empty_pool = (pool->dp_threads == NULL);
1207 
1208         caddr_t infop = NULL;
1209         char *datap = NULL;
1210         size_t datasize = 0;
1211         size_t descsize;
1212 
1213         file_t **fpp = ct->d_fpp;
1214         door_desc_t *start = NULL;
1215         uint_t ndesc = 0;
1216         uint_t ncopied = 0;
1217 
1218         if (ct != NULL) {
1219                 datap = ct->d_args.data_ptr;
1220                 datasize = ct->d_args.data_size;
1221                 ndesc = ct->d_args.desc_num;
1222         }
1223 
1224         descsize = ndesc * sizeof (door_desc_t);
1225 
1226         /*
1227          * Reset datap to NULL if we aren't passing any data.  Be careful
1228          * to let unref notifications through, though.
1229          */
1230         if (datap == DOOR_UNREF_DATA) {
1231                 if (ct->d_upcall != NULL)
1232                         datasize = 0;
1233                 else
1234                         datap = NULL;
1235         } else if (datasize == 0) {
1236                 datap = NULL;
1237         }
1238 
1239         /*
1240          * Get the stack layout, if it hasn't already been done.
1241          */
1242         if (!st->d_layout_done) {
1243                 error = door_layout(curthread, datasize, ndesc,
1244                     (is_private && empty_pool));
1245                 if (error != 0)
1246                         goto fail;
1247         }
1248 
1249         /*
1250          * fill out the stack, starting from the top.  Layout was already
1251          * filled in by door_args() or door_translate_out().
1252          */
1253         if (layout->dl_descp != NULL) {
1254                 ASSERT(ndesc != 0);
1255                 start = kmem_alloc(descsize, KM_SLEEP);
1256 
1257                 while (ndesc > 0) {
1258                         if (door_insert(*fpp, &start[ncopied]) == -1) {
1259                                 error = EMFILE;
1260                                 goto fail;
1261                         }
1262                         ndesc--;
1263                         ncopied++;
1264                         fpp++;
1265                 }
1266                 if (door_stack_copyout(start, layout->dl_descp, descsize)) {
1267                         error = E2BIG;
1268                         goto fail;
1269                 }
1270         }
1271         fpp = NULL;                     /* finished processing */
1272 
1273         if (layout->dl_datap != NULL) {
1274                 ASSERT(datasize != 0);
1275                 datap = layout->dl_datap;
1276                 if (ct->d_upcall != NULL || datasize <= door_max_arg) {
1277                         if (door_stack_copyout(ct->d_buf, datap, datasize)) {
1278                                 error = E2BIG;
1279                                 goto fail;
1280                         }
1281                 }
1282         }
1283 
1284         if (is_private && empty_pool) {
1285                 door_info_t di;
1286 
1287                 infop = layout->dl_infop;
1288                 ASSERT(infop != NULL);
1289 
1290                 di.di_target = curproc->p_pid;
1291                 di.di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
1292                 di.di_data = (door_ptr_t)(uintptr_t)dp->door_data;
1293                 di.di_uniquifier = dp->door_index;
1294                 di.di_attributes = (dp->door_flags & DOOR_ATTR_MASK) |
1295                     DOOR_LOCAL;
1296 
1297                 if (door_stack_copyout(&di, infop, sizeof (di))) {
1298                         error = E2BIG;
1299                         goto fail;
1300                 }
1301         }
1302 
1303         if (get_udatamodel() == DATAMODEL_NATIVE) {
1304                 struct door_results dr;
1305 
1306                 dr.cookie = dp->door_data;
1307                 dr.data_ptr = datap;
1308                 dr.data_size = datasize;
1309                 dr.desc_ptr = (door_desc_t *)layout->dl_descp;
1310                 dr.desc_num = ncopied;
1311                 dr.pc = dp->door_pc;
1312                 dr.nservers = !empty_pool;
1313                 dr.door_info = (door_info_t *)infop;
1314 
1315                 if (door_stack_copyout(&dr, layout->dl_resultsp, sizeof (dr))) {
1316                         error = E2BIG;
1317                         goto fail;
1318                 }
1319 #ifdef _SYSCALL32_IMPL
1320         } else {
1321                 struct door_results32 dr32;
1322 
1323                 dr32.cookie = (caddr32_t)(uintptr_t)dp->door_data;
1324                 dr32.data_ptr = (caddr32_t)(uintptr_t)datap;
1325                 dr32.data_size = (size32_t)datasize;
1326                 dr32.desc_ptr = (caddr32_t)(uintptr_t)layout->dl_descp;
1327                 dr32.desc_num = ncopied;
1328                 dr32.pc = (caddr32_t)(uintptr_t)dp->door_pc;
1329                 dr32.nservers = !empty_pool;
1330                 dr32.door_info = (caddr32_t)(uintptr_t)infop;
1331 
1332                 if (door_stack_copyout(&dr32, layout->dl_resultsp,
1333                     sizeof (dr32))) {
1334                         error = E2BIG;
1335                         goto fail;
1336                 }
1337 #endif
1338         }
1339 
1340         error = door_finish_dispatch(layout->dl_sp);
1341 fail:
1342         if (start != NULL) {
1343                 if (error != 0)
1344                         door_fd_close(start, ncopied);
1345                 kmem_free(start, descsize);
1346         }
1347         if (fpp != NULL)
1348                 door_fp_close(fpp, ndesc);
1349 
1350         return (error);
1351 }
1352 
1353 /*
1354  * Return the results (if any) to the caller (if any) and wait for the
1355  * next invocation on a door.
1356  */
1357 int
1358 door_return(caddr_t data_ptr, size_t data_size,
1359     door_desc_t *desc_ptr, uint_t desc_num, caddr_t sp, size_t ssize)
1360 {
1361         kthread_t       *caller;
1362         klwp_t          *lwp;
1363         int             error = 0;
1364         door_node_t     *dp;
1365         door_server_t   *st;            /* curthread door_data */
1366         door_client_t   *ct;            /* caller door_data */
1367         int             cancel_pending;
1368 
1369         st = door_my_server(1);
1370 
1371         /*
1372          * If thread was bound to a door that no longer exists, return
1373          * an error.  This can happen if a thread is bound to a door
1374          * before the process calls forkall(); in the child, the door
1375          * doesn't exist and door_fork() sets the d_invbound flag.
1376          */
1377         if (st->d_invbound)
1378                 return (set_errno(EINVAL));
1379 
1380         st->d_sp = sp;                       /* Save base of stack. */
1381         st->d_ssize = ssize;         /* and its size */
1382 
1383         /*
1384          * This should be done in shuttle_resume(), just before going to
1385          * sleep, but we want to avoid overhead while holding door_knob.
1386          * prstop() is just a no-op if we don't really go to sleep.
1387          * We test not-kernel-address-space for the sake of clustering code.
1388          */
1389         lwp = ttolwp(curthread);
1390         if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
1391                 prstop(PR_REQUESTED, 0);
1392 
1393         /* Make sure the caller hasn't gone away */
1394         mutex_enter(&door_knob);
1395         if ((caller = st->d_caller) == NULL || caller->t_door == NULL) {
1396                 if (desc_num != 0) {
1397                         /* close any DOOR_RELEASE descriptors */
1398                         mutex_exit(&door_knob);
1399                         error = door_release_fds(desc_ptr, desc_num);
1400                         if (error)
1401                                 return (set_errno(error));
1402                         mutex_enter(&door_knob);
1403                 }
1404                 goto out;
1405         }
1406         ct = DOOR_CLIENT(caller->t_door);
1407 
1408         ct->d_args.data_size = data_size;
1409         ct->d_args.desc_num = desc_num;
1410         /*
1411          * Transfer results, if any, to the client
1412          */
1413         if (data_size != 0 || desc_num != 0) {
1414                 /*
1415                  * Prevent the client from exiting until we have finished
1416                  * moving results.
1417                  */
1418                 DOOR_T_HOLD(ct);
1419                 mutex_exit(&door_knob);
1420                 error = door_results(caller, data_ptr, data_size,
1421                     desc_ptr, desc_num);
1422                 mutex_enter(&door_knob);
1423                 DOOR_T_RELEASE(ct);
1424                 /*
1425                  * Pass EOVERFLOW errors back to the client
1426                  */
1427                 if (error && error != EOVERFLOW) {
1428                         mutex_exit(&door_knob);
1429                         return (set_errno(error));
1430                 }
1431         }
1432 out:
1433         /* Put ourselves on the available server thread list */
1434         door_release_server(st->d_pool, curthread);
1435 
1436         /*
1437          * Make sure the caller is still waiting to be resumed
1438          */
1439         if (caller) {
1440                 disp_lock_t *tlp;
1441 
1442                 thread_lock(caller);
1443                 ct->d_error = error;         /* Return any errors */
1444                 if (caller->t_state == TS_SLEEP &&
1445                     SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) {
1446                         cpu_t *cp = CPU;
1447 
1448                         tlp = caller->t_lockp;
1449                         /*
1450                          * Setting t_disp_queue prevents erroneous preemptions
1451                          * if this thread is still in execution on another
1452                          * processor
1453                          */
1454                         caller->t_disp_queue = cp->cpu_disp;
1455                         CL_ACTIVE(caller);
1456                         /*
1457                          * We are calling thread_onproc() instead of
1458                          * THREAD_ONPROC() because compiler can reorder
1459                          * the two stores of t_state and t_lockp in
1460                          * THREAD_ONPROC().
1461                          */
1462                         thread_onproc(caller, cp);
1463                         disp_lock_exit_high(tlp);
1464                         shuttle_resume(caller, &door_knob);
1465                 } else {
1466                         /* May have been setrun or in stop state */
1467                         thread_unlock(caller);
1468                         shuttle_swtch(&door_knob);
1469                 }
1470         } else {
1471                 shuttle_swtch(&door_knob);
1472         }
1473 
1474         /*
1475          * We've sprung to life. Determine if we are part of a door
1476          * invocation, or just interrupted
1477          */
1478         mutex_enter(&door_knob);
1479         if ((dp = st->d_active) != NULL) {
1480                 /*
1481                  * Normal door invocation. Return any error condition
1482                  * encountered while trying to pass args to the server
1483                  * thread.
1484                  */
1485                 lwp->lwp_asleep = 0;
1486                 /*
1487                  * Prevent the caller from leaving us while we
1488                  * are copying out the arguments from it's buffer.
1489                  */
1490                 ASSERT(st->d_caller != NULL);
1491                 ct = DOOR_CLIENT(st->d_caller->t_door);
1492 
1493                 DOOR_T_HOLD(ct);
1494                 mutex_exit(&door_knob);
1495                 error = door_server_dispatch(ct, dp);
1496                 mutex_enter(&door_knob);
1497                 DOOR_T_RELEASE(ct);
1498 
1499                 /* let the client know we have processed his message */
1500                 ct->d_args_done = 1;
1501 
1502                 if (error) {
1503                         caller = st->d_caller;
1504                         if (caller)
1505                                 ct = DOOR_CLIENT(caller->t_door);
1506                         else
1507                                 ct = NULL;
1508                         goto out;
1509                 }
1510                 mutex_exit(&door_knob);
1511                 return (0);
1512         } else {
1513                 /*
1514                  * We are not involved in a door_invocation.
1515                  * Check for /proc related activity...
1516                  */
1517                 st->d_caller = NULL;
1518                 door_server_exit(curproc, curthread);
1519                 mutex_exit(&door_knob);
1520                 cancel_pending = 0;
1521                 if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
1522                     MUSTRETURN(curproc, curthread) ||
1523                     (cancel_pending = schedctl_cancel_pending()) != 0) {
1524                         if (cancel_pending)
1525                                 schedctl_cancel_eintr();
1526                         lwp->lwp_asleep = 0;
1527                         lwp->lwp_sysabort = 0;
1528                         return (set_errno(EINTR));
1529                 }
1530                 /* Go back and wait for another request */
1531                 lwp->lwp_asleep = 0;
1532                 mutex_enter(&door_knob);
1533                 caller = NULL;
1534                 goto out;
1535         }
1536 }
1537 
1538 /*
1539  * Revoke any future invocations on this door
1540  */
1541 int
1542 door_revoke(int did)
1543 {
1544         door_node_t     *d;
1545         int             error;
1546 
1547         if ((d = door_lookup(did, NULL)) == NULL)
1548                 return (set_errno(EBADF));
1549 
1550         mutex_enter(&door_knob);
1551         if (d->door_target != curproc) {
1552                 mutex_exit(&door_knob);
1553                 releasef(did);
1554                 return (set_errno(EPERM));
1555         }
1556         d->door_flags |= DOOR_REVOKED;
1557         if (d->door_flags & DOOR_PRIVATE)
1558                 cv_broadcast(&d->door_servers.dp_cv);
1559         else
1560                 cv_broadcast(&curproc->p_server_threads.dp_cv);
1561         mutex_exit(&door_knob);
1562         releasef(did);
1563         /* Invalidate the descriptor */
1564         if ((error = closeandsetf(did, NULL)) != 0)
1565                 return (set_errno(error));
1566         return (0);
1567 }
1568 
1569 int
1570 door_info(int did, struct door_info *d_info)
1571 {
1572         door_node_t     *dp;
1573         door_info_t     di;
1574         door_server_t   *st;
1575         file_t          *fp = NULL;
1576 
1577         if (did == DOOR_QUERY) {
1578                 /* Get information on door current thread is bound to */
1579                 if ((st = door_my_server(0)) == NULL ||
1580                     (dp = st->d_pool) == NULL)
1581                         /* Thread isn't bound to a door */
1582                         return (set_errno(EBADF));
1583         } else if ((dp = door_lookup(did, &fp)) == NULL) {
1584                 /* Not a door */
1585                 return (set_errno(EBADF));
1586         }
1587 
1588         door_info_common(dp, &di, fp);
1589 
1590         if (did != DOOR_QUERY)
1591                 releasef(did);
1592 
1593         if (copyout(&di, d_info, sizeof (struct door_info)))
1594                 return (set_errno(EFAULT));
1595         return (0);
1596 }
1597 
1598 /*
1599  * Common code for getting information about a door either via the
1600  * door_info system call or the door_ki_info kernel call.
1601  */
1602 void
1603 door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp)
1604 {
1605         int unref_count;
1606 
1607         bzero(dip, sizeof (door_info_t));
1608 
1609         mutex_enter(&door_knob);
1610         if (dp->door_target == NULL)
1611                 dip->di_target = -1;
1612         else
1613                 dip->di_target = dp->door_target->p_pid;
1614 
1615         dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK;
1616         if (dp->door_target == curproc)
1617                 dip->di_attributes |= DOOR_LOCAL;
1618         dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
1619         dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data;
1620         dip->di_uniquifier = dp->door_index;
1621         /*
1622          * If this door is in the middle of having an unreferenced
1623          * notification delivered, don't count the VN_HOLD by
1624          * door_deliver_unref in determining if it is unreferenced.
1625          * This handles the case where door_info is called from the
1626          * thread delivering the unref notification.
1627          */
1628         if (dp->door_flags & DOOR_UNREF_ACTIVE)
1629                 unref_count = 2;
1630         else
1631                 unref_count = 1;
1632         mutex_exit(&door_knob);
1633 
1634         if (fp == NULL) {
1635                 /*
1636                  * If this thread is bound to the door, then we can just
1637                  * check the vnode; a ref count of 1 (or 2 if this is
1638                  * handling an unref notification) means that the hold
1639                  * from the door_bind is the only reference to the door
1640                  * (no file descriptor refers to it).
1641                  */
1642                 if (DTOV(dp)->v_count == unref_count)
1643                         dip->di_attributes |= DOOR_IS_UNREF;
1644         } else {
1645                 /*
1646                  * If we're working from a file descriptor or door handle
1647                  * we need to look at the file structure count.  We don't
1648                  * need to hold the vnode lock since this is just a snapshot.
1649                  */
1650                 mutex_enter(&fp->f_tlock);
1651                 if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count)
1652                         dip->di_attributes |= DOOR_IS_UNREF;
1653                 mutex_exit(&fp->f_tlock);
1654         }
1655 }
1656 
1657 /*
1658  * Return credentials of the door caller (if any) for this invocation
1659  */
1660 int
1661 door_ucred(struct ucred_s *uch)
1662 {
1663         kthread_t       *caller;
1664         door_server_t   *st;
1665         door_client_t   *ct;
1666         door_upcall_t   *dup;
1667         struct proc     *p;
1668         struct ucred_s  *res;
1669         int             err;
1670 
1671         mutex_enter(&door_knob);
1672         if ((st = door_my_server(0)) == NULL ||
1673             (caller = st->d_caller) == NULL) {
1674                 mutex_exit(&door_knob);
1675                 return (set_errno(EINVAL));
1676         }
1677 
1678         ASSERT(caller->t_door != NULL);
1679         ct = DOOR_CLIENT(caller->t_door);
1680 
1681         /* Prevent caller from exiting while we examine the cred */
1682         DOOR_T_HOLD(ct);
1683         mutex_exit(&door_knob);
1684 
1685         p = ttoproc(caller);
1686 
1687         /*
1688          * If the credentials are not specified by the client, get the one
1689          * associated with the calling process.
1690          */
1691         if ((dup = ct->d_upcall) != NULL)
1692                 res = cred2ucred(dup->du_cred, p0.p_pid, NULL, CRED());
1693         else
1694                 res = cred2ucred(caller->t_cred, p->p_pid, NULL, CRED());
1695 
1696         mutex_enter(&door_knob);
1697         DOOR_T_RELEASE(ct);
1698         mutex_exit(&door_knob);
1699 
1700         err = copyout(res, uch, res->uc_size);
1701 
1702         kmem_free(res, res->uc_size);
1703 
1704         if (err != 0)
1705                 return (set_errno(EFAULT));
1706 
1707         return (0);
1708 }
1709 
1710 /*
1711  * Bind the current lwp to the server thread pool associated with 'did'
1712  */
1713 int
1714 door_bind(int did)
1715 {
1716         door_node_t     *dp;
1717         door_server_t   *st;
1718 
1719         if ((dp = door_lookup(did, NULL)) == NULL) {
1720                 /* Not a door */
1721                 return (set_errno(EBADF));
1722         }
1723 
1724         /*
1725          * Can't bind to a non-private door, and can't bind to a door
1726          * served by another process.
1727          */
1728         if ((dp->door_flags & DOOR_PRIVATE) == 0 ||
1729             dp->door_target != curproc) {
1730                 releasef(did);
1731                 return (set_errno(EINVAL));
1732         }
1733 
1734         st = door_my_server(1);
1735         if (st->d_pool)
1736                 door_unbind_thread(st->d_pool);
1737         st->d_pool = dp;
1738         st->d_invbound = 0;
1739         door_bind_thread(dp);
1740         releasef(did);
1741 
1742         return (0);
1743 }
1744 
1745 /*
1746  * Unbind the current lwp from it's server thread pool
1747  */
1748 int
1749 door_unbind(void)
1750 {
1751         door_server_t *st;
1752 
1753         if ((st = door_my_server(0)) == NULL)
1754                 return (set_errno(EBADF));
1755 
1756         if (st->d_invbound) {
1757                 ASSERT(st->d_pool == NULL);
1758                 st->d_invbound = 0;
1759                 return (0);
1760         }
1761         if (st->d_pool == NULL)
1762                 return (set_errno(EBADF));
1763         door_unbind_thread(st->d_pool);
1764         st->d_pool = NULL;
1765         return (0);
1766 }
1767 
1768 /*
1769  * Create a descriptor for the associated file and fill in the
1770  * attributes associated with it.
1771  *
1772  * Return 0 for success, -1 otherwise;
1773  */
1774 int
1775 door_insert(struct file *fp, door_desc_t *dp)
1776 {
1777         struct vnode *vp;
1778         int     fd;
1779         door_attr_t attributes = DOOR_DESCRIPTOR;
1780 
1781         ASSERT(MUTEX_NOT_HELD(&door_knob));
1782         if ((fd = ufalloc(0)) == -1)
1783                 return (-1);
1784         setf(fd, fp);
1785         dp->d_data.d_desc.d_descriptor = fd;
1786 
1787         /* Add pid to the list associated with that descriptor. */
1788         if (fp->f_vnode != NULL)
1789                 (void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
1790                     (intptr_t)curproc->p_pidp->pid_id, FKIOCTL, kcred, NULL,
1791                     NULL);
1792 
1793         /* Fill in the attributes */
1794         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
1795                 vp = fp->f_vnode;
1796         if (vp && vp->v_type == VDOOR) {
1797                 if (VTOD(vp)->door_target == curproc)
1798                         attributes |= DOOR_LOCAL;
1799                 attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK;
1800                 dp->d_data.d_desc.d_id = VTOD(vp)->door_index;
1801         }
1802         dp->d_attributes = attributes;
1803         return (0);
1804 }
1805 
1806 /*
1807  * Return an available thread for this server.  A NULL return value indicates
1808  * that either:
1809  *      The door has been revoked, or
1810  *      a signal was received.
1811  * The two conditions can be differentiated using DOOR_INVALID(dp).
1812  */
1813 static kthread_t *
1814 door_get_server(door_node_t *dp)
1815 {
1816         kthread_t **ktp;
1817         kthread_t *server_t;
1818         door_pool_t *pool;
1819         door_server_t *st;
1820         int signalled;
1821 
1822         disp_lock_t *tlp;
1823         cpu_t *cp;
1824 
1825         ASSERT(MUTEX_HELD(&door_knob));
1826 
1827         if (dp->door_flags & DOOR_PRIVATE)
1828                 pool = &dp->door_servers;
1829         else
1830                 pool = &dp->door_target->p_server_threads;
1831 
1832         for (;;) {
1833                 /*
1834                  * We search the thread pool, looking for a server thread
1835                  * ready to take an invocation (i.e. one which is still
1836                  * sleeping on a shuttle object).  If none are available,
1837                  * we sleep on the pool's CV, and will be signaled when a
1838                  * thread is added to the pool.
1839                  *
1840                  * This relies on the fact that once a thread in the thread
1841                  * pool wakes up, it *must* remove and add itself to the pool
1842                  * before it can receive door calls.
1843                  */
1844                 if (DOOR_INVALID(dp))
1845                         return (NULL);  /* Target has become invalid */
1846 
1847                 for (ktp = &pool->dp_threads;
1848                     (server_t = *ktp) != NULL;
1849                     ktp = &st->d_servers) {
1850                         st = DOOR_SERVER(server_t->t_door);
1851 
1852                         thread_lock(server_t);
1853                         if (server_t->t_state == TS_SLEEP &&
1854                             SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE)
1855                                 break;
1856                         thread_unlock(server_t);
1857                 }
1858                 if (server_t != NULL)
1859                         break;          /* we've got a live one! */
1860 
1861                 if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
1862                     &signalled)) {
1863                         /*
1864                          * If we were signaled and the door is still
1865                          * valid, pass the signal on to another waiter.
1866                          */
1867                         if (signalled && !DOOR_INVALID(dp))
1868                                 cv_signal(&pool->dp_cv);
1869                         return (NULL);  /* Got a signal */
1870                 }
1871         }
1872 
1873         /*
1874          * We've got a thread_lock()ed thread which is still on the
1875          * shuttle.  Take it off the list of available server threads
1876          * and mark it as ONPROC.  We are committed to resuming this
1877          * thread now.
1878          */
1879         tlp = server_t->t_lockp;
1880         cp = CPU;
1881 
1882         *ktp = st->d_servers;
1883         st->d_servers = NULL;
1884         /*
1885          * Setting t_disp_queue prevents erroneous preemptions
1886          * if this thread is still in execution on another processor
1887          */
1888         server_t->t_disp_queue = cp->cpu_disp;
1889         CL_ACTIVE(server_t);
1890         /*
1891          * We are calling thread_onproc() instead of
1892          * THREAD_ONPROC() because compiler can reorder
1893          * the two stores of t_state and t_lockp in
1894          * THREAD_ONPROC().
1895          */
1896         thread_onproc(server_t, cp);
1897         disp_lock_exit(tlp);
1898         return (server_t);
1899 }
1900 
1901 /*
1902  * Put a server thread back in the pool.
1903  */
1904 static void
1905 door_release_server(door_node_t *dp, kthread_t *t)
1906 {
1907         door_server_t *st = DOOR_SERVER(t->t_door);
1908         door_pool_t *pool;
1909 
1910         ASSERT(MUTEX_HELD(&door_knob));
1911         st->d_active = NULL;
1912         st->d_caller = NULL;
1913         st->d_layout_done = 0;
1914         if (dp && (dp->door_flags & DOOR_PRIVATE)) {
1915                 ASSERT(dp->door_target == NULL ||
1916                     dp->door_target == ttoproc(t));
1917                 pool = &dp->door_servers;
1918         } else {
1919                 pool = &ttoproc(t)->p_server_threads;
1920         }
1921 
1922         st->d_servers = pool->dp_threads;
1923         pool->dp_threads = t;
1924 
1925         /* If someone is waiting for a server thread, wake him up */
1926         cv_signal(&pool->dp_cv);
1927 }
1928 
1929 /*
1930  * Remove a server thread from the pool if present.
1931  */
1932 static void
1933 door_server_exit(proc_t *p, kthread_t *t)
1934 {
1935         door_pool_t *pool;
1936         kthread_t **next;
1937         door_server_t *st = DOOR_SERVER(t->t_door);
1938 
1939         ASSERT(MUTEX_HELD(&door_knob));
1940         if (st->d_pool != NULL) {
1941                 ASSERT(st->d_pool->door_flags & DOOR_PRIVATE);
1942                 pool = &st->d_pool->door_servers;
1943         } else {
1944                 pool = &p->p_server_threads;
1945         }
1946 
1947         next = &pool->dp_threads;
1948         while (*next != NULL) {
1949                 if (*next == t) {
1950                         *next = DOOR_SERVER(t->t_door)->d_servers;
1951                         return;
1952                 }
1953                 next = &(DOOR_SERVER((*next)->t_door)->d_servers);
1954         }
1955 }
1956 
1957 /*
1958  * Lookup the door descriptor. Caller must call releasef when finished
1959  * with associated door.
1960  */
1961 static door_node_t *
1962 door_lookup(int did, file_t **fpp)
1963 {
1964         vnode_t *vp;
1965         file_t *fp;
1966 
1967         ASSERT(MUTEX_NOT_HELD(&door_knob));
1968         if ((fp = getf(did)) == NULL)
1969                 return (NULL);
1970         /*
1971          * Use the underlying vnode (we may be namefs mounted)
1972          */
1973         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
1974                 vp = fp->f_vnode;
1975 
1976         if (vp == NULL || vp->v_type != VDOOR) {
1977                 releasef(did);
1978                 return (NULL);
1979         }
1980 
1981         if (fpp)
1982                 *fpp = fp;
1983 
1984         return (VTOD(vp));
1985 }
1986 
1987 /*
1988  * The current thread is exiting, so clean up any pending
1989  * invocation details
1990  */
1991 void
1992 door_slam(void)
1993 {
1994         door_node_t *dp;
1995         door_data_t *dt;
1996         door_client_t *ct;
1997         door_server_t *st;
1998 
1999         /*
2000          * If we are an active door server, notify our
2001          * client that we are exiting and revoke our door.
2002          */
2003         if ((dt = door_my_data(0)) == NULL)
2004                 return;
2005         ct = DOOR_CLIENT(dt);
2006         st = DOOR_SERVER(dt);
2007 
2008         mutex_enter(&door_knob);
2009         for (;;) {
2010                 if (DOOR_T_HELD(ct))
2011                         cv_wait(&ct->d_cv, &door_knob);
2012                 else if (DOOR_T_HELD(st))
2013                         cv_wait(&st->d_cv, &door_knob);
2014                 else
2015                         break;                  /* neither flag is set */
2016         }
2017         curthread->t_door = NULL;
2018         if ((dp = st->d_active) != NULL) {
2019                 kthread_t *t = st->d_caller;
2020                 proc_t *p = curproc;
2021 
2022                 /* Revoke our door if the process is exiting */
2023                 if (dp->door_target == p && (p->p_flag & SEXITING)) {
2024                         door_list_delete(dp);
2025                         dp->door_target = NULL;
2026                         dp->door_flags |= DOOR_REVOKED;
2027                         if (dp->door_flags & DOOR_PRIVATE)
2028                                 cv_broadcast(&dp->door_servers.dp_cv);
2029                         else
2030                                 cv_broadcast(&p->p_server_threads.dp_cv);
2031                 }
2032 
2033                 if (t != NULL) {
2034                         /*
2035                          * Let the caller know we are gone
2036                          */
2037                         DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT;
2038                         thread_lock(t);
2039                         if (t->t_state == TS_SLEEP &&
2040                             SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE)
2041                                 setrun_locked(t);
2042                         thread_unlock(t);
2043                 }
2044         }
2045         mutex_exit(&door_knob);
2046         if (st->d_pool)
2047                 door_unbind_thread(st->d_pool);      /* Implicit door_unbind */
2048         kmem_free(dt, sizeof (door_data_t));
2049 }
2050 
2051 /*
2052  * Set DOOR_REVOKED for all doors of the current process. This is called
2053  * on exit before all lwp's are being terminated so that door calls will
2054  * return with an error.
2055  */
2056 void
2057 door_revoke_all()
2058 {
2059         door_node_t *dp;
2060         proc_t *p = ttoproc(curthread);
2061 
2062         mutex_enter(&door_knob);
2063         for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
2064                 ASSERT(dp->door_target == p);
2065                 dp->door_flags |= DOOR_REVOKED;
2066                 if (dp->door_flags & DOOR_PRIVATE)
2067                         cv_broadcast(&dp->door_servers.dp_cv);
2068         }
2069         cv_broadcast(&p->p_server_threads.dp_cv);
2070         mutex_exit(&door_knob);
2071 }
2072 
2073 /*
2074  * The process is exiting, and all doors it created need to be revoked.
2075  */
2076 void
2077 door_exit(void)
2078 {
2079         door_node_t *dp;
2080         proc_t *p = ttoproc(curthread);
2081 
2082         ASSERT(p->p_lwpcnt == 1);
2083         /*
2084          * Walk the list of active doors created by this process and
2085          * revoke them all.
2086          */
2087         mutex_enter(&door_knob);
2088         for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
2089                 dp->door_target = NULL;
2090                 dp->door_flags |= DOOR_REVOKED;
2091                 if (dp->door_flags & DOOR_PRIVATE)
2092                         cv_broadcast(&dp->door_servers.dp_cv);
2093         }
2094         cv_broadcast(&p->p_server_threads.dp_cv);
2095         /* Clear the list */
2096         p->p_door_list = NULL;
2097 
2098         /* Clean up the unref list */
2099         while ((dp = p->p_unref_list) != NULL) {
2100                 p->p_unref_list = dp->door_ulist;
2101                 dp->door_ulist = NULL;
2102                 mutex_exit(&door_knob);
2103                 VN_RELE(DTOV(dp));
2104                 mutex_enter(&door_knob);
2105         }
2106         mutex_exit(&door_knob);
2107 }
2108 
2109 
2110 /*
2111  * The process is executing forkall(), and we need to flag threads that
2112  * are bound to a door in the child.  This will make the child threads
2113  * return an error to door_return unless they call door_unbind first.
2114  */
2115 void
2116 door_fork(kthread_t *parent, kthread_t *child)
2117 {
2118         door_data_t *pt = parent->t_door;
2119         door_server_t *st = DOOR_SERVER(pt);
2120         door_data_t *dt;
2121 
2122         ASSERT(MUTEX_NOT_HELD(&door_knob));
2123         if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) {
2124                 /* parent thread is bound to a door */
2125                 dt = child->t_door =
2126                     kmem_zalloc(sizeof (door_data_t), KM_SLEEP);
2127                 DOOR_SERVER(dt)->d_invbound = 1;
2128         }
2129 }
2130 
2131 /*
2132  * Deliver queued unrefs to appropriate door server.
2133  */
2134 static int
2135 door_unref(void)
2136 {
2137         door_node_t     *dp;
2138         static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
2139         proc_t *p = ttoproc(curthread);
2140 
2141         /* make sure there's only one unref thread per process */
2142         mutex_enter(&door_knob);
2143         if (p->p_unref_thread) {
2144                 mutex_exit(&door_knob);
2145                 return (set_errno(EALREADY));
2146         }
2147         p->p_unref_thread = 1;
2148         mutex_exit(&door_knob);
2149 
2150         (void) door_my_data(1);                 /* create info, if necessary */
2151 
2152         for (;;) {
2153                 mutex_enter(&door_knob);
2154 
2155                 /* Grab a queued request */
2156                 while ((dp = p->p_unref_list) == NULL) {
2157                         if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) {
2158                                 /*
2159                                  * Interrupted.
2160                                  * Return so we can finish forkall() or exit().
2161                                  */
2162                                 p->p_unref_thread = 0;
2163                                 mutex_exit(&door_knob);
2164                                 return (set_errno(EINTR));
2165                         }
2166                 }
2167                 p->p_unref_list = dp->door_ulist;
2168                 dp->door_ulist = NULL;
2169                 dp->door_flags |= DOOR_UNREF_ACTIVE;
2170                 mutex_exit(&door_knob);
2171 
2172                 (void) door_upcall(DTOV(dp), &unref_args, NULL, SIZE_MAX, 0);
2173 
2174                 if (unref_args.rbuf != 0) {
2175                         kmem_free(unref_args.rbuf, unref_args.rsize);
2176                         unref_args.rbuf = NULL;
2177                         unref_args.rsize = 0;
2178                 }
2179 
2180                 mutex_enter(&door_knob);
2181                 ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
2182                 dp->door_flags &= ~DOOR_UNREF_ACTIVE;
2183                 mutex_exit(&door_knob);
2184                 VN_RELE(DTOV(dp));
2185         }
2186 }
2187 
2188 
2189 /*
2190  * Deliver queued unrefs to kernel door server.
2191  */
2192 /* ARGSUSED */
2193 static void
2194 door_unref_kernel(caddr_t arg)
2195 {
2196         door_node_t     *dp;
2197         static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
2198         proc_t *p = ttoproc(curthread);
2199         callb_cpr_t cprinfo;
2200 
2201         /* should only be one of these */
2202         mutex_enter(&door_knob);
2203         if (p->p_unref_thread) {
2204                 mutex_exit(&door_knob);
2205                 return;
2206         }
2207         p->p_unref_thread = 1;
2208         mutex_exit(&door_knob);
2209 
2210         (void) door_my_data(1);         /* make sure we have a door_data_t */
2211 
2212         CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref");
2213         for (;;) {
2214                 mutex_enter(&door_knob);
2215                 /* Grab a queued request */
2216                 while ((dp = p->p_unref_list) == NULL) {
2217                         CALLB_CPR_SAFE_BEGIN(&cprinfo);
2218                         cv_wait(&p->p_unref_cv, &door_knob);
2219                         CALLB_CPR_SAFE_END(&cprinfo, &door_knob);
2220                 }
2221                 p->p_unref_list = dp->door_ulist;
2222                 dp->door_ulist = NULL;
2223                 dp->door_flags |= DOOR_UNREF_ACTIVE;
2224                 mutex_exit(&door_knob);
2225 
2226                 (*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL);
2227 
2228                 mutex_enter(&door_knob);
2229                 ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
2230                 dp->door_flags &= ~DOOR_UNREF_ACTIVE;
2231                 mutex_exit(&door_knob);
2232                 VN_RELE(DTOV(dp));
2233         }
2234 }
2235 
2236 
2237 /*
2238  * Queue an unref invocation for processing for the current process
2239  * The door may or may not be revoked at this point.
2240  */
2241 void
2242 door_deliver_unref(door_node_t *d)
2243 {
2244         struct proc *server = d->door_target;
2245 
2246         ASSERT(MUTEX_HELD(&door_knob));
2247         ASSERT(d->door_active == 0);
2248 
2249         if (server == NULL)
2250                 return;
2251         /*
2252          * Create a lwp to deliver unref calls if one isn't already running.
2253          *
2254          * A separate thread is used to deliver unrefs since the current
2255          * thread may be holding resources (e.g. locks) in user land that
2256          * may be needed by the unref processing. This would cause a
2257          * deadlock.
2258          */
2259         if (d->door_flags & DOOR_UNREF_MULTI) {
2260                 /* multiple unrefs */
2261                 d->door_flags &= ~DOOR_DELAY;
2262         } else {
2263                 /* Only 1 unref per door */
2264                 d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY);
2265         }
2266         mutex_exit(&door_knob);
2267 
2268         /*
2269          * Need to bump the vnode count before putting the door on the
2270          * list so it doesn't get prematurely released by door_unref.
2271          */
2272         VN_HOLD(DTOV(d));
2273 
2274         mutex_enter(&door_knob);
2275         /* is this door already on the unref list? */
2276         if (d->door_flags & DOOR_UNREF_MULTI) {
2277                 door_node_t *dp;
2278                 for (dp = server->p_unref_list; dp != NULL;
2279                     dp = dp->door_ulist) {
2280                         if (d == dp) {
2281                                 /* already there, don't need to add another */
2282                                 mutex_exit(&door_knob);
2283                                 VN_RELE(DTOV(d));
2284                                 mutex_enter(&door_knob);
2285                                 return;
2286                         }
2287                 }
2288         }
2289         ASSERT(d->door_ulist == NULL);
2290         d->door_ulist = server->p_unref_list;
2291         server->p_unref_list = d;
2292         cv_broadcast(&server->p_unref_cv);
2293 }
2294 
2295 /*
2296  * The callers buffer isn't big enough for all of the data/fd's. Allocate
2297  * space in the callers address space for the results and copy the data
2298  * there.
2299  *
2300  * For EOVERFLOW, we must clean up the server's door descriptors.
2301  */
2302 static int
2303 door_overflow(
2304         kthread_t       *caller,
2305         caddr_t         data_ptr,       /* data location */
2306         size_t          data_size,      /* data size */
2307         door_desc_t     *desc_ptr,      /* descriptor location */
2308         uint_t          desc_num)       /* descriptor size */
2309 {
2310         proc_t *callerp = ttoproc(caller);
2311         struct as *as = callerp->p_as;
2312         door_client_t *ct = DOOR_CLIENT(caller->t_door);
2313         caddr_t addr;                   /* Resulting address in target */
2314         size_t  rlen;                   /* Rounded len */
2315         size_t  len;
2316         uint_t  i;
2317         size_t  ds = desc_num * sizeof (door_desc_t);
2318 
2319         ASSERT(MUTEX_NOT_HELD(&door_knob));
2320         ASSERT(DOOR_T_HELD(ct) || ct->d_kernel);
2321 
2322         /* Do initial overflow check */
2323         if (!ufcanalloc(callerp, desc_num))
2324                 return (EMFILE);
2325 
2326         /*
2327          * Allocate space for this stuff in the callers address space
2328          */
2329         rlen = roundup(data_size + ds, PAGESIZE);
2330         as_rangelock(as);
2331         map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0);
2332         if (addr == NULL ||
2333             as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) {
2334                 /* No virtual memory available, or anon mapping failed */
2335                 as_rangeunlock(as);
2336                 if (!ct->d_kernel && desc_num > 0) {
2337                         int error = door_release_fds(desc_ptr, desc_num);
2338                         if (error)
2339                                 return (error);
2340                 }
2341                 return (EOVERFLOW);
2342         }
2343         as_rangeunlock(as);
2344 
2345         if (ct->d_kernel)
2346                 goto out;
2347 
2348         if (data_size != 0) {
2349                 caddr_t src = data_ptr;
2350                 caddr_t saddr = addr;
2351 
2352                 /* Copy any data */
2353                 len = data_size;
2354                 while (len != 0) {
2355                         int     amount;
2356                         int     error;
2357 
2358                         amount = len > PAGESIZE ? PAGESIZE : len;
2359                         if ((error = door_copy(as, src, saddr, amount)) != 0) {
2360                                 (void) as_unmap(as, addr, rlen);
2361                                 return (error);
2362                         }
2363                         saddr += amount;
2364                         src += amount;
2365                         len -= amount;
2366                 }
2367         }
2368         /* Copy any fd's */
2369         if (desc_num != 0) {
2370                 door_desc_t     *didpp, *start;
2371                 struct file     **fpp;
2372                 int             fpp_size;
2373 
2374                 start = didpp = kmem_alloc(ds, KM_SLEEP);
2375                 if (copyin_nowatch(desc_ptr, didpp, ds)) {
2376                         kmem_free(start, ds);
2377                         (void) as_unmap(as, addr, rlen);
2378                         return (EFAULT);
2379                 }
2380 
2381                 fpp_size = desc_num * sizeof (struct file *);
2382                 if (fpp_size > ct->d_fpp_size) {
2383                         /* make more space */
2384                         if (ct->d_fpp_size)
2385                                 kmem_free(ct->d_fpp, ct->d_fpp_size);
2386                         ct->d_fpp_size = fpp_size;
2387                         ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2388                 }
2389                 fpp = ct->d_fpp;
2390 
2391                 for (i = 0; i < desc_num; i++) {
2392                         struct file *fp;
2393                         int fd = didpp->d_data.d_desc.d_descriptor;
2394 
2395                         if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2396                             (fp = getf(fd)) == NULL) {
2397                                 /* close translated references */
2398                                 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2399                                 /* close untranslated references */
2400                                 door_fd_rele(didpp, desc_num - i, 0);
2401                                 kmem_free(start, ds);
2402                                 (void) as_unmap(as, addr, rlen);
2403                                 return (EINVAL);
2404                         }
2405                         mutex_enter(&fp->f_tlock);
2406                         fp->f_count++;
2407                         mutex_exit(&fp->f_tlock);
2408 
2409                         *fpp = fp;
2410                         releasef(fd);
2411 
2412                         if (didpp->d_attributes & DOOR_RELEASE) {
2413                                 /* release passed reference */
2414                                 (void) closeandsetf(fd, NULL);
2415                         }
2416 
2417                         fpp++; didpp++;
2418                 }
2419                 kmem_free(start, ds);
2420         }
2421 
2422 out:
2423         ct->d_overflow = 1;
2424         ct->d_args.rbuf = addr;
2425         ct->d_args.rsize = rlen;
2426         return (0);
2427 }
2428 
2429 /*
2430  * Transfer arguments from the client to the server.
2431  */
2432 static int
2433 door_args(kthread_t *server, int is_private)
2434 {
2435         door_server_t *st = DOOR_SERVER(server->t_door);
2436         door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2437         uint_t  ndid;
2438         size_t  dsize;
2439         int     error;
2440 
2441         ASSERT(DOOR_T_HELD(st));
2442         ASSERT(MUTEX_NOT_HELD(&door_knob));
2443 
2444         ndid = ct->d_args.desc_num;
2445         if (ndid > door_max_desc)
2446                 return (E2BIG);
2447 
2448         /*
2449          * Get the stack layout, and fail now if it won't fit.
2450          */
2451         error = door_layout(server, ct->d_args.data_size, ndid, is_private);
2452         if (error != 0)
2453                 return (error);
2454 
2455         dsize = ndid * sizeof (door_desc_t);
2456         if (ct->d_args.data_size != 0) {
2457                 if (ct->d_args.data_size <= door_max_arg) {
2458                         /*
2459                          * Use a 2 copy method for small amounts of data
2460                          *
2461                          * Allocate a little more than we need for the
2462                          * args, in the hope that the results will fit
2463                          * without having to reallocate a buffer
2464                          */
2465                         ASSERT(ct->d_buf == NULL);
2466                         ct->d_bufsize = roundup(ct->d_args.data_size,
2467                             DOOR_ROUND);
2468                         ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2469                         if (copyin_nowatch(ct->d_args.data_ptr,
2470                             ct->d_buf, ct->d_args.data_size) != 0) {
2471                                 kmem_free(ct->d_buf, ct->d_bufsize);
2472                                 ct->d_buf = NULL;
2473                                 ct->d_bufsize = 0;
2474                                 return (EFAULT);
2475                         }
2476                 } else {
2477                         struct as       *as;
2478                         caddr_t         src;
2479                         caddr_t         dest;
2480                         size_t          len = ct->d_args.data_size;
2481                         uintptr_t       base;
2482 
2483                         /*
2484                          * Use a 1 copy method
2485                          */
2486                         as = ttoproc(server)->p_as;
2487                         src = ct->d_args.data_ptr;
2488 
2489                         dest = st->d_layout.dl_datap;
2490                         base = (uintptr_t)dest;
2491 
2492                         /*
2493                          * Copy data directly into server.  We proceed
2494                          * downward from the top of the stack, to mimic
2495                          * normal stack usage. This allows the guard page
2496                          * to stop us before we corrupt anything.
2497                          */
2498                         while (len != 0) {
2499                                 uintptr_t start;
2500                                 uintptr_t end;
2501                                 uintptr_t offset;
2502                                 size_t  amount;
2503 
2504                                 /*
2505                                  * Locate the next part to copy.
2506                                  */
2507                                 end = base + len;
2508                                 start = P2ALIGN(end - 1, PAGESIZE);
2509 
2510                                 /*
2511                                  * if we are on the final (first) page, fix
2512                                  * up the start position.
2513                                  */
2514                                 if (P2ALIGN(base, PAGESIZE) == start)
2515                                         start = base;
2516 
2517                                 offset = start - base;  /* the copy offset */
2518                                 amount = end - start;   /* # bytes to copy */
2519 
2520                                 ASSERT(amount > 0 && amount <= len &&
2521                                     amount <= PAGESIZE);
2522 
2523                                 error = door_copy(as, src + offset,
2524                                     dest + offset, amount);
2525                                 if (error != 0)
2526                                         return (error);
2527                                 len -= amount;
2528                         }
2529                 }
2530         }
2531         /*
2532          * Copyin the door args and translate them into files
2533          */
2534         if (ndid != 0) {
2535                 door_desc_t     *didpp;
2536                 door_desc_t     *start;
2537                 struct file     **fpp;
2538 
2539                 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2540 
2541                 if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
2542                         kmem_free(start, dsize);
2543                         return (EFAULT);
2544                 }
2545                 ct->d_fpp_size = ndid * sizeof (struct file *);
2546                 ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2547                 fpp = ct->d_fpp;
2548                 while (ndid--) {
2549                         struct file *fp;
2550                         int fd = didpp->d_data.d_desc.d_descriptor;
2551 
2552                         /* We only understand file descriptors as passed objs */
2553                         if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2554                             (fp = getf(fd)) == NULL) {
2555                                 /* close translated references */
2556                                 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2557                                 /* close untranslated references */
2558                                 door_fd_rele(didpp, ndid + 1, 0);
2559                                 kmem_free(start, dsize);
2560                                 kmem_free(ct->d_fpp, ct->d_fpp_size);
2561                                 ct->d_fpp = NULL;
2562                                 ct->d_fpp_size = 0;
2563                                 return (EINVAL);
2564                         }
2565                         /* Hold the fp */
2566                         mutex_enter(&fp->f_tlock);
2567                         fp->f_count++;
2568                         mutex_exit(&fp->f_tlock);
2569 
2570                         *fpp = fp;
2571                         releasef(fd);
2572 
2573                         if (didpp->d_attributes & DOOR_RELEASE) {
2574                                 /* release passed reference */
2575                                 (void) closeandsetf(fd, NULL);
2576                         }
2577 
2578                         fpp++; didpp++;
2579                 }
2580                 kmem_free(start, dsize);
2581         }
2582         return (0);
2583 }
2584 
2585 /*
2586  * Transfer arguments from a user client to a kernel server.  This copies in
2587  * descriptors and translates them into door handles.  It doesn't touch the
2588  * other data, letting the kernel server deal with that (to avoid needing
2589  * to copy the data twice).
2590  */
2591 static int
2592 door_translate_in(void)
2593 {
2594         door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2595         uint_t  ndid;
2596 
2597         ASSERT(MUTEX_NOT_HELD(&door_knob));
2598         ndid = ct->d_args.desc_num;
2599         if (ndid > door_max_desc)
2600                 return (E2BIG);
2601         /*
2602          * Copyin the door args and translate them into door handles.
2603          */
2604         if (ndid != 0) {
2605                 door_desc_t     *didpp;
2606                 door_desc_t     *start;
2607                 size_t          dsize = ndid * sizeof (door_desc_t);
2608                 struct file     *fp;
2609 
2610                 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2611 
2612                 if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
2613                         kmem_free(start, dsize);
2614                         return (EFAULT);
2615                 }
2616                 while (ndid--) {
2617                         vnode_t *vp;
2618                         int fd = didpp->d_data.d_desc.d_descriptor;
2619 
2620                         /*
2621                          * We only understand file descriptors as passed objs
2622                          */
2623                         if ((didpp->d_attributes & DOOR_DESCRIPTOR) &&
2624                             (fp = getf(fd)) != NULL) {
2625                                 didpp->d_data.d_handle = FTODH(fp);
2626                                 /* Hold the door */
2627                                 door_ki_hold(didpp->d_data.d_handle);
2628 
2629                                 releasef(fd);
2630 
2631                                 if (didpp->d_attributes & DOOR_RELEASE) {
2632                                         /* release passed reference */
2633                                         (void) closeandsetf(fd, NULL);
2634                                 }
2635 
2636                                 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
2637                                         vp = fp->f_vnode;
2638 
2639                                 /* Set attributes */
2640                                 didpp->d_attributes = DOOR_HANDLE |
2641                                     (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
2642                         } else {
2643                                 /* close translated references */
2644                                 door_fd_close(start, didpp - start);
2645                                 /* close untranslated references */
2646                                 door_fd_rele(didpp, ndid + 1, 0);
2647                                 kmem_free(start, dsize);
2648                                 return (EINVAL);
2649                         }
2650                         didpp++;
2651                 }
2652                 ct->d_args.desc_ptr = start;
2653         }
2654         return (0);
2655 }
2656 
2657 /*
2658  * Translate door arguments from kernel to user.  This copies the passed
2659  * door handles.  It doesn't touch other data.  It is used by door_upcall,
2660  * and for data returned by a door_call to a kernel server.
2661  */
2662 static int
2663 door_translate_out(void)
2664 {
2665         door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2666         uint_t  ndid;
2667 
2668         ASSERT(MUTEX_NOT_HELD(&door_knob));
2669         ndid = ct->d_args.desc_num;
2670         if (ndid > door_max_desc) {
2671                 door_fd_rele(ct->d_args.desc_ptr, ndid, 1);
2672                 return (E2BIG);
2673         }
2674         /*
2675          * Translate the door args into files
2676          */
2677         if (ndid != 0) {
2678                 door_desc_t     *didpp = ct->d_args.desc_ptr;
2679                 struct file     **fpp;
2680 
2681                 ct->d_fpp_size = ndid * sizeof (struct file *);
2682                 fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2683                 while (ndid--) {
2684                         struct file *fp = NULL;
2685                         int fd = -1;
2686 
2687                         /*
2688                          * We understand file descriptors and door
2689                          * handles as passed objs.
2690                          */
2691                         if (didpp->d_attributes & DOOR_DESCRIPTOR) {
2692                                 fd = didpp->d_data.d_desc.d_descriptor;
2693                                 fp = getf(fd);
2694                         } else if (didpp->d_attributes & DOOR_HANDLE)
2695                                 fp = DHTOF(didpp->d_data.d_handle);
2696                         if (fp != NULL) {
2697                                 /* Hold the fp */
2698                                 mutex_enter(&fp->f_tlock);
2699                                 fp->f_count++;
2700                                 mutex_exit(&fp->f_tlock);
2701 
2702                                 *fpp = fp;
2703                                 if (didpp->d_attributes & DOOR_DESCRIPTOR)
2704                                         releasef(fd);
2705                                 if (didpp->d_attributes & DOOR_RELEASE) {
2706                                         /* release passed reference */
2707                                         if (fd >= 0)
2708                                                 (void) closeandsetf(fd, NULL);
2709                                         else
2710                                                 (void) closef(fp);
2711                                 }
2712                         } else {
2713                                 /* close translated references */
2714                                 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2715                                 /* close untranslated references */
2716                                 door_fd_rele(didpp, ndid + 1, 1);
2717                                 kmem_free(ct->d_fpp, ct->d_fpp_size);
2718                                 ct->d_fpp = NULL;
2719                                 ct->d_fpp_size = 0;
2720                                 return (EINVAL);
2721                         }
2722                         fpp++; didpp++;
2723                 }
2724         }
2725         return (0);
2726 }
2727 
2728 /*
2729  * Move the results from the server to the client
2730  */
2731 static int
2732 door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
2733     door_desc_t *desc_ptr, uint_t desc_num)
2734 {
2735         door_client_t   *ct = DOOR_CLIENT(caller->t_door);
2736         door_upcall_t   *dup = ct->d_upcall;
2737         size_t          dsize;
2738         size_t          rlen;
2739         size_t          result_size;
2740 
2741         ASSERT(DOOR_T_HELD(ct));
2742         ASSERT(MUTEX_NOT_HELD(&door_knob));
2743 
2744         if (ct->d_noresults)
2745                 return (E2BIG);         /* No results expected */
2746 
2747         if (desc_num > door_max_desc)
2748                 return (E2BIG);         /* Too many descriptors */
2749 
2750         dsize = desc_num * sizeof (door_desc_t);
2751         /*
2752          * Check if the results are bigger than the clients buffer
2753          */
2754         if (dsize)
2755                 rlen = roundup(data_size, sizeof (door_desc_t));
2756         else
2757                 rlen = data_size;
2758         if ((result_size = rlen + dsize) == 0)
2759                 return (0);
2760 
2761         if (dup != NULL) {
2762                 if (desc_num > dup->du_max_descs)
2763                         return (EMFILE);
2764 
2765                 if (data_size > dup->du_max_data)
2766                         return (E2BIG);
2767 
2768                 /*
2769                  * Handle upcalls
2770                  */
2771                 if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) {
2772                         /*
2773                          * If there's no return buffer or the buffer is too
2774                          * small, allocate a new one.  The old buffer (if it
2775                          * exists) will be freed by the upcall client.
2776                          */
2777                         if (result_size > door_max_upcall_reply)
2778                                 return (E2BIG);
2779                         ct->d_args.rsize = result_size;
2780                         ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP);
2781                 }
2782                 ct->d_args.data_ptr = ct->d_args.rbuf;
2783                 if (data_size != 0 &&
2784                     copyin_nowatch(data_ptr, ct->d_args.data_ptr,
2785                     data_size) != 0)
2786                         return (EFAULT);
2787         } else if (result_size > ct->d_args.rsize) {
2788                 return (door_overflow(caller, data_ptr, data_size,
2789                     desc_ptr, desc_num));
2790         } else if (data_size != 0) {
2791                 if (data_size <= door_max_arg) {
2792                         /*
2793                          * Use a 2 copy method for small amounts of data
2794                          */
2795                         if (ct->d_buf == NULL) {
2796                                 ct->d_bufsize = data_size;
2797                                 ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2798                         } else if (ct->d_bufsize < data_size) {
2799                                 kmem_free(ct->d_buf, ct->d_bufsize);
2800                                 ct->d_bufsize = data_size;
2801                                 ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2802                         }
2803                         if (copyin_nowatch(data_ptr, ct->d_buf, data_size) != 0)
2804                                 return (EFAULT);
2805                 } else {
2806                         struct as *as = ttoproc(caller)->p_as;
2807                         caddr_t dest = ct->d_args.rbuf;
2808                         caddr_t src = data_ptr;
2809                         size_t  len = data_size;
2810 
2811                         /* Copy data directly into client */
2812                         while (len != 0) {
2813                                 uint_t  amount;
2814                                 uint_t  max;
2815                                 uint_t  off;
2816                                 int     error;
2817 
2818                                 off = (uintptr_t)dest & PAGEOFFSET;
2819                                 if (off)
2820                                         max = PAGESIZE - off;
2821                                 else
2822                                         max = PAGESIZE;
2823                                 amount = len > max ? max : len;
2824                                 error = door_copy(as, src, dest, amount);
2825                                 if (error != 0)
2826                                         return (error);
2827                                 dest += amount;
2828                                 src += amount;
2829                                 len -= amount;
2830                         }
2831                 }
2832         }
2833 
2834         /*
2835          * Copyin the returned door ids and translate them into door_node_t
2836          */
2837         if (desc_num != 0) {
2838                 door_desc_t *start;
2839                 door_desc_t *didpp;
2840                 struct file **fpp;
2841                 size_t  fpp_size;
2842                 uint_t  i;
2843 
2844                 /* First, check if we would overflow client */
2845                 if (!ufcanalloc(ttoproc(caller), desc_num))
2846                         return (EMFILE);
2847 
2848                 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2849                 if (copyin_nowatch(desc_ptr, didpp, dsize)) {
2850                         kmem_free(start, dsize);
2851                         return (EFAULT);
2852                 }
2853                 fpp_size = desc_num * sizeof (struct file *);
2854                 if (fpp_size > ct->d_fpp_size) {
2855                         /* make more space */
2856                         if (ct->d_fpp_size)
2857                                 kmem_free(ct->d_fpp, ct->d_fpp_size);
2858                         ct->d_fpp_size = fpp_size;
2859                         ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP);
2860                 }
2861                 fpp = ct->d_fpp;
2862 
2863                 for (i = 0; i < desc_num; i++) {
2864                         struct file *fp;
2865                         int fd = didpp->d_data.d_desc.d_descriptor;
2866 
2867                         /* Only understand file descriptor results */
2868                         if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2869                             (fp = getf(fd)) == NULL) {
2870                                 /* close translated references */
2871                                 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2872                                 /* close untranslated references */
2873                                 door_fd_rele(didpp, desc_num - i, 0);
2874                                 kmem_free(start, dsize);
2875                                 return (EINVAL);
2876                         }
2877 
2878                         mutex_enter(&fp->f_tlock);
2879                         fp->f_count++;
2880                         mutex_exit(&fp->f_tlock);
2881 
2882                         *fpp = fp;
2883                         releasef(fd);
2884 
2885                         if (didpp->d_attributes & DOOR_RELEASE) {
2886                                 /* release passed reference */
2887                                 (void) closeandsetf(fd, NULL);
2888                         }
2889 
2890                         fpp++; didpp++;
2891                 }
2892                 kmem_free(start, dsize);
2893         }
2894         return (0);
2895 }
2896 
2897 /*
2898  * Close all the descriptors.
2899  */
2900 static void
2901 door_fd_close(door_desc_t *d, uint_t n)
2902 {
2903         uint_t  i;
2904 
2905         ASSERT(MUTEX_NOT_HELD(&door_knob));
2906         for (i = 0; i < n; i++) {
2907                 if (d->d_attributes & DOOR_DESCRIPTOR) {
2908                         (void) closeandsetf(
2909                             d->d_data.d_desc.d_descriptor, NULL);
2910                 } else if (d->d_attributes & DOOR_HANDLE) {
2911                         door_ki_rele(d->d_data.d_handle);
2912                 }
2913                 d++;
2914         }
2915 }
2916 
2917 /*
2918  * Close descriptors that have the DOOR_RELEASE attribute set.
2919  */
2920 void
2921 door_fd_rele(door_desc_t *d, uint_t n, int from_kernel)
2922 {
2923         uint_t  i;
2924 
2925         ASSERT(MUTEX_NOT_HELD(&door_knob));
2926         for (i = 0; i < n; i++) {
2927                 if (d->d_attributes & DOOR_RELEASE) {
2928                         if (d->d_attributes & DOOR_DESCRIPTOR) {
2929                                 (void) closeandsetf(
2930                                     d->d_data.d_desc.d_descriptor, NULL);
2931                         } else if (from_kernel &&
2932                             (d->d_attributes & DOOR_HANDLE)) {
2933                                 door_ki_rele(d->d_data.d_handle);
2934                         }
2935                 }
2936                 d++;
2937         }
2938 }
2939 
2940 /*
2941  * Copy descriptors into the kernel so we can release any marked
2942  * DOOR_RELEASE.
2943  */
2944 int
2945 door_release_fds(door_desc_t *desc_ptr, uint_t ndesc)
2946 {
2947         size_t dsize;
2948         door_desc_t *didpp;
2949         uint_t desc_num;
2950 
2951         ASSERT(MUTEX_NOT_HELD(&door_knob));
2952         ASSERT(ndesc != 0);
2953 
2954         desc_num = MIN(ndesc, door_max_desc);
2955 
2956         dsize = desc_num * sizeof (door_desc_t);
2957         didpp = kmem_alloc(dsize, KM_SLEEP);
2958 
2959         while (ndesc > 0) {
2960                 uint_t count = MIN(ndesc, desc_num);
2961 
2962                 if (copyin_nowatch(desc_ptr, didpp,
2963                     count * sizeof (door_desc_t))) {
2964                         kmem_free(didpp, dsize);
2965                         return (EFAULT);
2966                 }
2967                 door_fd_rele(didpp, count, 0);
2968 
2969                 ndesc -= count;
2970                 desc_ptr += count;
2971         }
2972         kmem_free(didpp, dsize);
2973         return (0);
2974 }
2975 
2976 /*
2977  * Decrement ref count on all the files passed
2978  */
2979 static void
2980 door_fp_close(struct file **fp, uint_t n)
2981 {
2982         uint_t  i;
2983 
2984         ASSERT(MUTEX_NOT_HELD(&door_knob));
2985 
2986         for (i = 0; i < n; i++)
2987                 (void) closef(fp[i]);
2988 }
2989 
2990 /*
2991  * Copy data from 'src' in current address space to 'dest' in 'as' for 'len'
2992  * bytes.
2993  *
2994  * Performs this using 1 mapin and 1 copy operation.
2995  *
2996  * We really should do more than 1 page at a time to improve
2997  * performance, but for now this is treated as an anomalous condition.
2998  */
2999 static int
3000 door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len)
3001 {
3002         caddr_t kaddr;
3003         caddr_t rdest;
3004         uint_t  off;
3005         page_t  **pplist;
3006         page_t  *pp = NULL;
3007         int     error = 0;
3008 
3009         ASSERT(len <= PAGESIZE);
3010         off = (uintptr_t)dest & PAGEOFFSET; /* offset within the page */
3011         rdest = (caddr_t)((uintptr_t)dest &
3012             (uintptr_t)PAGEMASK);       /* Page boundary */
3013         ASSERT(off + len <= PAGESIZE);
3014 
3015         /*
3016          * Lock down destination page.
3017          */
3018         if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE))
3019                 return (E2BIG);
3020         /*
3021          * Check if we have a shadow page list from as_pagelock. If not,
3022          * we took the slow path and have to find our page struct the hard
3023          * way.
3024          */
3025         if (pplist == NULL) {
3026                 pfn_t   pfnum;
3027 
3028                 /* MMU mapping is already locked down */
3029                 AS_LOCK_ENTER(as, RW_READER);
3030                 pfnum = hat_getpfnum(as->a_hat, rdest);
3031                 AS_LOCK_EXIT(as);
3032 
3033                 /*
3034                  * TODO: The pfn step should not be necessary - need
3035                  * a hat_getpp() function.
3036                  */
3037                 if (pf_is_memory(pfnum)) {
3038                         pp = page_numtopp_nolock(pfnum);
3039                         ASSERT(pp == NULL || PAGE_LOCKED(pp));
3040                 } else
3041                         pp = NULL;
3042                 if (pp == NULL) {
3043                         as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
3044                         return (E2BIG);
3045                 }
3046         } else {
3047                 pp = *pplist;
3048         }
3049         /*
3050          * Map destination page into kernel address
3051          */
3052         if (kpm_enable)
3053                 kaddr = (caddr_t)hat_kpm_mapin(pp, (struct kpme *)NULL);
3054         else
3055                 kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE,
3056                     (caddr_t)-1);
3057 
3058         /*
3059          * Copy from src to dest
3060          */
3061         if (copyin_nowatch(src, kaddr + off, len) != 0)
3062                 error = EFAULT;
3063         /*
3064          * Unmap destination page from kernel
3065          */
3066         if (kpm_enable)
3067                 hat_kpm_mapout(pp, (struct kpme *)NULL, kaddr);
3068         else
3069                 ppmapout(kaddr);
3070         /*
3071          * Unlock destination page
3072          */
3073         as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
3074         return (error);
3075 }
3076 
3077 /*
3078  * General kernel upcall using doors
3079  *      Returns 0 on success, errno for failures.
3080  *      Caller must have a hold on the door based vnode, and on any
3081  *      references passed in desc_ptr.  The references are released
3082  *      in the event of an error, and passed without duplication
3083  *      otherwise.  Note that param->rbuf must be 64-bit aligned in
3084  *      a 64-bit kernel, since it may be used to store door descriptors
3085  *      if they are returned by the server.  The caller is responsible
3086  *      for holding a reference to the cred passed in.
3087  */
3088 int
3089 door_upcall(vnode_t *vp, door_arg_t *param, struct cred *cred,
3090     size_t max_data, uint_t max_descs)
3091 {
3092         /* Locals */
3093         door_upcall_t   *dup;
3094         door_node_t     *dp;
3095         kthread_t       *server_thread;
3096         int             error = 0;
3097         klwp_t          *lwp;
3098         door_client_t   *ct;            /* curthread door_data */
3099         door_server_t   *st;            /* server thread door_data */
3100         int             gotresults = 0;
3101         int             cancel_pending;
3102 
3103         if (vp->v_type != VDOOR) {
3104                 if (param->desc_num)
3105                         door_fd_rele(param->desc_ptr, param->desc_num, 1);
3106                 return (EINVAL);
3107         }
3108 
3109         lwp = ttolwp(curthread);
3110         ct = door_my_client(1);
3111         dp = VTOD(vp);  /* Convert to a door_node_t */
3112 
3113         dup = kmem_zalloc(sizeof (*dup), KM_SLEEP);
3114         dup->du_cred = (cred != NULL) ? cred : curthread->t_cred;
3115         dup->du_max_data = max_data;
3116         dup->du_max_descs = max_descs;
3117 
3118         /*
3119          * This should be done in shuttle_resume(), just before going to
3120          * sleep, but we want to avoid overhead while holding door_knob.
3121          * prstop() is just a no-op if we don't really go to sleep.
3122          * We test not-kernel-address-space for the sake of clustering code.
3123          */
3124         if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
3125                 prstop(PR_REQUESTED, 0);
3126 
3127         mutex_enter(&door_knob);
3128         if (DOOR_INVALID(dp)) {
3129                 mutex_exit(&door_knob);
3130                 if (param->desc_num)
3131                         door_fd_rele(param->desc_ptr, param->desc_num, 1);
3132                 error = EBADF;
3133                 goto out;
3134         }
3135 
3136         if (dp->door_target == &p0) {
3137                 /* Can't do an upcall to a kernel server */
3138                 mutex_exit(&door_knob);
3139                 if (param->desc_num)
3140                         door_fd_rele(param->desc_ptr, param->desc_num, 1);
3141                 error = EINVAL;
3142                 goto out;
3143         }
3144 
3145         error = door_check_limits(dp, param, 1);
3146         if (error != 0) {
3147                 mutex_exit(&door_knob);
3148                 if (param->desc_num)
3149                         door_fd_rele(param->desc_ptr, param->desc_num, 1);
3150                 goto out;
3151         }
3152 
3153         /*
3154          * Get a server thread from the target domain
3155          */
3156         if ((server_thread = door_get_server(dp)) == NULL) {
3157                 if (DOOR_INVALID(dp))
3158                         error = EBADF;
3159                 else
3160                         error = EAGAIN;
3161                 mutex_exit(&door_knob);
3162                 if (param->desc_num)
3163                         door_fd_rele(param->desc_ptr, param->desc_num, 1);
3164                 goto out;
3165         }
3166 
3167         st = DOOR_SERVER(server_thread->t_door);
3168         ct->d_buf = param->data_ptr;
3169         ct->d_bufsize = param->data_size;
3170         ct->d_args = *param; /* structure assignment */
3171 
3172         if (ct->d_args.desc_num) {
3173                 /*
3174                  * Move data from client to server
3175                  */
3176                 DOOR_T_HOLD(st);
3177                 mutex_exit(&door_knob);
3178                 error = door_translate_out();
3179                 mutex_enter(&door_knob);
3180                 DOOR_T_RELEASE(st);
3181                 if (error) {
3182                         /*
3183                          * We're not going to resume this thread after all
3184                          */
3185                         door_release_server(dp, server_thread);
3186                         shuttle_sleep(server_thread);
3187                         mutex_exit(&door_knob);
3188                         goto out;
3189                 }
3190         }
3191 
3192         ct->d_upcall = dup;
3193         if (param->rsize == 0)
3194                 ct->d_noresults = 1;
3195         else
3196                 ct->d_noresults = 0;
3197 
3198         dp->door_active++;
3199 
3200         ct->d_error = DOOR_WAIT;
3201         st->d_caller = curthread;
3202         st->d_active = dp;
3203 
3204         shuttle_resume(server_thread, &door_knob);
3205 
3206         mutex_enter(&door_knob);
3207 shuttle_return:
3208         if ((error = ct->d_error) < 0) {  /* DOOR_WAIT or DOOR_EXIT */
3209                 /*
3210                  * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
3211                  */
3212                 mutex_exit(&door_knob);             /* May block in ISSIG */
3213                 cancel_pending = 0;
3214                 if (lwp && (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
3215                     MUSTRETURN(curproc, curthread) ||
3216                     (cancel_pending = schedctl_cancel_pending()) != 0)) {
3217                         /* Signal, forkall, ... */
3218                         if (cancel_pending)
3219                                 schedctl_cancel_eintr();
3220                         lwp->lwp_sysabort = 0;
3221                         mutex_enter(&door_knob);
3222                         error = EINTR;
3223                         /*
3224                          * If the server has finished processing our call,
3225                          * or exited (calling door_slam()), then d_error
3226                          * will have changed.  If the server hasn't finished
3227                          * yet, d_error will still be DOOR_WAIT, and we
3228                          * let it know we are not interested in any
3229                          * results by sending a SIGCANCEL, unless the door
3230                          * is marked with DOOR_NO_CANCEL.
3231                          */
3232                         if (ct->d_error == DOOR_WAIT &&
3233                             st->d_caller == curthread) {
3234                                 proc_t  *p = ttoproc(server_thread);
3235 
3236                                 st->d_active = NULL;
3237                                 st->d_caller = NULL;
3238                                 if (!(dp->door_flags & DOOR_NO_CANCEL)) {
3239                                         DOOR_T_HOLD(st);
3240                                         mutex_exit(&door_knob);
3241 
3242                                         mutex_enter(&p->p_lock);
3243                                         sigtoproc(p, server_thread, SIGCANCEL);
3244                                         mutex_exit(&p->p_lock);
3245 
3246                                         mutex_enter(&door_knob);
3247                                         DOOR_T_RELEASE(st);
3248                                 }
3249                         }
3250                 } else {
3251                         /*
3252                          * Return from stop(), server exit...
3253                          *
3254                          * Note that the server could have done a
3255                          * door_return while the client was in stop state
3256                          * (ISSIG), in which case the error condition
3257                          * is updated by the server.
3258                          */
3259                         mutex_enter(&door_knob);
3260                         if (ct->d_error == DOOR_WAIT) {
3261                                 /* Still waiting for a reply */
3262                                 shuttle_swtch(&door_knob);
3263                                 mutex_enter(&door_knob);
3264                                 if (lwp)
3265                                         lwp->lwp_asleep = 0;
3266                                 goto    shuttle_return;
3267                         } else if (ct->d_error == DOOR_EXIT) {
3268                                 /* Server exit */
3269                                 error = EINTR;
3270                         } else {
3271                                 /* Server did a door_return during ISSIG */
3272                                 error = ct->d_error;
3273                         }
3274                 }
3275                 /*
3276                  * Can't exit if the server is currently copying
3277                  * results for me
3278                  */
3279                 while (DOOR_T_HELD(ct))
3280                         cv_wait(&ct->d_cv, &door_knob);
3281 
3282                 /*
3283                  * Find out if results were successfully copied.
3284                  */
3285                 if (ct->d_error == 0)
3286                         gotresults = 1;
3287         }
3288         if (lwp) {
3289                 lwp->lwp_asleep = 0;         /* /proc */
3290                 lwp->lwp_sysabort = 0;               /* /proc */
3291         }
3292         if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
3293                 door_deliver_unref(dp);
3294         mutex_exit(&door_knob);
3295 
3296         /*
3297          * Translate returned doors (if any)
3298          */
3299 
3300         if (ct->d_noresults)
3301                 goto out;
3302 
3303         if (error) {
3304                 /*
3305                  * If server returned results successfully, then we've
3306                  * been interrupted and may need to clean up.
3307                  */
3308                 if (gotresults) {
3309                         ASSERT(error == EINTR);
3310                         door_fp_close(ct->d_fpp, ct->d_args.desc_num);
3311                 }
3312                 goto out;
3313         }
3314 
3315         if (ct->d_args.desc_num) {
3316                 struct file     **fpp;
3317                 door_desc_t     *didpp;
3318                 vnode_t         *vp;
3319                 uint_t          n = ct->d_args.desc_num;
3320 
3321                 didpp = ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
3322                     roundup(ct->d_args.data_size, sizeof (door_desc_t)));
3323                 fpp = ct->d_fpp;
3324 
3325                 while (n--) {
3326                         struct file *fp;
3327 
3328                         fp = *fpp;
3329                         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3330                                 vp = fp->f_vnode;
3331 
3332                         didpp->d_attributes = DOOR_HANDLE |
3333                             (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
3334                         didpp->d_data.d_handle = FTODH(fp);
3335 
3336                         fpp++; didpp++;
3337                 }
3338         }
3339 
3340         /* on return data is in rbuf */
3341         *param = ct->d_args;         /* structure assignment */
3342 
3343 out:
3344         kmem_free(dup, sizeof (*dup));
3345 
3346         if (ct->d_fpp) {
3347                 kmem_free(ct->d_fpp, ct->d_fpp_size);
3348                 ct->d_fpp = NULL;
3349                 ct->d_fpp_size = 0;
3350         }
3351 
3352         ct->d_upcall = NULL;
3353         ct->d_noresults = 0;
3354         ct->d_buf = NULL;
3355         ct->d_bufsize = 0;
3356         return (error);
3357 }
3358 
3359 /*
3360  * Add a door to the per-process list of active doors for which the
3361  * process is a server.
3362  */
3363 static void
3364 door_list_insert(door_node_t *dp)
3365 {
3366         proc_t *p = dp->door_target;
3367 
3368         ASSERT(MUTEX_HELD(&door_knob));
3369         dp->door_list = p->p_door_list;
3370         p->p_door_list = dp;
3371 }
3372 
3373 /*
3374  * Remove a door from the per-process list of active doors.
3375  */
3376 void
3377 door_list_delete(door_node_t *dp)
3378 {
3379         door_node_t **pp;
3380 
3381         ASSERT(MUTEX_HELD(&door_knob));
3382         /*
3383          * Find the door in the list.  If the door belongs to another process,
3384          * it's OK to use p_door_list since that process can't exit until all
3385          * doors have been taken off the list (see door_exit).
3386          */
3387         pp = &(dp->door_target->p_door_list);
3388         while (*pp != dp)
3389                 pp = &((*pp)->door_list);
3390 
3391         /* found it, take it off the list */
3392         *pp = dp->door_list;
3393 }
3394 
3395 
3396 /*
3397  * External kernel interfaces for doors.  These functions are available
3398  * outside the doorfs module for use in creating and using doors from
3399  * within the kernel.
3400  */
3401 
3402 /*
3403  * door_ki_upcall invokes a user-level door server from the kernel, with
3404  * the credentials associated with curthread.
3405  */
3406 int
3407 door_ki_upcall(door_handle_t dh, door_arg_t *param)
3408 {
3409         return (door_ki_upcall_limited(dh, param, NULL, SIZE_MAX, UINT_MAX));
3410 }
3411 
3412 /*
3413  * door_ki_upcall_limited invokes a user-level door server from the
3414  * kernel with the given credentials and reply limits.  If the "cred"
3415  * argument is NULL, uses the credentials associated with current
3416  * thread.  max_data limits the maximum length of the returned data (the
3417  * client will get E2BIG if they go over), and max_desc limits the
3418  * number of returned descriptors (the client will get EMFILE if they
3419  * go over).
3420  */
3421 int
3422 door_ki_upcall_limited(door_handle_t dh, door_arg_t *param, struct cred *cred,
3423     size_t max_data, uint_t max_desc)
3424 {
3425         file_t *fp = DHTOF(dh);
3426         vnode_t *realvp;
3427 
3428         if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
3429                 realvp = fp->f_vnode;
3430         return (door_upcall(realvp, param, cred, max_data, max_desc));
3431 }
3432 
3433 /*
3434  * Function call to create a "kernel" door server.  A kernel door
3435  * server provides a way for a user-level process to invoke a function
3436  * in the kernel through a door_call.  From the caller's point of
3437  * view, a kernel door server looks the same as a user-level one
3438  * (except the server pid is 0).  Unlike normal door calls, the
3439  * kernel door function is invoked via a normal function call in the
3440  * same thread and context as the caller.
3441  */
3442 int
3443 door_ki_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
3444     door_handle_t *dhp)
3445 {
3446         int err;
3447         file_t *fp;
3448 
3449         /* no DOOR_PRIVATE */
3450         if ((attributes & ~DOOR_KI_CREATE_MASK) ||
3451             (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3452             (DOOR_UNREF | DOOR_UNREF_MULTI))
3453                 return (EINVAL);
3454 
3455         err = door_create_common(pc_cookie, data_cookie, attributes,
3456             1, NULL, &fp);
3457         if (err == 0 && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) &&
3458             p0.p_unref_thread == 0) {
3459                 /* need to create unref thread for process 0 */
3460                 (void) thread_create(NULL, 0, door_unref_kernel, NULL, 0, &p0,
3461                     TS_RUN, minclsyspri);
3462         }
3463         if (err == 0) {
3464                 *dhp = FTODH(fp);
3465         }
3466         return (err);
3467 }
3468 
3469 void
3470 door_ki_hold(door_handle_t dh)
3471 {
3472         file_t *fp = DHTOF(dh);
3473 
3474         mutex_enter(&fp->f_tlock);
3475         fp->f_count++;
3476         mutex_exit(&fp->f_tlock);
3477 }
3478 
3479 void
3480 door_ki_rele(door_handle_t dh)
3481 {
3482         file_t *fp = DHTOF(dh);
3483 
3484         (void) closef(fp);
3485 }
3486 
3487 int
3488 door_ki_open(char *pathname, door_handle_t *dhp)
3489 {
3490         file_t *fp;
3491         vnode_t *vp;
3492         int err;
3493 
3494         if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
3495                 return (err);
3496         if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
3497                 VN_RELE(vp);
3498                 return (err);
3499         }
3500         if (vp->v_type != VDOOR) {
3501                 VN_RELE(vp);
3502                 return (EINVAL);
3503         }
3504         if ((err = falloc(vp, FREAD | FWRITE, &fp, NULL)) != 0) {
3505                 VN_RELE(vp);
3506                 return (err);
3507         }
3508         /* falloc returns with f_tlock held on success */
3509         mutex_exit(&fp->f_tlock);
3510         *dhp = FTODH(fp);
3511         return (0);
3512 }
3513 
3514 int
3515 door_ki_info(door_handle_t dh, struct door_info *dip)
3516 {
3517         file_t *fp = DHTOF(dh);
3518         vnode_t *vp;
3519 
3520         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3521                 vp = fp->f_vnode;
3522         if (vp->v_type != VDOOR)
3523                 return (EINVAL);
3524         door_info_common(VTOD(vp), dip, fp);
3525         return (0);
3526 }
3527 
3528 door_handle_t
3529 door_ki_lookup(int did)
3530 {
3531         file_t *fp;
3532         door_handle_t dh;
3533 
3534         /* is the descriptor really a door? */
3535         if (door_lookup(did, &fp) == NULL)
3536                 return (NULL);
3537         /* got the door, put a hold on it and release the fd */
3538         dh = FTODH(fp);
3539         door_ki_hold(dh);
3540         releasef(did);
3541         return (dh);
3542 }
3543 
3544 int
3545 door_ki_setparam(door_handle_t dh, int type, size_t val)
3546 {
3547         file_t *fp = DHTOF(dh);
3548         vnode_t *vp;
3549 
3550         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3551                 vp = fp->f_vnode;
3552         if (vp->v_type != VDOOR)
3553                 return (EINVAL);
3554         return (door_setparam_common(VTOD(vp), 1, type, val));
3555 }
3556 
3557 int
3558 door_ki_getparam(door_handle_t dh, int type, size_t *out)
3559 {
3560         file_t *fp = DHTOF(dh);
3561         vnode_t *vp;
3562 
3563         if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3564                 vp = fp->f_vnode;
3565         if (vp->v_type != VDOOR)
3566                 return (EINVAL);
3567         return (door_getparam_common(VTOD(vp), type, out));
3568 }