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