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