17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5aa59c4cbSrsb  * Common Development and Distribution License (the "License").
6aa59c4cbSrsb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2197eda132Sraf 
227c478bd9Sstevel@tonic-gate /*
23*a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * System call I/F to doors (outside of vnodes I/F) and misc support
317c478bd9Sstevel@tonic-gate  * routines
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/door.h>
367c478bd9Sstevel@tonic-gate #include <sys/door_data.h>
377c478bd9Sstevel@tonic-gate #include <sys/proc.h>
387c478bd9Sstevel@tonic-gate #include <sys/thread.h>
397c478bd9Sstevel@tonic-gate #include <sys/class.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/stack.h>
447c478bd9Sstevel@tonic-gate #include <sys/debug.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
487c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
497c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
50aa59c4cbSrsb #include <sys/vfs_opreg.h>
517c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
527c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
537c478bd9Sstevel@tonic-gate #include <sys/callb.h>
547c478bd9Sstevel@tonic-gate #include <sys/ucred.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <sys/mman.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
587c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
597c478bd9Sstevel@tonic-gate #include <vm/as.h>
607c478bd9Sstevel@tonic-gate #include <vm/hat.h>
617c478bd9Sstevel@tonic-gate #include <vm/page.h>
627c478bd9Sstevel@tonic-gate #include <vm/seg.h>
637c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
647c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
677c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
687c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
697c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
72da6c28aaSamw  * The maximum amount of data (in bytes) that will be transferred using
737c478bd9Sstevel@tonic-gate  * an intermediate kernel buffer.  For sizes greater than this we map
747c478bd9Sstevel@tonic-gate  * in the destination pages and perform a 1-copy transfer.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate size_t	door_max_arg = 16 * 1024;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
79da6c28aaSamw  * Maximum amount of data that will be transferred in a reply to a
807c478bd9Sstevel@tonic-gate  * door_upcall.  Need to guard against a process returning huge amounts
817c478bd9Sstevel@tonic-gate  * of data and getting the kernel stuck in kmem_alloc.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate size_t	door_max_upcall_reply = 1024 * 1024;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Maximum number of descriptors allowed to be passed in a single
877c478bd9Sstevel@tonic-gate  * door_call or door_return.  We need to allocate kernel memory
887c478bd9Sstevel@tonic-gate  * for all of them at once, so we can't let it scale without limit.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate uint_t door_max_desc = 1024;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Definition of a door handle, used by other kernel subsystems when
947c478bd9Sstevel@tonic-gate  * calling door functions.  This is really a file structure but we
957c478bd9Sstevel@tonic-gate  * want to hide that fact.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate struct __door_handle {
987c478bd9Sstevel@tonic-gate 	file_t dh_file;
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	DHTOF(dh) ((file_t *)(dh))
1027c478bd9Sstevel@tonic-gate #define	FTODH(fp) ((door_handle_t)(fp))
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static int doorfs(long, long, long, long, long, long);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static struct sysent door_sysent = {
1077c478bd9Sstevel@tonic-gate 	6,
1087c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1097c478bd9Sstevel@tonic-gate 	(int (*)())doorfs,
1107c478bd9Sstevel@tonic-gate };
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1137c478bd9Sstevel@tonic-gate 	&mod_syscallops, "doors", &door_sysent
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int
1197c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
1207c478bd9Sstevel@tonic-gate     int32_t arg5, int32_t subcode);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static struct sysent door_sysent32 = {
1237c478bd9Sstevel@tonic-gate 	6,
1247c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1257c478bd9Sstevel@tonic-gate 	(int (*)())doorfs32,
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1297c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
1307c478bd9Sstevel@tonic-gate 	"32-bit door syscalls",
1317c478bd9Sstevel@tonic-gate 	&door_sysent32
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate #endif
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1367c478bd9Sstevel@tonic-gate 	MODREV_1,
1377c478bd9Sstevel@tonic-gate 	&modlsys,
1387c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1397c478bd9Sstevel@tonic-gate 	&modlsys32,
1407c478bd9Sstevel@tonic-gate #endif
1417c478bd9Sstevel@tonic-gate 	NULL
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate dev_t	doordev;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate extern	struct vfs door_vfs;
1477c478bd9Sstevel@tonic-gate extern	struct vnodeops *door_vnodeops;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate int
1507c478bd9Sstevel@tonic-gate _init(void)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t door_vfsops_template[] = {
1537c478bd9Sstevel@tonic-gate 		NULL, NULL
1547c478bd9Sstevel@tonic-gate 	};
1557c478bd9Sstevel@tonic-gate 	extern const fs_operation_def_t door_vnodeops_template[];
1567c478bd9Sstevel@tonic-gate 	vfsops_t *door_vfsops;
1577c478bd9Sstevel@tonic-gate 	major_t major;
1587c478bd9Sstevel@tonic-gate 	int error;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
1617c478bd9Sstevel@tonic-gate 	if ((major = getudev()) == (major_t)-1)
1627c478bd9Sstevel@tonic-gate 		return (ENXIO);
1637c478bd9Sstevel@tonic-gate 	doordev = makedevice(major, 0);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* Create a dummy vfs */
1667c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(door_vfsops_template, &door_vfsops);
1677c478bd9Sstevel@tonic-gate 	if (error != 0) {
1687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vfs ops");
1697c478bd9Sstevel@tonic-gate 		return (error);
1707c478bd9Sstevel@tonic-gate 	}
171da6c28aaSamw 	VFS_INIT(&door_vfs, door_vfsops, NULL);
1727c478bd9Sstevel@tonic-gate 	door_vfs.vfs_flag = VFS_RDONLY;
1737c478bd9Sstevel@tonic-gate 	door_vfs.vfs_dev = doordev;
1747c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
1777c478bd9Sstevel@tonic-gate 	if (error != 0) {
1787c478bd9Sstevel@tonic-gate 		vfs_freevfsops(door_vfsops);
1797c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vnode ops");
1807c478bd9Sstevel@tonic-gate 		return (error);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate int
1867c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /* system call functions */
1927c478bd9Sstevel@tonic-gate static int door_call(int, void *);
1937c478bd9Sstevel@tonic-gate static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
1947c478bd9Sstevel@tonic-gate static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
1957c478bd9Sstevel@tonic-gate     uint_t), void *data_cookie, uint_t);
1967c478bd9Sstevel@tonic-gate static int door_revoke(int);
1977c478bd9Sstevel@tonic-gate static int door_info(int, struct door_info *);
1987c478bd9Sstevel@tonic-gate static int door_ucred(struct ucred_s *);
1997c478bd9Sstevel@tonic-gate static int door_bind(int);
2007c478bd9Sstevel@tonic-gate static int door_unbind(void);
2017c478bd9Sstevel@tonic-gate static int door_unref(void);
2027c478bd9Sstevel@tonic-gate static int door_getparam(int, int, size_t *);
2037c478bd9Sstevel@tonic-gate static int door_setparam(int, int, size_t);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate #define	DOOR_RETURN_OLD	4		/* historic value, for s10 */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate static int
2117c478bd9Sstevel@tonic-gate doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	switch (subcode) {
2147c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2157c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)arg2));
2167c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2177c478bd9Sstevel@tonic-gate 		door_return_desc_t *drdp = (door_return_desc_t *)arg3;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2207c478bd9Sstevel@tonic-gate 			door_return_desc_t drd;
2217c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2227c478bd9Sstevel@tonic-gate 				return (EFAULT);
2237c478bd9Sstevel@tonic-gate 			return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
2247c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)arg4, arg5));
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, NULL,
2277c478bd9Sstevel@tonic-gate 		    0, (caddr_t)arg4, arg5));
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2307c478bd9Sstevel@tonic-gate 		/*
2317c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2327c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2337c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2347c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2357c478bd9Sstevel@tonic-gate 		 */
2367c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
2377c478bd9Sstevel@tonic-gate 		    arg4, (caddr_t)arg5, 0));
2387c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
2397c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())arg1, (void *)arg2, arg3));
2407c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
2417c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
2427c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
2437c478bd9Sstevel@tonic-gate 		return (door_info(arg1, (struct door_info *)arg2));
2447c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
2457c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
2467c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
2477c478bd9Sstevel@tonic-gate 		return (door_unbind());
2487c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
2497c478bd9Sstevel@tonic-gate 		return (door_unref());
2507c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
2517c478bd9Sstevel@tonic-gate 		return (door_ucred((struct ucred_s *)arg1));
2527c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
2537c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2, (size_t *)arg3));
2547c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
2557c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, arg3));
2567c478bd9Sstevel@tonic-gate 	default:
2577c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls from 32-bit programs.
2647c478bd9Sstevel@tonic-gate  * Needed at the moment because of the casts - they undo some damage
2657c478bd9Sstevel@tonic-gate  * that truss causes (sign-extending the stack pointer) when truss'ing
2667c478bd9Sstevel@tonic-gate  * a 32-bit program using doors.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate static int
2697c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
2707c478bd9Sstevel@tonic-gate     int32_t arg4, int32_t arg5, int32_t subcode)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	switch (subcode) {
2737c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2747c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
2757c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2767c478bd9Sstevel@tonic-gate 		door_return_desc32_t *drdp =
2777c478bd9Sstevel@tonic-gate 		    (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
2787c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2797c478bd9Sstevel@tonic-gate 			door_return_desc32_t drd;
2807c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2817c478bd9Sstevel@tonic-gate 				return (EFAULT);
2827c478bd9Sstevel@tonic-gate 			return (door_return(
2837c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
2847c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)drd.desc_ptr,
2857c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2867c478bd9Sstevel@tonic-gate 			    (size_t)(uintptr_t)(size32_t)arg5));
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
2897c478bd9Sstevel@tonic-gate 		    arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2907c478bd9Sstevel@tonic-gate 		    (size_t)(uintptr_t)(size32_t)arg5));
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2937c478bd9Sstevel@tonic-gate 		/*
2947c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2957c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2967c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2977c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2987c478bd9Sstevel@tonic-gate 		 */
2997c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
3007c478bd9Sstevel@tonic-gate 		    (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
3017c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
3027c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
3037c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
3047c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)(caddr32_t)arg2, arg3));
3057c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
3067c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
3077c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
3087c478bd9Sstevel@tonic-gate 		return (door_info(arg1,
3097c478bd9Sstevel@tonic-gate 		    (struct door_info *)(uintptr_t)(caddr32_t)arg2));
3107c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
3117c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
3127c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
3137c478bd9Sstevel@tonic-gate 		return (door_unbind());
3147c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
3157c478bd9Sstevel@tonic-gate 		return (door_unref());
3167c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
3177c478bd9Sstevel@tonic-gate 		return (door_ucred(
3187c478bd9Sstevel@tonic-gate 		    (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
3197c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
3207c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2,
3217c478bd9Sstevel@tonic-gate 		    (size_t *)(uintptr_t)(caddr32_t)arg3));
3227c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
3237c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	default:
3267c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate #endif
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate void shuttle_resume(kthread_t *, kmutex_t *);
3327c478bd9Sstevel@tonic-gate void shuttle_swtch(kmutex_t *);
3337c478bd9Sstevel@tonic-gate void shuttle_sleep(kthread_t *);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * Support routines
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate static int door_create_common(void (*)(), void *, uint_t, int, int *,
3397c478bd9Sstevel@tonic-gate     file_t **);
3407c478bd9Sstevel@tonic-gate static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3417c478bd9Sstevel@tonic-gate static int door_args(kthread_t *, int);
3427c478bd9Sstevel@tonic-gate static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3437c478bd9Sstevel@tonic-gate static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
344c4ace179Sdm static void	door_server_exit(proc_t *, kthread_t *);
3457c478bd9Sstevel@tonic-gate static void	door_release_server(door_node_t *, kthread_t *);
3467c478bd9Sstevel@tonic-gate static kthread_t	*door_get_server(door_node_t *);
3477c478bd9Sstevel@tonic-gate static door_node_t	*door_lookup(int, file_t **);
3487c478bd9Sstevel@tonic-gate static int	door_translate_in(void);
3497c478bd9Sstevel@tonic-gate static int	door_translate_out(void);
3507c478bd9Sstevel@tonic-gate static void	door_fd_rele(door_desc_t *, uint_t, int);
3517c478bd9Sstevel@tonic-gate static void	door_list_insert(door_node_t *);
3527c478bd9Sstevel@tonic-gate static void	door_info_common(door_node_t *, door_info_t *, file_t *);
3537c478bd9Sstevel@tonic-gate static int	door_release_fds(door_desc_t *, uint_t);
3547c478bd9Sstevel@tonic-gate static void	door_fd_close(door_desc_t *, uint_t);
3557c478bd9Sstevel@tonic-gate static void	door_fp_close(struct file **, uint_t);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static door_data_t *
3587c478bd9Sstevel@tonic-gate door_my_data(int create_if_missing)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	door_data_t *ddp;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	ddp = curthread->t_door;
3637c478bd9Sstevel@tonic-gate 	if (create_if_missing && ddp == NULL)
3647c478bd9Sstevel@tonic-gate 		ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	return (ddp);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static door_server_t *
3707c478bd9Sstevel@tonic-gate door_my_server(int create_if_missing)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static door_client_t *
3787c478bd9Sstevel@tonic-gate door_my_client(int create_if_missing)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * System call to create a door
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate int
3897c478bd9Sstevel@tonic-gate door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	int fd;
3927c478bd9Sstevel@tonic-gate 	int err;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_CREATE_MASK) ||
3957c478bd9Sstevel@tonic-gate 	    ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3967c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI)))
3977c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
4007c478bd9Sstevel@tonic-gate 	    &fd, NULL)) != 0)
4017c478bd9Sstevel@tonic-gate 		return (set_errno(err));
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	f_setfd(fd, FD_CLOEXEC);
4047c478bd9Sstevel@tonic-gate 	return (fd);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * Common code for creating user and kernel doors.  If a door was
4097c478bd9Sstevel@tonic-gate  * created, stores a file structure pointer in the location pointed
4107c478bd9Sstevel@tonic-gate  * to by fpp (if fpp is non-NULL) and returns 0.  Also, if a non-NULL
4117c478bd9Sstevel@tonic-gate  * pointer to a file descriptor is passed in as fdp, allocates a file
4127c478bd9Sstevel@tonic-gate  * descriptor representing the door.  If a door could not be created,
4137c478bd9Sstevel@tonic-gate  * returns an error.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static int
4167c478bd9Sstevel@tonic-gate door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
4177c478bd9Sstevel@tonic-gate     int from_kernel, int *fdp, file_t **fpp)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
4207c478bd9Sstevel@tonic-gate 	vnode_t		*vp;
4217c478bd9Sstevel@tonic-gate 	struct file	*fp;
4227c478bd9Sstevel@tonic-gate 	static door_id_t index = 0;
4237c478bd9Sstevel@tonic-gate 	proc_t		*p = (from_kernel)? &p0 : curproc;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	dp->door_vnode = vn_alloc(KM_SLEEP);
4287c478bd9Sstevel@tonic-gate 	dp->door_target = p;
4297c478bd9Sstevel@tonic-gate 	dp->door_data = data_cookie;
4307c478bd9Sstevel@tonic-gate 	dp->door_pc = pc_cookie;
4317c478bd9Sstevel@tonic-gate 	dp->door_flags = attributes;
4327c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4337c478bd9Sstevel@tonic-gate 	if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
4347c478bd9Sstevel@tonic-gate 		dp->door_data_max = UINT32_MAX;
4357c478bd9Sstevel@tonic-gate 	else
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate 		dp->door_data_max = SIZE_MAX;
4387c478bd9Sstevel@tonic-gate 	dp->door_data_min = 0UL;
4397c478bd9Sstevel@tonic-gate 	dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	vp = DTOV(dp);
4427c478bd9Sstevel@tonic-gate 	vn_setops(vp, door_vnodeops);
4437c478bd9Sstevel@tonic-gate 	vp->v_type = VDOOR;
4447c478bd9Sstevel@tonic-gate 	vp->v_vfsp = &door_vfs;
4457c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)dp;
4467c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
4477c478bd9Sstevel@tonic-gate 	dp->door_index = index++;
4487c478bd9Sstevel@tonic-gate 	/* add to per-process door list */
4497c478bd9Sstevel@tonic-gate 	door_list_insert(dp);
4507c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
4537c478bd9Sstevel@tonic-gate 		/*
4547c478bd9Sstevel@tonic-gate 		 * If the file table is full, remove the door from the
4557c478bd9Sstevel@tonic-gate 		 * per-process list, free the door, and return NULL.
4567c478bd9Sstevel@tonic-gate 		 */
4577c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
4587c478bd9Sstevel@tonic-gate 		door_list_delete(dp);
4597c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
4607c478bd9Sstevel@tonic-gate 		vn_free(vp);
4617c478bd9Sstevel@tonic-gate 		kmem_free(dp, sizeof (door_node_t));
4627c478bd9Sstevel@tonic-gate 		return (EMFILE);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 	vn_exists(vp);
4657c478bd9Sstevel@tonic-gate 	if (fdp != NULL)
4667c478bd9Sstevel@tonic-gate 		setf(*fdp, fp);
4677c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
4707c478bd9Sstevel@tonic-gate 		*fpp = fp;
4717c478bd9Sstevel@tonic-gate 	return (0);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate static int
4757c478bd9Sstevel@tonic-gate door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* we allow unref upcalls through, despite any minimum */
4807c478bd9Sstevel@tonic-gate 	if (da->data_size < dp->door_data_min &&
4817c478bd9Sstevel@tonic-gate 	    !(upcall && da->data_ptr == DOOR_UNREF_DATA))
4827c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (da->data_size > dp->door_data_max)
4857c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
4887c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (da->desc_num > dp->door_desc_max)
4917c478bd9Sstevel@tonic-gate 		return (ENFILE);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (0);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * Door invocation.
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate int
5007c478bd9Sstevel@tonic-gate door_call(int did, void *args)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	/* Locals */
5037c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
5047c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
5057c478bd9Sstevel@tonic-gate 	int		error = 0;
5067c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
5077c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
5087c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
5097c478bd9Sstevel@tonic-gate 	door_desc_t	*start = NULL;
5107c478bd9Sstevel@tonic-gate 	uint_t		ncopied = 0;
5117c478bd9Sstevel@tonic-gate 	size_t		dsize;
5127c478bd9Sstevel@tonic-gate 	/* destructor for data returned by a kernel server */
5137c478bd9Sstevel@tonic-gate 	void		(*destfn)() = NULL;
5147c478bd9Sstevel@tonic-gate 	void		*destarg;
5157c478bd9Sstevel@tonic-gate 	model_t		datamodel;
5167c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
517*a574db85Sraf 	int		cancel_pending;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
5207c478bd9Sstevel@tonic-gate 	datamodel = lwp_getdatamodel(lwp);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * Get the arguments
5267c478bd9Sstevel@tonic-gate 	 */
5277c478bd9Sstevel@tonic-gate 	if (args) {
5287c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
5297c478bd9Sstevel@tonic-gate 			if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
5307c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5317c478bd9Sstevel@tonic-gate 		} else {
5327c478bd9Sstevel@tonic-gate 			door_arg32_t    da32;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 			if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
5357c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5367c478bd9Sstevel@tonic-gate 			ct->d_args.data_ptr =
5377c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.data_ptr;
5387c478bd9Sstevel@tonic-gate 			ct->d_args.data_size = da32.data_size;
5397c478bd9Sstevel@tonic-gate 			ct->d_args.desc_ptr =
5407c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)da32.desc_ptr;
5417c478bd9Sstevel@tonic-gate 			ct->d_args.desc_num = da32.desc_num;
5427c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf =
5437c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.rbuf;
5447c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = da32.rsize;
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 	} else {
5477c478bd9Sstevel@tonic-gate 		/* No arguments, and no results allowed */
5487c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
5497c478bd9Sstevel@tonic-gate 		ct->d_args.data_size = 0;
5507c478bd9Sstevel@tonic-gate 		ct->d_args.desc_num = 0;
5517c478bd9Sstevel@tonic-gate 		ct->d_args.rsize = 0;
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
5557c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
5587c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
5597c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5607c478bd9Sstevel@tonic-gate 		error = EBADF;
5617c478bd9Sstevel@tonic-gate 		goto out;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/*
5657c478bd9Sstevel@tonic-gate 	 * before we do anything, check that we are not overflowing the
5667c478bd9Sstevel@tonic-gate 	 * required limits.
5677c478bd9Sstevel@tonic-gate 	 */
5687c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, &ct->d_args, 0);
5697c478bd9Sstevel@tonic-gate 	if (error != 0) {
5707c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5717c478bd9Sstevel@tonic-gate 		goto out;
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/*
5757c478bd9Sstevel@tonic-gate 	 * Check for in-kernel door server.
5767c478bd9Sstevel@tonic-gate 	 */
5777c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
5787c478bd9Sstevel@tonic-gate 		caddr_t rbuf = ct->d_args.rbuf;
5797c478bd9Sstevel@tonic-gate 		size_t rsize = ct->d_args.rsize;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		dp->door_active++;
5827c478bd9Sstevel@tonic-gate 		ct->d_kernel = 1;
5837c478bd9Sstevel@tonic-gate 		ct->d_error = DOOR_WAIT;
5847c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5857c478bd9Sstevel@tonic-gate 		/* translate file descriptors to vnodes */
5867c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
5877c478bd9Sstevel@tonic-gate 			error = door_translate_in();
5887c478bd9Sstevel@tonic-gate 			if (error)
5897c478bd9Sstevel@tonic-gate 				goto out;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 		/*
5927c478bd9Sstevel@tonic-gate 		 * Call kernel door server.  Arguments are passed and
5937c478bd9Sstevel@tonic-gate 		 * returned as a door_arg pointer.  When called, data_ptr
5947c478bd9Sstevel@tonic-gate 		 * points to user data and desc_ptr points to a kernel list
5957c478bd9Sstevel@tonic-gate 		 * of door descriptors that have been converted to file
5967c478bd9Sstevel@tonic-gate 		 * structure pointers.  It's the server function's
5977c478bd9Sstevel@tonic-gate 		 * responsibility to copyin the data pointed to by data_ptr
5987c478bd9Sstevel@tonic-gate 		 * (this avoids extra copying in some cases).  On return,
5997c478bd9Sstevel@tonic-gate 		 * data_ptr points to a user buffer of data, and desc_ptr
6007c478bd9Sstevel@tonic-gate 		 * points to a kernel list of door descriptors representing
6017c478bd9Sstevel@tonic-gate 		 * files.  When a reference is passed to a kernel server,
6027c478bd9Sstevel@tonic-gate 		 * it is the server's responsibility to release the reference
6037c478bd9Sstevel@tonic-gate 		 * (by calling closef).  When the server includes a
6047c478bd9Sstevel@tonic-gate 		 * reference in its reply, it is released as part of the
6057c478bd9Sstevel@tonic-gate 		 * the call (the server must duplicate the reference if
6067c478bd9Sstevel@tonic-gate 		 * it wants to retain a copy).  The destfn, if set to
6077c478bd9Sstevel@tonic-gate 		 * non-NULL, is a destructor to be called when the returned
6087c478bd9Sstevel@tonic-gate 		 * kernel data (if any) is no longer needed (has all been
6097c478bd9Sstevel@tonic-gate 		 * translated and copied to user level).
6107c478bd9Sstevel@tonic-gate 		 */
6117c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &ct->d_args,
6127c478bd9Sstevel@tonic-gate 		    &destfn, &destarg, &error);
6137c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6147c478bd9Sstevel@tonic-gate 		/* not implemented yet */
6157c478bd9Sstevel@tonic-gate 		if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
6167c478bd9Sstevel@tonic-gate 			door_deliver_unref(dp);
6177c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6187c478bd9Sstevel@tonic-gate 		if (error)
6197c478bd9Sstevel@tonic-gate 			goto out;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		/* translate vnodes to files */
6227c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
6237c478bd9Sstevel@tonic-gate 			error = door_translate_out();
6247c478bd9Sstevel@tonic-gate 			if (error)
6257c478bd9Sstevel@tonic-gate 				goto out;
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 		ct->d_buf = ct->d_args.rbuf;
6287c478bd9Sstevel@tonic-gate 		ct->d_bufsize = ct->d_args.rsize;
6297c478bd9Sstevel@tonic-gate 		if (rsize < (ct->d_args.data_size +
6307c478bd9Sstevel@tonic-gate 		    (ct->d_args.desc_num * sizeof (door_desc_t)))) {
6317c478bd9Sstevel@tonic-gate 			/* handle overflow */
6327c478bd9Sstevel@tonic-gate 			error = door_overflow(curthread, ct->d_args.data_ptr,
6337c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size, ct->d_args.desc_ptr,
6347c478bd9Sstevel@tonic-gate 			    ct->d_args.desc_num);
6357c478bd9Sstevel@tonic-gate 			if (error)
6367c478bd9Sstevel@tonic-gate 				goto out;
6377c478bd9Sstevel@tonic-gate 			/* door_overflow sets d_args rbuf and rsize */
6387c478bd9Sstevel@tonic-gate 		} else {
6397c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = rbuf;
6407c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = rsize;
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 		goto results;
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	/*
6467c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
6477c478bd9Sstevel@tonic-gate 	 */
6487c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
6497c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
6507c478bd9Sstevel@tonic-gate 			error = EBADF;
6517c478bd9Sstevel@tonic-gate 		else
6527c478bd9Sstevel@tonic-gate 			error = EAGAIN;
6537c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6547c478bd9Sstevel@tonic-gate 		goto out;
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
6587c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num || ct->d_args.data_size) {
6597c478bd9Sstevel@tonic-gate 		int is_private = (dp->door_flags & DOOR_PRIVATE);
6607c478bd9Sstevel@tonic-gate 		/*
6617c478bd9Sstevel@tonic-gate 		 * Move data from client to server
6627c478bd9Sstevel@tonic-gate 		 */
6637c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
6647c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6657c478bd9Sstevel@tonic-gate 		error = door_args(server_thread, is_private);
6667c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6677c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
6687c478bd9Sstevel@tonic-gate 		if (error) {
6697c478bd9Sstevel@tonic-gate 			/*
6707c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
6717c478bd9Sstevel@tonic-gate 			 */
6727c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
6737c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
6747c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
6757c478bd9Sstevel@tonic-gate 			goto out;
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	dp->door_active++;
6807c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
6817c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
6827c478bd9Sstevel@tonic-gate 	st->d_active = dp;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
6877c478bd9Sstevel@tonic-gate shuttle_return:
6887c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
6897c478bd9Sstevel@tonic-gate 		/*
6907c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
6917c478bd9Sstevel@tonic-gate 		 */
6927c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
693*a574db85Sraf 		cancel_pending = 0;
694*a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
695*a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
696*a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
6977c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
6987c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
699*a574db85Sraf 			if (cancel_pending)
700*a574db85Sraf 				schedctl_cancel_eintr();
7017c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7027c478bd9Sstevel@tonic-gate 			error = EINTR;
7037c478bd9Sstevel@tonic-gate 			/*
7047c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
7057c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
7067c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
7077c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
7087c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
7097c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
7107c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
7117c478bd9Sstevel@tonic-gate 			 */
7127c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
7137c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
7147c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
7177c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
7207c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
7217c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
7247c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
7257c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
7287c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
7297c478bd9Sstevel@tonic-gate 				}
7307c478bd9Sstevel@tonic-gate 			}
7317c478bd9Sstevel@tonic-gate 		} else {
7327c478bd9Sstevel@tonic-gate 			/*
7337c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
7347c478bd9Sstevel@tonic-gate 			 *
7357c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
7367c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
7377c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
7387c478bd9Sstevel@tonic-gate 			 * is updated by the server.
7397c478bd9Sstevel@tonic-gate 			 */
7407c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7417c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
7427c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
7437c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
7447c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
7457c478bd9Sstevel@tonic-gate 				lwp->lwp_asleep = 0;
7467c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
7477c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
7487c478bd9Sstevel@tonic-gate 				/* Server exit */
7497c478bd9Sstevel@tonic-gate 				error = EINTR;
7507c478bd9Sstevel@tonic-gate 			} else {
7517c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
7527c478bd9Sstevel@tonic-gate 				error = ct->d_error;
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 		/*
7567c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
7577c478bd9Sstevel@tonic-gate 		 * results for me.
7587c478bd9Sstevel@tonic-gate 		 */
7597c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
7607c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		/*
7637c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
7667c478bd9Sstevel@tonic-gate 			gotresults = 1;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;		/* /proc */
7697c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;		/* /proc */
7707c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
7717c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
7727c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate results:
7757c478bd9Sstevel@tonic-gate 	/*
7767c478bd9Sstevel@tonic-gate 	 * Move the results to userland (if any)
7777c478bd9Sstevel@tonic-gate 	 */
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
7807c478bd9Sstevel@tonic-gate 		goto out;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if (error) {
7837c478bd9Sstevel@tonic-gate 		/*
7847c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
7857c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
7867c478bd9Sstevel@tonic-gate 		 */
7877c478bd9Sstevel@tonic-gate 		if (gotresults) {
7887c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
7897c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 		goto out;
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * Copy back data if we haven't caused an overflow (already
7967c478bd9Sstevel@tonic-gate 	 * handled) and we are using a 2 copy transfer, or we are
7977c478bd9Sstevel@tonic-gate 	 * returning data from a kernel server.
7987c478bd9Sstevel@tonic-gate 	 */
7997c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size) {
8007c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
8017c478bd9Sstevel@tonic-gate 		if (ct->d_kernel || (!ct->d_overflow &&
8027c478bd9Sstevel@tonic-gate 		    ct->d_args.data_size <= door_max_arg)) {
8037c478bd9Sstevel@tonic-gate 			if (copyout(ct->d_buf, ct->d_args.rbuf,
8047c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size)) {
8057c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, ct->d_args.desc_num);
8067c478bd9Sstevel@tonic-gate 				error = EFAULT;
8077c478bd9Sstevel@tonic-gate 				goto out;
8087c478bd9Sstevel@tonic-gate 			}
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * stuff returned doors into our proc, copyout the descriptors
8147c478bd9Sstevel@tonic-gate 	 */
8157c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
8167c478bd9Sstevel@tonic-gate 		struct file	**fpp;
8177c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
8187c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		dsize = n * sizeof (door_desc_t);
8217c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
8227c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		while (n--) {
8257c478bd9Sstevel@tonic-gate 			if (door_insert(*fpp, didpp) == -1) {
8267c478bd9Sstevel@tonic-gate 				/* Close remaining files */
8277c478bd9Sstevel@tonic-gate 				door_fp_close(fpp, n + 1);
8287c478bd9Sstevel@tonic-gate 				error = EMFILE;
8297c478bd9Sstevel@tonic-gate 				goto out;
8307c478bd9Sstevel@tonic-gate 			}
8317c478bd9Sstevel@tonic-gate 			fpp++; didpp++; ncopied++;
8327c478bd9Sstevel@tonic-gate 		}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
8357c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 		if (copyout(start, ct->d_args.desc_ptr, dsize)) {
8387c478bd9Sstevel@tonic-gate 			error = EFAULT;
8397c478bd9Sstevel@tonic-gate 			goto out;
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	/*
8447c478bd9Sstevel@tonic-gate 	 * Return the results
8457c478bd9Sstevel@tonic-gate 	 */
8467c478bd9Sstevel@tonic-gate 	if (datamodel == DATAMODEL_NATIVE) {
8477c478bd9Sstevel@tonic-gate 		if (copyout(&ct->d_args, args, sizeof (door_arg_t)) != 0)
8487c478bd9Sstevel@tonic-gate 			error = EFAULT;
8497c478bd9Sstevel@tonic-gate 	} else {
8507c478bd9Sstevel@tonic-gate 		door_arg32_t    da32;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 		da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr;
8537c478bd9Sstevel@tonic-gate 		da32.data_size = ct->d_args.data_size;
8547c478bd9Sstevel@tonic-gate 		da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr;
8557c478bd9Sstevel@tonic-gate 		da32.desc_num = ct->d_args.desc_num;
8567c478bd9Sstevel@tonic-gate 		da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf;
8577c478bd9Sstevel@tonic-gate 		da32.rsize = ct->d_args.rsize;
8587c478bd9Sstevel@tonic-gate 		if (copyout(&da32, args, sizeof (door_arg32_t)) != 0) {
8597c478bd9Sstevel@tonic-gate 			error = EFAULT;
8607c478bd9Sstevel@tonic-gate 		}
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate out:
8647c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	/* clean up the overflow buffer if an error occurred */
8677c478bd9Sstevel@tonic-gate 	if (error != 0 && ct->d_overflow) {
8687c478bd9Sstevel@tonic-gate 		(void) as_unmap(curproc->p_as, ct->d_args.rbuf,
8697c478bd9Sstevel@tonic-gate 		    ct->d_args.rsize);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 	ct->d_overflow = 0;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/* call destructor */
8747c478bd9Sstevel@tonic-gate 	if (destfn) {
8757c478bd9Sstevel@tonic-gate 		ASSERT(ct->d_kernel);
8767c478bd9Sstevel@tonic-gate 		(*destfn)(dp->door_data, destarg);
8777c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
8787c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	if (dp)
8827c478bd9Sstevel@tonic-gate 		releasef(did);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	if (ct->d_buf) {
8857c478bd9Sstevel@tonic-gate 		ASSERT(!ct->d_kernel);
8867c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_buf, ct->d_bufsize);
8877c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
8887c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate 	ct->d_kernel = 0;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	/* clean up the descriptor copyout buffer */
8937c478bd9Sstevel@tonic-gate 	if (start != NULL) {
8947c478bd9Sstevel@tonic-gate 		if (error != 0)
8957c478bd9Sstevel@tonic-gate 			door_fd_close(start, ncopied);
8967c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
9007c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
9017c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
9027c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if (error)
9067c478bd9Sstevel@tonic-gate 		return (set_errno(error));
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	return (0);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate static int
9127c478bd9Sstevel@tonic-gate door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate 	int error = 0;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
9197c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9207c478bd9Sstevel@tonic-gate 		return (EBADF);
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	/*
9247c478bd9Sstevel@tonic-gate 	 * door_ki_setparam() can only affect kernel doors.
9257c478bd9Sstevel@tonic-gate 	 * door_setparam() can only affect doors attached to the current
9267c478bd9Sstevel@tonic-gate 	 * process.
9277c478bd9Sstevel@tonic-gate 	 */
9287c478bd9Sstevel@tonic-gate 	if ((from_kernel && dp->door_target != &p0) ||
9297c478bd9Sstevel@tonic-gate 	    (!from_kernel && dp->door_target != curproc)) {
9307c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9317c478bd9Sstevel@tonic-gate 		return (EPERM);
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	switch (type) {
9357c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
9367c478bd9Sstevel@tonic-gate 		if (val > INT_MAX)
9377c478bd9Sstevel@tonic-gate 			error = ERANGE;
9387c478bd9Sstevel@tonic-gate 		else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0)
9397c478bd9Sstevel@tonic-gate 			error = ENOTSUP;
9407c478bd9Sstevel@tonic-gate 		else
9417c478bd9Sstevel@tonic-gate 			dp->door_desc_max = (uint_t)val;
9427c478bd9Sstevel@tonic-gate 		break;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
9457c478bd9Sstevel@tonic-gate 		if (val > dp->door_data_max)
9467c478bd9Sstevel@tonic-gate 			error = EINVAL;
9477c478bd9Sstevel@tonic-gate 		else
9487c478bd9Sstevel@tonic-gate 			dp->door_data_min = val;
9497c478bd9Sstevel@tonic-gate 		break;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
9527c478bd9Sstevel@tonic-gate 		if (val < dp->door_data_min)
9537c478bd9Sstevel@tonic-gate 			error = EINVAL;
9547c478bd9Sstevel@tonic-gate 		else
9557c478bd9Sstevel@tonic-gate 			dp->door_data_max = val;
9567c478bd9Sstevel@tonic-gate 		break;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	default:
9597c478bd9Sstevel@tonic-gate 		error = EINVAL;
9607c478bd9Sstevel@tonic-gate 		break;
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
9647c478bd9Sstevel@tonic-gate 	return (error);
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate static int
9687c478bd9Sstevel@tonic-gate door_getparam_common(door_node_t *dp, int type, size_t *out)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate 	int error = 0;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
9737c478bd9Sstevel@tonic-gate 	switch (type) {
9747c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
9757c478bd9Sstevel@tonic-gate 		*out = (size_t)dp->door_desc_max;
9767c478bd9Sstevel@tonic-gate 		break;
9777c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
9787c478bd9Sstevel@tonic-gate 		*out = dp->door_data_min;
9797c478bd9Sstevel@tonic-gate 		break;
9807c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
9817c478bd9Sstevel@tonic-gate 		*out = dp->door_data_max;
9827c478bd9Sstevel@tonic-gate 		break;
9837c478bd9Sstevel@tonic-gate 	default:
9847c478bd9Sstevel@tonic-gate 		error = EINVAL;
9857c478bd9Sstevel@tonic-gate 		break;
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
9887c478bd9Sstevel@tonic-gate 	return (error);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate int
9927c478bd9Sstevel@tonic-gate door_setparam(int did, int type, size_t val)
9937c478bd9Sstevel@tonic-gate {
9947c478bd9Sstevel@tonic-gate 	door_node_t *dp;
9957c478bd9Sstevel@tonic-gate 	int error = 0;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
9987c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	error = door_setparam_common(dp, 0, type, val);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	releasef(did);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if (error)
10057c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	return (0);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate int
10117c478bd9Sstevel@tonic-gate door_getparam(int did, int type, size_t *out)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate 	door_node_t *dp;
10147c478bd9Sstevel@tonic-gate 	size_t val = 0;
10157c478bd9Sstevel@tonic-gate 	int error = 0;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
10187c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	error = door_getparam_common(dp, type, &val);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	releasef(did);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (error)
10257c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
10287c478bd9Sstevel@tonic-gate 		if (copyout(&val, out, sizeof (val)))
10297c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10307c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10317c478bd9Sstevel@tonic-gate 	} else {
10327c478bd9Sstevel@tonic-gate 		size32_t val32 = (size32_t)val;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 		if (val != val32)
10357c478bd9Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		if (copyout(&val32, out, sizeof (val32)))
10387c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10397c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	return (0);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate  * A copyout() which proceeds from high addresses to low addresses.  This way,
10477c478bd9Sstevel@tonic-gate  * stack guard pages are effective.
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate static int
10507c478bd9Sstevel@tonic-gate door_stack_copyout(const void *kaddr, void *uaddr, size_t count)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	const char *kbase = (const char *)kaddr;
10537c478bd9Sstevel@tonic-gate 	uintptr_t ubase = (uintptr_t)uaddr;
10547c478bd9Sstevel@tonic-gate 	size_t pgsize = PAGESIZE;
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	if (count <= pgsize)
10577c478bd9Sstevel@tonic-gate 		return (copyout(kaddr, uaddr, count));
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	while (count > 0) {
10607c478bd9Sstevel@tonic-gate 		uintptr_t start, end, offset, amount;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		end = ubase + count;
10637c478bd9Sstevel@tonic-gate 		start = P2ALIGN(end - 1, pgsize);
10647c478bd9Sstevel@tonic-gate 		if (P2ALIGN(ubase, pgsize) == start)
10657c478bd9Sstevel@tonic-gate 			start = ubase;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 		offset = start - ubase;
10687c478bd9Sstevel@tonic-gate 		amount = end - start;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		ASSERT(amount > 0 && amount <= count && amount <= pgsize);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		if (copyout(kbase + offset, (void *)start, amount))
10737c478bd9Sstevel@tonic-gate 			return (1);
10747c478bd9Sstevel@tonic-gate 		count -= amount;
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 	return (0);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  * Writes the stack layout for door_return() into the door_server_t of the
10817c478bd9Sstevel@tonic-gate  * server thread.
10827c478bd9Sstevel@tonic-gate  */
10837c478bd9Sstevel@tonic-gate static int
10847c478bd9Sstevel@tonic-gate door_layout(kthread_t *tp, size_t data_size, uint_t ndesc, int info_needed)
10857c478bd9Sstevel@tonic-gate {
10867c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(tp->t_door);
10877c478bd9Sstevel@tonic-gate 	door_layout_t *out = &st->d_layout;
10887c478bd9Sstevel@tonic-gate 	uintptr_t base_sp = (uintptr_t)st->d_sp;
10897c478bd9Sstevel@tonic-gate 	size_t ssize = st->d_ssize;
10907c478bd9Sstevel@tonic-gate 	size_t descsz;
10917c478bd9Sstevel@tonic-gate 	uintptr_t descp, datap, infop, resultsp, finalsp;
10927c478bd9Sstevel@tonic-gate 	size_t align = STACK_ALIGN;
10937c478bd9Sstevel@tonic-gate 	size_t results_sz = sizeof (struct door_results);
10947c478bd9Sstevel@tonic-gate 	model_t datamodel = lwp_getdatamodel(ttolwp(tp));
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	ASSERT(!st->d_layout_done);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate #ifndef _STACK_GROWS_DOWNWARD
10997c478bd9Sstevel@tonic-gate #error stack does not grow downward, door_layout() must change
11007c478bd9Sstevel@tonic-gate #endif
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
11037c478bd9Sstevel@tonic-gate 	if (datamodel != DATAMODEL_NATIVE) {
11047c478bd9Sstevel@tonic-gate 		align = STACK_ALIGN32;
11057c478bd9Sstevel@tonic-gate 		results_sz = sizeof (struct door_results32);
11067c478bd9Sstevel@tonic-gate 	}
11077c478bd9Sstevel@tonic-gate #endif
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	descsz = ndesc * sizeof (door_desc_t);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/*
11127c478bd9Sstevel@tonic-gate 	 * To speed up the overflow checking, we do an initial check
11137c478bd9Sstevel@tonic-gate 	 * that the passed in data size won't cause us to wrap past
11147c478bd9Sstevel@tonic-gate 	 * base_sp.  Since door_max_desc limits descsz, we can
11157c478bd9Sstevel@tonic-gate 	 * safely use it here.  65535 is an arbitrary 'bigger than
11167c478bd9Sstevel@tonic-gate 	 * we need, small enough to not cause trouble' constant;
11177c478bd9Sstevel@tonic-gate 	 * the only constraint is that it must be > than:
11187c478bd9Sstevel@tonic-gate 	 *
11197c478bd9Sstevel@tonic-gate 	 *	5 * STACK_ALIGN +
11207c478bd9Sstevel@tonic-gate 	 *	    sizeof (door_info_t) +
11217c478bd9Sstevel@tonic-gate 	 *	    sizeof (door_results_t) +
11227c478bd9Sstevel@tonic-gate 	 *	    (max adjustment from door_final_sp())
11237c478bd9Sstevel@tonic-gate 	 *
11247c478bd9Sstevel@tonic-gate 	 * After we compute the layout, we can safely do a "did we wrap
11257c478bd9Sstevel@tonic-gate 	 * around" check, followed by a check against the recorded
11267c478bd9Sstevel@tonic-gate 	 * stack size.
11277c478bd9Sstevel@tonic-gate 	 */
11287c478bd9Sstevel@tonic-gate 	if (data_size >= SIZE_MAX - (size_t)65535UL - descsz)
11297c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* overflow */
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	descp = P2ALIGN(base_sp - descsz, align);
11327c478bd9Sstevel@tonic-gate 	datap = P2ALIGN(descp - data_size, align);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	if (info_needed)
11357c478bd9Sstevel@tonic-gate 		infop = P2ALIGN(datap - sizeof (door_info_t), align);
11367c478bd9Sstevel@tonic-gate 	else
11377c478bd9Sstevel@tonic-gate 		infop = datap;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	resultsp = P2ALIGN(infop - results_sz, align);
11407c478bd9Sstevel@tonic-gate 	finalsp = door_final_sp(resultsp, align, datamodel);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	if (finalsp > base_sp)
11437c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* overflow */
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	if (ssize != 0 && (base_sp - finalsp) > ssize)
11467c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* doesn't fit in stack */
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	out->dl_descp = (ndesc != 0)? (caddr_t)descp : 0;
11497c478bd9Sstevel@tonic-gate 	out->dl_datap = (data_size != 0)? (caddr_t)datap : 0;
11507c478bd9Sstevel@tonic-gate 	out->dl_infop = info_needed? (caddr_t)infop : 0;
11517c478bd9Sstevel@tonic-gate 	out->dl_resultsp = (caddr_t)resultsp;
11527c478bd9Sstevel@tonic-gate 	out->dl_sp = (caddr_t)finalsp;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	st->d_layout_done = 1;
11557c478bd9Sstevel@tonic-gate 	return (0);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate static int
11597c478bd9Sstevel@tonic-gate door_server_dispatch(door_client_t *ct, door_node_t *dp)
11607c478bd9Sstevel@tonic-gate {
11617c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(curthread->t_door);
11627c478bd9Sstevel@tonic-gate 	door_layout_t *layout = &st->d_layout;
11637c478bd9Sstevel@tonic-gate 	int error = 0;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	int is_private = (dp->door_flags & DOOR_PRIVATE);
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	door_pool_t *pool = (is_private)? &dp->door_servers :
11687c478bd9Sstevel@tonic-gate 	    &curproc->p_server_threads;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	int empty_pool = (pool->dp_threads == NULL);
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	caddr_t infop = NULL;
11737c478bd9Sstevel@tonic-gate 	char *datap = NULL;
11747c478bd9Sstevel@tonic-gate 	size_t datasize = 0;
11757c478bd9Sstevel@tonic-gate 	size_t descsize;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	file_t **fpp = ct->d_fpp;
11787c478bd9Sstevel@tonic-gate 	door_desc_t *start = NULL;
11797c478bd9Sstevel@tonic-gate 	uint_t ndesc = 0;
11807c478bd9Sstevel@tonic-gate 	uint_t ncopied = 0;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
11837c478bd9Sstevel@tonic-gate 		datap = ct->d_args.data_ptr;
11847c478bd9Sstevel@tonic-gate 		datasize = ct->d_args.data_size;
11857c478bd9Sstevel@tonic-gate 		ndesc = ct->d_args.desc_num;
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	descsize = ndesc * sizeof (door_desc_t);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	/*
11917c478bd9Sstevel@tonic-gate 	 * Reset datap to NULL if we aren't passing any data.  Be careful
11927c478bd9Sstevel@tonic-gate 	 * to let unref notifications through, though.
11937c478bd9Sstevel@tonic-gate 	 */
11947c478bd9Sstevel@tonic-gate 	if (datap == DOOR_UNREF_DATA) {
11957c478bd9Sstevel@tonic-gate 		if (ct->d_upcall)
11967c478bd9Sstevel@tonic-gate 			datasize = 0;
11977c478bd9Sstevel@tonic-gate 		else
11987c478bd9Sstevel@tonic-gate 			datap = NULL;
11997c478bd9Sstevel@tonic-gate 	} else if (datasize == 0) {
12007c478bd9Sstevel@tonic-gate 		datap = NULL;
12017c478bd9Sstevel@tonic-gate 	}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	/*
12047c478bd9Sstevel@tonic-gate 	 * Get the stack layout, if it hasn't already been done.
12057c478bd9Sstevel@tonic-gate 	 */
12067c478bd9Sstevel@tonic-gate 	if (!st->d_layout_done) {
12077c478bd9Sstevel@tonic-gate 		error = door_layout(curthread, datasize, ndesc,
12087c478bd9Sstevel@tonic-gate 		    (is_private && empty_pool));
12097c478bd9Sstevel@tonic-gate 		if (error != 0)
12107c478bd9Sstevel@tonic-gate 			goto fail;
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/*
12147c478bd9Sstevel@tonic-gate 	 * fill out the stack, starting from the top.  Layout was already
12157c478bd9Sstevel@tonic-gate 	 * filled in by door_args() or door_translate_out().
12167c478bd9Sstevel@tonic-gate 	 */
12177c478bd9Sstevel@tonic-gate 	if (layout->dl_descp != NULL) {
12187c478bd9Sstevel@tonic-gate 		ASSERT(ndesc != 0);
12197c478bd9Sstevel@tonic-gate 		start = kmem_alloc(descsize, KM_SLEEP);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		while (ndesc > 0) {
12227c478bd9Sstevel@tonic-gate 			if (door_insert(*fpp, &start[ncopied]) == -1) {
12237c478bd9Sstevel@tonic-gate 				error = EMFILE;
12247c478bd9Sstevel@tonic-gate 				goto fail;
12257c478bd9Sstevel@tonic-gate 			}
12267c478bd9Sstevel@tonic-gate 			ndesc--;
12277c478bd9Sstevel@tonic-gate 			ncopied++;
12287c478bd9Sstevel@tonic-gate 			fpp++;
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 		if (door_stack_copyout(start, layout->dl_descp, descsize)) {
12317c478bd9Sstevel@tonic-gate 			error = E2BIG;
12327c478bd9Sstevel@tonic-gate 			goto fail;
12337c478bd9Sstevel@tonic-gate 		}
12347c478bd9Sstevel@tonic-gate 	}
12357c478bd9Sstevel@tonic-gate 	fpp = NULL;			/* finished processing */
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	if (layout->dl_datap != NULL) {
12387c478bd9Sstevel@tonic-gate 		ASSERT(datasize != 0);
12397c478bd9Sstevel@tonic-gate 		datap = layout->dl_datap;
12407c478bd9Sstevel@tonic-gate 		if (ct->d_upcall || datasize <= door_max_arg) {
12417c478bd9Sstevel@tonic-gate 			if (door_stack_copyout(ct->d_buf, datap, datasize)) {
12427c478bd9Sstevel@tonic-gate 				error = E2BIG;
12437c478bd9Sstevel@tonic-gate 				goto fail;
12447c478bd9Sstevel@tonic-gate 			}
12457c478bd9Sstevel@tonic-gate 		}
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if (is_private && empty_pool) {
12497c478bd9Sstevel@tonic-gate 		door_info_t di;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		infop = layout->dl_infop;
12527c478bd9Sstevel@tonic-gate 		ASSERT(infop != NULL);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 		di.di_target = curproc->p_pid;
12557c478bd9Sstevel@tonic-gate 		di.di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
12567c478bd9Sstevel@tonic-gate 		di.di_data = (door_ptr_t)(uintptr_t)dp->door_data;
12577c478bd9Sstevel@tonic-gate 		di.di_uniquifier = dp->door_index;
12587c478bd9Sstevel@tonic-gate 		di.di_attributes = (dp->door_flags & DOOR_ATTR_MASK) |
12597c478bd9Sstevel@tonic-gate 		    DOOR_LOCAL;
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		if (copyout(&di, infop, sizeof (di))) {
12627c478bd9Sstevel@tonic-gate 			error = E2BIG;
12637c478bd9Sstevel@tonic-gate 			goto fail;
12647c478bd9Sstevel@tonic-gate 		}
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
12687c478bd9Sstevel@tonic-gate 		struct door_results dr;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		dr.cookie = dp->door_data;
12717c478bd9Sstevel@tonic-gate 		dr.data_ptr = datap;
12727c478bd9Sstevel@tonic-gate 		dr.data_size = datasize;
12737c478bd9Sstevel@tonic-gate 		dr.desc_ptr = (door_desc_t *)layout->dl_descp;
12747c478bd9Sstevel@tonic-gate 		dr.desc_num = ncopied;
12757c478bd9Sstevel@tonic-gate 		dr.pc = dp->door_pc;
12767c478bd9Sstevel@tonic-gate 		dr.nservers = !empty_pool;
12777c478bd9Sstevel@tonic-gate 		dr.door_info = (door_info_t *)infop;
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 		if (copyout(&dr, layout->dl_resultsp, sizeof (dr))) {
12807c478bd9Sstevel@tonic-gate 			error = E2BIG;
12817c478bd9Sstevel@tonic-gate 			goto fail;
12827c478bd9Sstevel@tonic-gate 		}
12837c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
12847c478bd9Sstevel@tonic-gate 	} else {
12857c478bd9Sstevel@tonic-gate 		struct door_results32 dr32;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		dr32.cookie = (caddr32_t)(uintptr_t)dp->door_data;
12887c478bd9Sstevel@tonic-gate 		dr32.data_ptr = (caddr32_t)(uintptr_t)datap;
12897c478bd9Sstevel@tonic-gate 		dr32.data_size = (size32_t)datasize;
12907c478bd9Sstevel@tonic-gate 		dr32.desc_ptr = (caddr32_t)(uintptr_t)layout->dl_descp;
12917c478bd9Sstevel@tonic-gate 		dr32.desc_num = ncopied;
12927c478bd9Sstevel@tonic-gate 		dr32.pc = (caddr32_t)(uintptr_t)dp->door_pc;
12937c478bd9Sstevel@tonic-gate 		dr32.nservers = !empty_pool;
12947c478bd9Sstevel@tonic-gate 		dr32.door_info = (caddr32_t)(uintptr_t)infop;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		if (copyout(&dr32, layout->dl_resultsp, sizeof (dr32))) {
12977c478bd9Sstevel@tonic-gate 			error = E2BIG;
12987c478bd9Sstevel@tonic-gate 			goto fail;
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate #endif
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	error = door_finish_dispatch(layout->dl_sp);
13047c478bd9Sstevel@tonic-gate fail:
13057c478bd9Sstevel@tonic-gate 	if (start != NULL) {
13067c478bd9Sstevel@tonic-gate 		if (error != 0)
13077c478bd9Sstevel@tonic-gate 			door_fd_close(start, ncopied);
13087c478bd9Sstevel@tonic-gate 		kmem_free(start, descsize);
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
13117c478bd9Sstevel@tonic-gate 		door_fp_close(fpp, ndesc);
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	return (error);
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate /*
13177c478bd9Sstevel@tonic-gate  * Return the results (if any) to the caller (if any) and wait for the
13187c478bd9Sstevel@tonic-gate  * next invocation on a door.
13197c478bd9Sstevel@tonic-gate  */
13207c478bd9Sstevel@tonic-gate int
13217c478bd9Sstevel@tonic-gate door_return(caddr_t data_ptr, size_t data_size,
13227c478bd9Sstevel@tonic-gate     door_desc_t *desc_ptr, uint_t desc_num, caddr_t sp, size_t ssize)
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate 	kthread_t	*caller;
13257c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
13267c478bd9Sstevel@tonic-gate 	int		error = 0;
13277c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
13287c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* curthread door_data */
13297c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* caller door_data */
1330*a574db85Sraf 	int		cancel_pending;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	st = door_my_server(1);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/*
13357c478bd9Sstevel@tonic-gate 	 * If thread was bound to a door that no longer exists, return
13367c478bd9Sstevel@tonic-gate 	 * an error.  This can happen if a thread is bound to a door
13377c478bd9Sstevel@tonic-gate 	 * before the process calls forkall(); in the child, the door
13387c478bd9Sstevel@tonic-gate 	 * doesn't exist and door_fork() sets the d_invbound flag.
13397c478bd9Sstevel@tonic-gate 	 */
13407c478bd9Sstevel@tonic-gate 	if (st->d_invbound)
13417c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	st->d_sp = sp;			/* Save base of stack. */
13447c478bd9Sstevel@tonic-gate 	st->d_ssize = ssize;		/* and its size */
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	/*
13477c478bd9Sstevel@tonic-gate 	 * before we release our stack to the whims of our next caller,
13487c478bd9Sstevel@tonic-gate 	 * copy in the syscall arguments if we're being traced by /proc.
13497c478bd9Sstevel@tonic-gate 	 */
13507c478bd9Sstevel@tonic-gate 	if (curthread->t_post_sys && PTOU(ttoproc(curthread))->u_systrap)
13517c478bd9Sstevel@tonic-gate 		(void) save_syscall_args();
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	/* Make sure the caller hasn't gone away */
13547c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
13557c478bd9Sstevel@tonic-gate 	if ((caller = st->d_caller) == NULL || caller->t_door == NULL) {
13567c478bd9Sstevel@tonic-gate 		if (desc_num != 0) {
13577c478bd9Sstevel@tonic-gate 			/* close any DOOR_RELEASE descriptors */
13587c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
13597c478bd9Sstevel@tonic-gate 			error = door_release_fds(desc_ptr, desc_num);
13607c478bd9Sstevel@tonic-gate 			if (error)
13617c478bd9Sstevel@tonic-gate 				return (set_errno(error));
13627c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
13637c478bd9Sstevel@tonic-gate 		}
13647c478bd9Sstevel@tonic-gate 		goto out;
13657c478bd9Sstevel@tonic-gate 	}
13667c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	ct->d_args.data_size = data_size;
13697c478bd9Sstevel@tonic-gate 	ct->d_args.desc_num = desc_num;
13707c478bd9Sstevel@tonic-gate 	/*
13717c478bd9Sstevel@tonic-gate 	 * Transfer results, if any, to the client
13727c478bd9Sstevel@tonic-gate 	 */
13737c478bd9Sstevel@tonic-gate 	if (data_size != 0 || desc_num != 0) {
13747c478bd9Sstevel@tonic-gate 		/*
13757c478bd9Sstevel@tonic-gate 		 * Prevent the client from exiting until we have finished
13767c478bd9Sstevel@tonic-gate 		 * moving results.
13777c478bd9Sstevel@tonic-gate 		 */
13787c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
13797c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
13807c478bd9Sstevel@tonic-gate 		error = door_results(caller, data_ptr, data_size,
13817c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num);
13827c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
13837c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
13847c478bd9Sstevel@tonic-gate 		/*
13857c478bd9Sstevel@tonic-gate 		 * Pass EOVERFLOW errors back to the client
13867c478bd9Sstevel@tonic-gate 		 */
13877c478bd9Sstevel@tonic-gate 		if (error && error != EOVERFLOW) {
13887c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
13897c478bd9Sstevel@tonic-gate 			return (set_errno(error));
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 	}
13927c478bd9Sstevel@tonic-gate out:
13937c478bd9Sstevel@tonic-gate 	/* Put ourselves on the available server thread list */
13947c478bd9Sstevel@tonic-gate 	door_release_server(st->d_pool, curthread);
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	/*
13977c478bd9Sstevel@tonic-gate 	 * Make sure the caller is still waiting to be resumed
13987c478bd9Sstevel@tonic-gate 	 */
13997c478bd9Sstevel@tonic-gate 	if (caller) {
14007c478bd9Sstevel@tonic-gate 		disp_lock_t *tlp;
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 		thread_lock(caller);
14037c478bd9Sstevel@tonic-gate 		ct->d_error = error;		/* Return any errors */
14047c478bd9Sstevel@tonic-gate 		if (caller->t_state == TS_SLEEP &&
14057c478bd9Sstevel@tonic-gate 		    SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) {
14067c478bd9Sstevel@tonic-gate 			cpu_t *cp = CPU;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 			tlp = caller->t_lockp;
14097c478bd9Sstevel@tonic-gate 			/*
14107c478bd9Sstevel@tonic-gate 			 * Setting t_disp_queue prevents erroneous preemptions
14117c478bd9Sstevel@tonic-gate 			 * if this thread is still in execution on another
14127c478bd9Sstevel@tonic-gate 			 * processor
14137c478bd9Sstevel@tonic-gate 			 */
14147c478bd9Sstevel@tonic-gate 			caller->t_disp_queue = cp->cpu_disp;
14157c478bd9Sstevel@tonic-gate 			CL_ACTIVE(caller);
14167c478bd9Sstevel@tonic-gate 			/*
14177c478bd9Sstevel@tonic-gate 			 * We are calling thread_onproc() instead of
14187c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC() because compiler can reorder
14197c478bd9Sstevel@tonic-gate 			 * the two stores of t_state and t_lockp in
14207c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC().
14217c478bd9Sstevel@tonic-gate 			 */
14227c478bd9Sstevel@tonic-gate 			thread_onproc(caller, cp);
14237c478bd9Sstevel@tonic-gate 			disp_lock_exit_high(tlp);
14247c478bd9Sstevel@tonic-gate 			shuttle_resume(caller, &door_knob);
14257c478bd9Sstevel@tonic-gate 		} else {
14267c478bd9Sstevel@tonic-gate 			/* May have been setrun or in stop state */
14277c478bd9Sstevel@tonic-gate 			thread_unlock(caller);
14287c478bd9Sstevel@tonic-gate 			shuttle_swtch(&door_knob);
14297c478bd9Sstevel@tonic-gate 		}
14307c478bd9Sstevel@tonic-gate 	} else {
14317c478bd9Sstevel@tonic-gate 		shuttle_swtch(&door_knob);
14327c478bd9Sstevel@tonic-gate 	}
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	/*
14357c478bd9Sstevel@tonic-gate 	 * We've sprung to life. Determine if we are part of a door
14367c478bd9Sstevel@tonic-gate 	 * invocation, or just interrupted
14377c478bd9Sstevel@tonic-gate 	 */
14387c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
14397c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
14407c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
14417c478bd9Sstevel@tonic-gate 		/*
14427c478bd9Sstevel@tonic-gate 		 * Normal door invocation. Return any error condition
14437c478bd9Sstevel@tonic-gate 		 * encountered while trying to pass args to the server
14447c478bd9Sstevel@tonic-gate 		 * thread.
14457c478bd9Sstevel@tonic-gate 		 */
14467c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
14477c478bd9Sstevel@tonic-gate 		/*
14487c478bd9Sstevel@tonic-gate 		 * Prevent the caller from leaving us while we
14497c478bd9Sstevel@tonic-gate 		 * are copying out the arguments from it's buffer.
14507c478bd9Sstevel@tonic-gate 		 */
14517c478bd9Sstevel@tonic-gate 		ASSERT(st->d_caller != NULL);
14527c478bd9Sstevel@tonic-gate 		ct = DOOR_CLIENT(st->d_caller->t_door);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
14557c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14567c478bd9Sstevel@tonic-gate 		error = door_server_dispatch(ct, dp);
14577c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14587c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 		if (error) {
14617c478bd9Sstevel@tonic-gate 			caller = st->d_caller;
14627c478bd9Sstevel@tonic-gate 			if (caller)
14637c478bd9Sstevel@tonic-gate 				ct = DOOR_CLIENT(caller->t_door);
14647c478bd9Sstevel@tonic-gate 			else
14657c478bd9Sstevel@tonic-gate 				ct = NULL;
14667c478bd9Sstevel@tonic-gate 			goto out;
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14697c478bd9Sstevel@tonic-gate 		return (0);
14707c478bd9Sstevel@tonic-gate 	} else {
14717c478bd9Sstevel@tonic-gate 		/*
14727c478bd9Sstevel@tonic-gate 		 * We are not involved in a door_invocation.
14737c478bd9Sstevel@tonic-gate 		 * Check for /proc related activity...
14747c478bd9Sstevel@tonic-gate 		 */
14757c478bd9Sstevel@tonic-gate 		st->d_caller = NULL;
1476c4ace179Sdm 		door_server_exit(curproc, curthread);
14777c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
1478*a574db85Sraf 		cancel_pending = 0;
1479*a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
1480*a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
1481*a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
1482*a574db85Sraf 			if (cancel_pending)
1483*a574db85Sraf 				schedctl_cancel_eintr();
14847c478bd9Sstevel@tonic-gate 			lwp->lwp_asleep = 0;
14857c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
14867c478bd9Sstevel@tonic-gate 			return (set_errno(EINTR));
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 		/* Go back and wait for another request */
14897c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
14907c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14917c478bd9Sstevel@tonic-gate 		caller = NULL;
14927c478bd9Sstevel@tonic-gate 		goto out;
14937c478bd9Sstevel@tonic-gate 	}
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate /*
14977c478bd9Sstevel@tonic-gate  * Revoke any future invocations on this door
14987c478bd9Sstevel@tonic-gate  */
14997c478bd9Sstevel@tonic-gate int
15007c478bd9Sstevel@tonic-gate door_revoke(int did)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	door_node_t	*d;
15037c478bd9Sstevel@tonic-gate 	int		error;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	if ((d = door_lookup(did, NULL)) == NULL)
15067c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
15097c478bd9Sstevel@tonic-gate 	if (d->door_target != curproc) {
15107c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
15117c478bd9Sstevel@tonic-gate 		releasef(did);
15127c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
15137c478bd9Sstevel@tonic-gate 	}
15147c478bd9Sstevel@tonic-gate 	d->door_flags |= DOOR_REVOKED;
15157c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_PRIVATE)
15167c478bd9Sstevel@tonic-gate 		cv_broadcast(&d->door_servers.dp_cv);
15177c478bd9Sstevel@tonic-gate 	else
15187c478bd9Sstevel@tonic-gate 		cv_broadcast(&curproc->p_server_threads.dp_cv);
15197c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
15207c478bd9Sstevel@tonic-gate 	releasef(did);
15217c478bd9Sstevel@tonic-gate 	/* Invalidate the descriptor */
15227c478bd9Sstevel@tonic-gate 	if ((error = closeandsetf(did, NULL)) != 0)
15237c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15247c478bd9Sstevel@tonic-gate 	return (0);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate int
15287c478bd9Sstevel@tonic-gate door_info(int did, struct door_info *d_info)
15297c478bd9Sstevel@tonic-gate {
15307c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
15317c478bd9Sstevel@tonic-gate 	door_info_t	di;
15327c478bd9Sstevel@tonic-gate 	door_server_t	*st;
15337c478bd9Sstevel@tonic-gate 	file_t		*fp = NULL;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	if (did == DOOR_QUERY) {
15367c478bd9Sstevel@tonic-gate 		/* Get information on door current thread is bound to */
15377c478bd9Sstevel@tonic-gate 		if ((st = door_my_server(0)) == NULL ||
15387c478bd9Sstevel@tonic-gate 		    (dp = st->d_pool) == NULL)
15397c478bd9Sstevel@tonic-gate 			/* Thread isn't bound to a door */
15407c478bd9Sstevel@tonic-gate 			return (set_errno(EBADF));
15417c478bd9Sstevel@tonic-gate 	} else if ((dp = door_lookup(did, &fp)) == NULL) {
15427c478bd9Sstevel@tonic-gate 		/* Not a door */
15437c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15447c478bd9Sstevel@tonic-gate 	}
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	door_info_common(dp, &di, fp);
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	if (did != DOOR_QUERY)
15497c478bd9Sstevel@tonic-gate 		releasef(did);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	if (copyout(&di, d_info, sizeof (struct door_info)))
15527c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
15537c478bd9Sstevel@tonic-gate 	return (0);
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate /*
15577c478bd9Sstevel@tonic-gate  * Common code for getting information about a door either via the
15587c478bd9Sstevel@tonic-gate  * door_info system call or the door_ki_info kernel call.
15597c478bd9Sstevel@tonic-gate  */
15607c478bd9Sstevel@tonic-gate void
15617c478bd9Sstevel@tonic-gate door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	int unref_count;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	bzero(dip, sizeof (door_info_t));
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
15687c478bd9Sstevel@tonic-gate 	if (dp->door_target == NULL)
15697c478bd9Sstevel@tonic-gate 		dip->di_target = -1;
15707c478bd9Sstevel@tonic-gate 	else
15717c478bd9Sstevel@tonic-gate 		dip->di_target = dp->door_target->p_pid;
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK;
15747c478bd9Sstevel@tonic-gate 	if (dp->door_target == curproc)
15757c478bd9Sstevel@tonic-gate 		dip->di_attributes |= DOOR_LOCAL;
15767c478bd9Sstevel@tonic-gate 	dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
15777c478bd9Sstevel@tonic-gate 	dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data;
15787c478bd9Sstevel@tonic-gate 	dip->di_uniquifier = dp->door_index;
15797c478bd9Sstevel@tonic-gate 	/*
15807c478bd9Sstevel@tonic-gate 	 * If this door is in the middle of having an unreferenced
15817c478bd9Sstevel@tonic-gate 	 * notification delivered, don't count the VN_HOLD by
15827c478bd9Sstevel@tonic-gate 	 * door_deliver_unref in determining if it is unreferenced.
15837c478bd9Sstevel@tonic-gate 	 * This handles the case where door_info is called from the
15847c478bd9Sstevel@tonic-gate 	 * thread delivering the unref notification.
15857c478bd9Sstevel@tonic-gate 	 */
15867c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_UNREF_ACTIVE)
15877c478bd9Sstevel@tonic-gate 		unref_count = 2;
15887c478bd9Sstevel@tonic-gate 	else
15897c478bd9Sstevel@tonic-gate 		unref_count = 1;
15907c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
15937c478bd9Sstevel@tonic-gate 		/*
15947c478bd9Sstevel@tonic-gate 		 * If this thread is bound to the door, then we can just
15957c478bd9Sstevel@tonic-gate 		 * check the vnode; a ref count of 1 (or 2 if this is
15967c478bd9Sstevel@tonic-gate 		 * handling an unref notification) means that the hold
15977c478bd9Sstevel@tonic-gate 		 * from the door_bind is the only reference to the door
15987c478bd9Sstevel@tonic-gate 		 * (no file descriptor refers to it).
15997c478bd9Sstevel@tonic-gate 		 */
16007c478bd9Sstevel@tonic-gate 		if (DTOV(dp)->v_count == unref_count)
16017c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16027c478bd9Sstevel@tonic-gate 	} else {
16037c478bd9Sstevel@tonic-gate 		/*
16047c478bd9Sstevel@tonic-gate 		 * If we're working from a file descriptor or door handle
16057c478bd9Sstevel@tonic-gate 		 * we need to look at the file structure count.  We don't
16067c478bd9Sstevel@tonic-gate 		 * need to hold the vnode lock since this is just a snapshot.
16077c478bd9Sstevel@tonic-gate 		 */
16087c478bd9Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
16097c478bd9Sstevel@tonic-gate 		if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count)
16107c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16117c478bd9Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
16127c478bd9Sstevel@tonic-gate 	}
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate /*
16167c478bd9Sstevel@tonic-gate  * Return credentials of the door caller (if any) for this invocation
16177c478bd9Sstevel@tonic-gate  */
16187c478bd9Sstevel@tonic-gate int
16197c478bd9Sstevel@tonic-gate door_ucred(struct ucred_s *uch)
16207c478bd9Sstevel@tonic-gate {
16217c478bd9Sstevel@tonic-gate 	kthread_t	*caller;
16227c478bd9Sstevel@tonic-gate 	door_server_t	*st;
16237c478bd9Sstevel@tonic-gate 	door_client_t	*ct;
16247c478bd9Sstevel@tonic-gate 	struct proc	*p;
16257c478bd9Sstevel@tonic-gate 	struct ucred_s	*res;
16267c478bd9Sstevel@tonic-gate 	int		err;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16297c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL ||
16307c478bd9Sstevel@tonic-gate 	    (caller = st->d_caller) == NULL) {
16317c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
16327c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
16337c478bd9Sstevel@tonic-gate 	}
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	ASSERT(caller->t_door != NULL);
16367c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	/* Prevent caller from exiting while we examine the cred */
16397c478bd9Sstevel@tonic-gate 	DOOR_T_HOLD(ct);
16407c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/* Get the credentials of the calling process */
16437c478bd9Sstevel@tonic-gate 	p = ttoproc(caller);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	res = pgetucred(p);
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16487c478bd9Sstevel@tonic-gate 	DOOR_T_RELEASE(ct);
16497c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	err = copyout(res, uch, res->uc_size);
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	kmem_free(res, res->uc_size);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if (err != 0)
16567c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	return (0);
16597c478bd9Sstevel@tonic-gate }
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate /*
16627c478bd9Sstevel@tonic-gate  * Bind the current lwp to the server thread pool associated with 'did'
16637c478bd9Sstevel@tonic-gate  */
16647c478bd9Sstevel@tonic-gate int
16657c478bd9Sstevel@tonic-gate door_bind(int did)
16667c478bd9Sstevel@tonic-gate {
16677c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
16687c478bd9Sstevel@tonic-gate 	door_server_t	*st;
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL) {
16717c478bd9Sstevel@tonic-gate 		/* Not a door */
16727c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	/*
16767c478bd9Sstevel@tonic-gate 	 * Can't bind to a non-private door, and can't bind to a door
16777c478bd9Sstevel@tonic-gate 	 * served by another process.
16787c478bd9Sstevel@tonic-gate 	 */
16797c478bd9Sstevel@tonic-gate 	if ((dp->door_flags & DOOR_PRIVATE) == 0 ||
16807c478bd9Sstevel@tonic-gate 	    dp->door_target != curproc) {
16817c478bd9Sstevel@tonic-gate 		releasef(did);
16827c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
16837c478bd9Sstevel@tonic-gate 	}
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	st = door_my_server(1);
16867c478bd9Sstevel@tonic-gate 	if (st->d_pool)
16877c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);
16887c478bd9Sstevel@tonic-gate 	st->d_pool = dp;
16897c478bd9Sstevel@tonic-gate 	st->d_invbound = 0;
16907c478bd9Sstevel@tonic-gate 	door_bind_thread(dp);
16917c478bd9Sstevel@tonic-gate 	releasef(did);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	return (0);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate  * Unbind the current lwp from it's server thread pool
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate int
17007c478bd9Sstevel@tonic-gate door_unbind(void)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	door_server_t *st;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL)
17057c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	if (st->d_invbound) {
17087c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool == NULL);
17097c478bd9Sstevel@tonic-gate 		st->d_invbound = 0;
17107c478bd9Sstevel@tonic-gate 		return (0);
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 	if (st->d_pool == NULL)
17137c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17147c478bd9Sstevel@tonic-gate 	door_unbind_thread(st->d_pool);
17157c478bd9Sstevel@tonic-gate 	st->d_pool = NULL;
17167c478bd9Sstevel@tonic-gate 	return (0);
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate /*
17207c478bd9Sstevel@tonic-gate  * Create a descriptor for the associated file and fill in the
17217c478bd9Sstevel@tonic-gate  * attributes associated with it.
17227c478bd9Sstevel@tonic-gate  *
17237c478bd9Sstevel@tonic-gate  * Return 0 for success, -1 otherwise;
17247c478bd9Sstevel@tonic-gate  */
17257c478bd9Sstevel@tonic-gate int
17267c478bd9Sstevel@tonic-gate door_insert(struct file *fp, door_desc_t *dp)
17277c478bd9Sstevel@tonic-gate {
17287c478bd9Sstevel@tonic-gate 	struct vnode *vp;
17297c478bd9Sstevel@tonic-gate 	int	fd;
17307c478bd9Sstevel@tonic-gate 	door_attr_t attributes = DOOR_DESCRIPTOR;
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
17337c478bd9Sstevel@tonic-gate 	if ((fd = ufalloc(0)) == -1)
17347c478bd9Sstevel@tonic-gate 		return (-1);
17357c478bd9Sstevel@tonic-gate 	setf(fd, fp);
17367c478bd9Sstevel@tonic-gate 	dp->d_data.d_desc.d_descriptor = fd;
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	/* Fill in the attributes */
1739da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
17407c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
17417c478bd9Sstevel@tonic-gate 	if (vp && vp->v_type == VDOOR) {
17427c478bd9Sstevel@tonic-gate 		if (VTOD(vp)->door_target == curproc)
17437c478bd9Sstevel@tonic-gate 			attributes |= DOOR_LOCAL;
17447c478bd9Sstevel@tonic-gate 		attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK;
17457c478bd9Sstevel@tonic-gate 		dp->d_data.d_desc.d_id = VTOD(vp)->door_index;
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 	dp->d_attributes = attributes;
17487c478bd9Sstevel@tonic-gate 	return (0);
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate /*
17527c478bd9Sstevel@tonic-gate  * Return an available thread for this server.  A NULL return value indicates
17537c478bd9Sstevel@tonic-gate  * that either:
17547c478bd9Sstevel@tonic-gate  *	The door has been revoked, or
17557c478bd9Sstevel@tonic-gate  *	a signal was received.
17567c478bd9Sstevel@tonic-gate  * The two conditions can be differentiated using DOOR_INVALID(dp).
17577c478bd9Sstevel@tonic-gate  */
17587c478bd9Sstevel@tonic-gate static kthread_t *
17597c478bd9Sstevel@tonic-gate door_get_server(door_node_t *dp)
17607c478bd9Sstevel@tonic-gate {
17617c478bd9Sstevel@tonic-gate 	kthread_t **ktp;
17627c478bd9Sstevel@tonic-gate 	kthread_t *server_t;
17637c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
17647c478bd9Sstevel@tonic-gate 	door_server_t *st;
17657c478bd9Sstevel@tonic-gate 	int signalled;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	disp_lock_t *tlp;
17687c478bd9Sstevel@tonic-gate 	cpu_t *cp;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_PRIVATE)
17737c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
17747c478bd9Sstevel@tonic-gate 	else
17757c478bd9Sstevel@tonic-gate 		pool = &dp->door_target->p_server_threads;
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	for (;;) {
17787c478bd9Sstevel@tonic-gate 		/*
17797c478bd9Sstevel@tonic-gate 		 * We search the thread pool, looking for a server thread
17807c478bd9Sstevel@tonic-gate 		 * ready to take an invocation (i.e. one which is still
17817c478bd9Sstevel@tonic-gate 		 * sleeping on a shuttle object).  If none are available,
17827c478bd9Sstevel@tonic-gate 		 * we sleep on the pool's CV, and will be signaled when a
17837c478bd9Sstevel@tonic-gate 		 * thread is added to the pool.
17847c478bd9Sstevel@tonic-gate 		 *
17857c478bd9Sstevel@tonic-gate 		 * This relies on the fact that once a thread in the thread
17867c478bd9Sstevel@tonic-gate 		 * pool wakes up, it *must* remove and add itself to the pool
17877c478bd9Sstevel@tonic-gate 		 * before it can receive door calls.
17887c478bd9Sstevel@tonic-gate 		 */
17897c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
17907c478bd9Sstevel@tonic-gate 			return (NULL);	/* Target has become invalid */
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 		for (ktp = &pool->dp_threads;
17937c478bd9Sstevel@tonic-gate 		    (server_t = *ktp) != NULL;
17947c478bd9Sstevel@tonic-gate 		    ktp = &st->d_servers) {
17957c478bd9Sstevel@tonic-gate 			st = DOOR_SERVER(server_t->t_door);
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 			thread_lock(server_t);
17987c478bd9Sstevel@tonic-gate 			if (server_t->t_state == TS_SLEEP &&
17997c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE)
18007c478bd9Sstevel@tonic-gate 				break;
18017c478bd9Sstevel@tonic-gate 			thread_unlock(server_t);
18027c478bd9Sstevel@tonic-gate 		}
18037c478bd9Sstevel@tonic-gate 		if (server_t != NULL)
18047c478bd9Sstevel@tonic-gate 			break;		/* we've got a live one! */
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
18077c478bd9Sstevel@tonic-gate 		    &signalled)) {
18087c478bd9Sstevel@tonic-gate 			/*
1809da6c28aaSamw 			 * If we were signaled and the door is still
18107c478bd9Sstevel@tonic-gate 			 * valid, pass the signal on to another waiter.
18117c478bd9Sstevel@tonic-gate 			 */
18127c478bd9Sstevel@tonic-gate 			if (signalled && !DOOR_INVALID(dp))
18137c478bd9Sstevel@tonic-gate 				cv_signal(&pool->dp_cv);
18147c478bd9Sstevel@tonic-gate 			return (NULL);	/* Got a signal */
18157c478bd9Sstevel@tonic-gate 		}
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	/*
18197c478bd9Sstevel@tonic-gate 	 * We've got a thread_lock()ed thread which is still on the
18207c478bd9Sstevel@tonic-gate 	 * shuttle.  Take it off the list of available server threads
18217c478bd9Sstevel@tonic-gate 	 * and mark it as ONPROC.  We are committed to resuming this
18227c478bd9Sstevel@tonic-gate 	 * thread now.
18237c478bd9Sstevel@tonic-gate 	 */
18247c478bd9Sstevel@tonic-gate 	tlp = server_t->t_lockp;
18257c478bd9Sstevel@tonic-gate 	cp = CPU;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	*ktp = st->d_servers;
18287c478bd9Sstevel@tonic-gate 	st->d_servers = NULL;
18297c478bd9Sstevel@tonic-gate 	/*
18307c478bd9Sstevel@tonic-gate 	 * Setting t_disp_queue prevents erroneous preemptions
18317c478bd9Sstevel@tonic-gate 	 * if this thread is still in execution on another processor
18327c478bd9Sstevel@tonic-gate 	 */
18337c478bd9Sstevel@tonic-gate 	server_t->t_disp_queue = cp->cpu_disp;
18347c478bd9Sstevel@tonic-gate 	CL_ACTIVE(server_t);
18357c478bd9Sstevel@tonic-gate 	/*
18367c478bd9Sstevel@tonic-gate 	 * We are calling thread_onproc() instead of
18377c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC() because compiler can reorder
18387c478bd9Sstevel@tonic-gate 	 * the two stores of t_state and t_lockp in
18397c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC().
18407c478bd9Sstevel@tonic-gate 	 */
18417c478bd9Sstevel@tonic-gate 	thread_onproc(server_t, cp);
18427c478bd9Sstevel@tonic-gate 	disp_lock_exit(tlp);
18437c478bd9Sstevel@tonic-gate 	return (server_t);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate /*
18477c478bd9Sstevel@tonic-gate  * Put a server thread back in the pool.
18487c478bd9Sstevel@tonic-gate  */
18497c478bd9Sstevel@tonic-gate static void
18507c478bd9Sstevel@tonic-gate door_release_server(door_node_t *dp, kthread_t *t)
18517c478bd9Sstevel@tonic-gate {
18527c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
18537c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
18567c478bd9Sstevel@tonic-gate 	st->d_active = NULL;
18577c478bd9Sstevel@tonic-gate 	st->d_caller = NULL;
18587c478bd9Sstevel@tonic-gate 	st->d_layout_done = 0;
18597c478bd9Sstevel@tonic-gate 	if (dp && (dp->door_flags & DOOR_PRIVATE)) {
18607c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == NULL ||
18617c478bd9Sstevel@tonic-gate 		    dp->door_target == ttoproc(t));
18627c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
18637c478bd9Sstevel@tonic-gate 	} else {
18647c478bd9Sstevel@tonic-gate 		pool = &ttoproc(t)->p_server_threads;
18657c478bd9Sstevel@tonic-gate 	}
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 	st->d_servers = pool->dp_threads;
18687c478bd9Sstevel@tonic-gate 	pool->dp_threads = t;
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	/* If someone is waiting for a server thread, wake him up */
18717c478bd9Sstevel@tonic-gate 	cv_signal(&pool->dp_cv);
18727c478bd9Sstevel@tonic-gate }
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate /*
18757c478bd9Sstevel@tonic-gate  * Remove a server thread from the pool if present.
18767c478bd9Sstevel@tonic-gate  */
1877c4ace179Sdm static void
18787c478bd9Sstevel@tonic-gate door_server_exit(proc_t *p, kthread_t *t)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
18817c478bd9Sstevel@tonic-gate 	kthread_t **next;
18827c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
18857c478bd9Sstevel@tonic-gate 	if (st->d_pool != NULL) {
18867c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool->door_flags & DOOR_PRIVATE);
18877c478bd9Sstevel@tonic-gate 		pool = &st->d_pool->door_servers;
18887c478bd9Sstevel@tonic-gate 	} else {
18897c478bd9Sstevel@tonic-gate 		pool = &p->p_server_threads;
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	next = &pool->dp_threads;
18937c478bd9Sstevel@tonic-gate 	while (*next != NULL) {
18947c478bd9Sstevel@tonic-gate 		if (*next == t) {
18957c478bd9Sstevel@tonic-gate 			*next = DOOR_SERVER(t->t_door)->d_servers;
1896c4ace179Sdm 			return;
18977c478bd9Sstevel@tonic-gate 		}
18987c478bd9Sstevel@tonic-gate 		next = &(DOOR_SERVER((*next)->t_door)->d_servers);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate /*
19037c478bd9Sstevel@tonic-gate  * Lookup the door descriptor. Caller must call releasef when finished
19047c478bd9Sstevel@tonic-gate  * with associated door.
19057c478bd9Sstevel@tonic-gate  */
19067c478bd9Sstevel@tonic-gate static door_node_t *
19077c478bd9Sstevel@tonic-gate door_lookup(int did, file_t **fpp)
19087c478bd9Sstevel@tonic-gate {
19097c478bd9Sstevel@tonic-gate 	vnode_t	*vp;
19107c478bd9Sstevel@tonic-gate 	file_t *fp;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
19137c478bd9Sstevel@tonic-gate 	if ((fp = getf(did)) == NULL)
19147c478bd9Sstevel@tonic-gate 		return (NULL);
19157c478bd9Sstevel@tonic-gate 	/*
19167c478bd9Sstevel@tonic-gate 	 * Use the underlying vnode (we may be namefs mounted)
19177c478bd9Sstevel@tonic-gate 	 */
1918da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
19197c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_type != VDOOR) {
19227c478bd9Sstevel@tonic-gate 		releasef(did);
19237c478bd9Sstevel@tonic-gate 		return (NULL);
19247c478bd9Sstevel@tonic-gate 	}
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	if (fpp)
19277c478bd9Sstevel@tonic-gate 		*fpp = fp;
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	return (VTOD(vp));
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate /*
19337c478bd9Sstevel@tonic-gate  * The current thread is exiting, so clean up any pending
19347c478bd9Sstevel@tonic-gate  * invocation details
19357c478bd9Sstevel@tonic-gate  */
19367c478bd9Sstevel@tonic-gate void
19377c478bd9Sstevel@tonic-gate door_slam(void)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate 	door_node_t *dp;
19407c478bd9Sstevel@tonic-gate 	door_data_t *dt;
19417c478bd9Sstevel@tonic-gate 	door_client_t *ct;
19427c478bd9Sstevel@tonic-gate 	door_server_t *st;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	/*
19457c478bd9Sstevel@tonic-gate 	 * If we are an active door server, notify our
19467c478bd9Sstevel@tonic-gate 	 * client that we are exiting and revoke our door.
19477c478bd9Sstevel@tonic-gate 	 */
19487c478bd9Sstevel@tonic-gate 	if ((dt = door_my_data(0)) == NULL)
19497c478bd9Sstevel@tonic-gate 		return;
19507c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(dt);
19517c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(dt);
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
19547c478bd9Sstevel@tonic-gate 	for (;;) {
19557c478bd9Sstevel@tonic-gate 		if (DOOR_T_HELD(ct))
19567c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
19577c478bd9Sstevel@tonic-gate 		else if (DOOR_T_HELD(st))
19587c478bd9Sstevel@tonic-gate 			cv_wait(&st->d_cv, &door_knob);
19597c478bd9Sstevel@tonic-gate 		else
19607c478bd9Sstevel@tonic-gate 			break;			/* neither flag is set */
19617c478bd9Sstevel@tonic-gate 	}
19627c478bd9Sstevel@tonic-gate 	curthread->t_door = NULL;
19637c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
19647c478bd9Sstevel@tonic-gate 		kthread_t *t = st->d_caller;
19657c478bd9Sstevel@tonic-gate 		proc_t *p = curproc;
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 		/* Revoke our door if the process is exiting */
196897eda132Sraf 		if (dp->door_target == p && (p->p_flag & SEXITING)) {
19697c478bd9Sstevel@tonic-gate 			door_list_delete(dp);
19707c478bd9Sstevel@tonic-gate 			dp->door_target = NULL;
19717c478bd9Sstevel@tonic-gate 			dp->door_flags |= DOOR_REVOKED;
19727c478bd9Sstevel@tonic-gate 			if (dp->door_flags & DOOR_PRIVATE)
19737c478bd9Sstevel@tonic-gate 				cv_broadcast(&dp->door_servers.dp_cv);
19747c478bd9Sstevel@tonic-gate 			else
19757c478bd9Sstevel@tonic-gate 				cv_broadcast(&p->p_server_threads.dp_cv);
19767c478bd9Sstevel@tonic-gate 		}
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 		if (t != NULL) {
19797c478bd9Sstevel@tonic-gate 			/*
19807c478bd9Sstevel@tonic-gate 			 * Let the caller know we are gone
19817c478bd9Sstevel@tonic-gate 			 */
19827c478bd9Sstevel@tonic-gate 			DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT;
19837c478bd9Sstevel@tonic-gate 			thread_lock(t);
19847c478bd9Sstevel@tonic-gate 			if (t->t_state == TS_SLEEP &&
19857c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE)
19867c478bd9Sstevel@tonic-gate 				setrun_locked(t);
19877c478bd9Sstevel@tonic-gate 			thread_unlock(t);
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 	}
19907c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
19917c478bd9Sstevel@tonic-gate 	if (st->d_pool)
19927c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);	/* Implicit door_unbind */
19937c478bd9Sstevel@tonic-gate 	kmem_free(dt, sizeof (door_data_t));
19947c478bd9Sstevel@tonic-gate }
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate /*
19977c478bd9Sstevel@tonic-gate  * Set DOOR_REVOKED for all doors of the current process. This is called
19987c478bd9Sstevel@tonic-gate  * on exit before all lwp's are being terminated so that door calls will
19997c478bd9Sstevel@tonic-gate  * return with an error.
20007c478bd9Sstevel@tonic-gate  */
20017c478bd9Sstevel@tonic-gate void
20027c478bd9Sstevel@tonic-gate door_revoke_all()
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20057c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20087c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20097c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == p);
20107c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20117c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20127c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20137c478bd9Sstevel@tonic-gate 	}
20147c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20157c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate /*
20197c478bd9Sstevel@tonic-gate  * The process is exiting, and all doors it created need to be revoked.
20207c478bd9Sstevel@tonic-gate  */
20217c478bd9Sstevel@tonic-gate void
20227c478bd9Sstevel@tonic-gate door_exit(void)
20237c478bd9Sstevel@tonic-gate {
20247c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20257c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1);
20287c478bd9Sstevel@tonic-gate 	/*
20297c478bd9Sstevel@tonic-gate 	 * Walk the list of active doors created by this process and
20307c478bd9Sstevel@tonic-gate 	 * revoke them all.
20317c478bd9Sstevel@tonic-gate 	 */
20327c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20337c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20347c478bd9Sstevel@tonic-gate 		dp->door_target = NULL;
20357c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20367c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20377c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20407c478bd9Sstevel@tonic-gate 	/* Clear the list */
20417c478bd9Sstevel@tonic-gate 	p->p_door_list = NULL;
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 	/* Clean up the unref list */
20447c478bd9Sstevel@tonic-gate 	while ((dp = p->p_unref_list) != NULL) {
20457c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
20467c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
20477c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
20487c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
20497c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
20507c478bd9Sstevel@tonic-gate 	}
20517c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate /*
20567c478bd9Sstevel@tonic-gate  * The process is executing forkall(), and we need to flag threads that
20577c478bd9Sstevel@tonic-gate  * are bound to a door in the child.  This will make the child threads
20587c478bd9Sstevel@tonic-gate  * return an error to door_return unless they call door_unbind first.
20597c478bd9Sstevel@tonic-gate  */
20607c478bd9Sstevel@tonic-gate void
20617c478bd9Sstevel@tonic-gate door_fork(kthread_t *parent, kthread_t *child)
20627c478bd9Sstevel@tonic-gate {
20637c478bd9Sstevel@tonic-gate 	door_data_t *pt = parent->t_door;
20647c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(pt);
20657c478bd9Sstevel@tonic-gate 	door_data_t *dt;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
20687c478bd9Sstevel@tonic-gate 	if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) {
20697c478bd9Sstevel@tonic-gate 		/* parent thread is bound to a door */
20707c478bd9Sstevel@tonic-gate 		dt = child->t_door =
20717c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sizeof (door_data_t), KM_SLEEP);
20727c478bd9Sstevel@tonic-gate 		DOOR_SERVER(dt)->d_invbound = 1;
20737c478bd9Sstevel@tonic-gate 	}
20747c478bd9Sstevel@tonic-gate }
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate /*
20777c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to appropriate door server.
20787c478bd9Sstevel@tonic-gate  */
20797c478bd9Sstevel@tonic-gate static int
20807c478bd9Sstevel@tonic-gate door_unref(void)
20817c478bd9Sstevel@tonic-gate {
20827c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
20837c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
20847c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	/* make sure there's only one unref thread per process */
20877c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20887c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
20897c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
20907c478bd9Sstevel@tonic-gate 		return (set_errno(EALREADY));
20917c478bd9Sstevel@tonic-gate 	}
20927c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
20937c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);			/* create info, if necessary */
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	for (;;) {
20987c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
21017c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
21027c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) {
21037c478bd9Sstevel@tonic-gate 				/*
21047c478bd9Sstevel@tonic-gate 				 * Interrupted.
21057c478bd9Sstevel@tonic-gate 				 * Return so we can finish forkall() or exit().
21067c478bd9Sstevel@tonic-gate 				 */
21077c478bd9Sstevel@tonic-gate 				p->p_unref_thread = 0;
21087c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
21097c478bd9Sstevel@tonic-gate 				return (set_errno(EINTR));
21107c478bd9Sstevel@tonic-gate 			}
21117c478bd9Sstevel@tonic-gate 		}
21127c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
21137c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
21147c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
21157c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 		(void) door_upcall(DTOV(dp), &unref_args);
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21207c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
21217c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
21227c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21237c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate /*
21297c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to kernel door server.
21307c478bd9Sstevel@tonic-gate  */
21317c478bd9Sstevel@tonic-gate /* ARGSUSED */
21327c478bd9Sstevel@tonic-gate static void
21337c478bd9Sstevel@tonic-gate door_unref_kernel(caddr_t arg)
21347c478bd9Sstevel@tonic-gate {
21357c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
21367c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
21377c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
21387c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	/* should only be one of these */
21417c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
21427c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
21437c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21447c478bd9Sstevel@tonic-gate 		return;
21457c478bd9Sstevel@tonic-gate 	}
21467c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
21477c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);		/* make sure we have a door_data_t */
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref");
21527c478bd9Sstevel@tonic-gate 	for (;;) {
21537c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21547c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
21557c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
21567c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
21577c478bd9Sstevel@tonic-gate 			cv_wait(&p->p_unref_cv, &door_knob);
21587c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &door_knob);
21597c478bd9Sstevel@tonic-gate 		}
21607c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
21617c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
21627c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
21637c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL);
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21687c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
21697c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
21707c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21717c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
21727c478bd9Sstevel@tonic-gate 	}
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate /*
21777c478bd9Sstevel@tonic-gate  * Queue an unref invocation for processing for the current process
21787c478bd9Sstevel@tonic-gate  * The door may or may not be revoked at this point.
21797c478bd9Sstevel@tonic-gate  */
21807c478bd9Sstevel@tonic-gate void
21817c478bd9Sstevel@tonic-gate door_deliver_unref(door_node_t *d)
21827c478bd9Sstevel@tonic-gate {
21837c478bd9Sstevel@tonic-gate 	struct proc *server = d->door_target;
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
21867c478bd9Sstevel@tonic-gate 	ASSERT(d->door_active == 0);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	if (server == NULL)
21897c478bd9Sstevel@tonic-gate 		return;
21907c478bd9Sstevel@tonic-gate 	/*
21917c478bd9Sstevel@tonic-gate 	 * Create a lwp to deliver unref calls if one isn't already running.
21927c478bd9Sstevel@tonic-gate 	 *
21937c478bd9Sstevel@tonic-gate 	 * A separate thread is used to deliver unrefs since the current
21947c478bd9Sstevel@tonic-gate 	 * thread may be holding resources (e.g. locks) in user land that
21957c478bd9Sstevel@tonic-gate 	 * may be needed by the unref processing. This would cause a
21967c478bd9Sstevel@tonic-gate 	 * deadlock.
21977c478bd9Sstevel@tonic-gate 	 */
21987c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
21997c478bd9Sstevel@tonic-gate 		/* multiple unrefs */
22007c478bd9Sstevel@tonic-gate 		d->door_flags &= ~DOOR_DELAY;
22017c478bd9Sstevel@tonic-gate 	} else {
22027c478bd9Sstevel@tonic-gate 		/* Only 1 unref per door */
22037c478bd9Sstevel@tonic-gate 		d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY);
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	/*
22087c478bd9Sstevel@tonic-gate 	 * Need to bump the vnode count before putting the door on the
22097c478bd9Sstevel@tonic-gate 	 * list so it doesn't get prematurely released by door_unref.
22107c478bd9Sstevel@tonic-gate 	 */
22117c478bd9Sstevel@tonic-gate 	VN_HOLD(DTOV(d));
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
22147c478bd9Sstevel@tonic-gate 	/* is this door already on the unref list? */
22157c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
22167c478bd9Sstevel@tonic-gate 		door_node_t *dp;
22177c478bd9Sstevel@tonic-gate 		for (dp = server->p_unref_list; dp != NULL;
22187c478bd9Sstevel@tonic-gate 		    dp = dp->door_ulist) {
22197c478bd9Sstevel@tonic-gate 			if (d == dp) {
22207c478bd9Sstevel@tonic-gate 				/* already there, don't need to add another */
22217c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
22227c478bd9Sstevel@tonic-gate 				VN_RELE(DTOV(d));
22237c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
22247c478bd9Sstevel@tonic-gate 				return;
22257c478bd9Sstevel@tonic-gate 			}
22267c478bd9Sstevel@tonic-gate 		}
22277c478bd9Sstevel@tonic-gate 	}
22287c478bd9Sstevel@tonic-gate 	ASSERT(d->door_ulist == NULL);
22297c478bd9Sstevel@tonic-gate 	d->door_ulist = server->p_unref_list;
22307c478bd9Sstevel@tonic-gate 	server->p_unref_list = d;
22317c478bd9Sstevel@tonic-gate 	cv_broadcast(&server->p_unref_cv);
22327c478bd9Sstevel@tonic-gate }
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate /*
22357c478bd9Sstevel@tonic-gate  * The callers buffer isn't big enough for all of the data/fd's. Allocate
22367c478bd9Sstevel@tonic-gate  * space in the callers address space for the results and copy the data
22377c478bd9Sstevel@tonic-gate  * there.
22387c478bd9Sstevel@tonic-gate  *
22397c478bd9Sstevel@tonic-gate  * For EOVERFLOW, we must clean up the server's door descriptors.
22407c478bd9Sstevel@tonic-gate  */
22417c478bd9Sstevel@tonic-gate static int
22427c478bd9Sstevel@tonic-gate door_overflow(
22437c478bd9Sstevel@tonic-gate 	kthread_t	*caller,
22447c478bd9Sstevel@tonic-gate 	caddr_t		data_ptr,	/* data location */
22457c478bd9Sstevel@tonic-gate 	size_t		data_size,	/* data size */
22467c478bd9Sstevel@tonic-gate 	door_desc_t	*desc_ptr,	/* descriptor location */
22477c478bd9Sstevel@tonic-gate 	uint_t		desc_num)	/* descriptor size */
22487c478bd9Sstevel@tonic-gate {
22497c478bd9Sstevel@tonic-gate 	proc_t *callerp = ttoproc(caller);
22507c478bd9Sstevel@tonic-gate 	struct as *as = callerp->p_as;
22517c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(caller->t_door);
22527c478bd9Sstevel@tonic-gate 	caddr_t	addr;			/* Resulting address in target */
22537c478bd9Sstevel@tonic-gate 	size_t	rlen;			/* Rounded len */
22547c478bd9Sstevel@tonic-gate 	size_t	len;
22557c478bd9Sstevel@tonic-gate 	uint_t	i;
22567c478bd9Sstevel@tonic-gate 	size_t	ds = desc_num * sizeof (door_desc_t);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
22597c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct) || ct->d_kernel);
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 	/* Do initial overflow check */
22627c478bd9Sstevel@tonic-gate 	if (!ufcanalloc(callerp, desc_num))
22637c478bd9Sstevel@tonic-gate 		return (EMFILE);
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 	/*
22667c478bd9Sstevel@tonic-gate 	 * Allocate space for this stuff in the callers address space
22677c478bd9Sstevel@tonic-gate 	 */
22687c478bd9Sstevel@tonic-gate 	rlen = roundup(data_size + ds, PAGESIZE);
22697c478bd9Sstevel@tonic-gate 	as_rangelock(as);
22707c478bd9Sstevel@tonic-gate 	map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0);
22717c478bd9Sstevel@tonic-gate 	if (addr == NULL ||
22727c478bd9Sstevel@tonic-gate 	    as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) {
22737c478bd9Sstevel@tonic-gate 		/* No virtual memory available, or anon mapping failed */
22747c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
22757c478bd9Sstevel@tonic-gate 		if (!ct->d_kernel && desc_num > 0) {
22767c478bd9Sstevel@tonic-gate 			int error = door_release_fds(desc_ptr, desc_num);
22777c478bd9Sstevel@tonic-gate 			if (error)
22787c478bd9Sstevel@tonic-gate 				return (error);
22797c478bd9Sstevel@tonic-gate 		}
22807c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
22817c478bd9Sstevel@tonic-gate 	}
22827c478bd9Sstevel@tonic-gate 	as_rangeunlock(as);
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 	if (ct->d_kernel)
22857c478bd9Sstevel@tonic-gate 		goto out;
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	if (data_size != 0) {
22887c478bd9Sstevel@tonic-gate 		caddr_t	src = data_ptr;
22897c478bd9Sstevel@tonic-gate 		caddr_t saddr = addr;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 		/* Copy any data */
22927c478bd9Sstevel@tonic-gate 		len = data_size;
22937c478bd9Sstevel@tonic-gate 		while (len != 0) {
22947c478bd9Sstevel@tonic-gate 			int	amount;
22957c478bd9Sstevel@tonic-gate 			int	error;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 			amount = len > PAGESIZE ? PAGESIZE : len;
22987c478bd9Sstevel@tonic-gate 			if ((error = door_copy(as, src, saddr, amount)) != 0) {
22997c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23007c478bd9Sstevel@tonic-gate 				return (error);
23017c478bd9Sstevel@tonic-gate 			}
23027c478bd9Sstevel@tonic-gate 			saddr += amount;
23037c478bd9Sstevel@tonic-gate 			src += amount;
23047c478bd9Sstevel@tonic-gate 			len -= amount;
23057c478bd9Sstevel@tonic-gate 		}
23067c478bd9Sstevel@tonic-gate 	}
23077c478bd9Sstevel@tonic-gate 	/* Copy any fd's */
23087c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
23097c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp, *start;
23107c478bd9Sstevel@tonic-gate 		struct file	**fpp;
23117c478bd9Sstevel@tonic-gate 		int		fpp_size;
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(ds, KM_SLEEP);
23147c478bd9Sstevel@tonic-gate 		if (copyin(desc_ptr, didpp, ds)) {
23157c478bd9Sstevel@tonic-gate 			kmem_free(start, ds);
23167c478bd9Sstevel@tonic-gate 			(void) as_unmap(as, addr, rlen);
23177c478bd9Sstevel@tonic-gate 			return (EFAULT);
23187c478bd9Sstevel@tonic-gate 		}
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
23217c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
23227c478bd9Sstevel@tonic-gate 			/* make more space */
23237c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
23247c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
23257c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
23267c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
23277c478bd9Sstevel@tonic-gate 		}
23287c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
23317c478bd9Sstevel@tonic-gate 			struct file *fp;
23327c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
23357c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
23367c478bd9Sstevel@tonic-gate 				/* close translated references */
23377c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
23387c478bd9Sstevel@tonic-gate 				/* close untranslated references */
23397c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
23407c478bd9Sstevel@tonic-gate 				kmem_free(start, ds);
23417c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23427c478bd9Sstevel@tonic-gate 				return (EINVAL);
23437c478bd9Sstevel@tonic-gate 			}
23447c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
23457c478bd9Sstevel@tonic-gate 			fp->f_count++;
23467c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 			*fpp = fp;
23497c478bd9Sstevel@tonic-gate 			releasef(fd);
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
23527c478bd9Sstevel@tonic-gate 				/* release passed reference */
23537c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
23547c478bd9Sstevel@tonic-gate 			}
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
23577c478bd9Sstevel@tonic-gate 		}
23587c478bd9Sstevel@tonic-gate 		kmem_free(start, ds);
23597c478bd9Sstevel@tonic-gate 	}
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate out:
23627c478bd9Sstevel@tonic-gate 	ct->d_overflow = 1;
23637c478bd9Sstevel@tonic-gate 	ct->d_args.rbuf = addr;
23647c478bd9Sstevel@tonic-gate 	ct->d_args.rsize = rlen;
23657c478bd9Sstevel@tonic-gate 	return (0);
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate /*
23697c478bd9Sstevel@tonic-gate  * Transfer arguments from the client to the server.
23707c478bd9Sstevel@tonic-gate  */
23717c478bd9Sstevel@tonic-gate static int
23727c478bd9Sstevel@tonic-gate door_args(kthread_t *server, int is_private)
23737c478bd9Sstevel@tonic-gate {
23747c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(server->t_door);
23757c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
23767c478bd9Sstevel@tonic-gate 	uint_t	ndid;
23777c478bd9Sstevel@tonic-gate 	size_t	dsize;
23787c478bd9Sstevel@tonic-gate 	int	error;
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(st));
23817c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
23847c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
23857c478bd9Sstevel@tonic-gate 		return (E2BIG);
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	/*
23887c478bd9Sstevel@tonic-gate 	 * Get the stack layout, and fail now if it won't fit.
23897c478bd9Sstevel@tonic-gate 	 */
23907c478bd9Sstevel@tonic-gate 	error = door_layout(server, ct->d_args.data_size, ndid, is_private);
23917c478bd9Sstevel@tonic-gate 	if (error != 0)
23927c478bd9Sstevel@tonic-gate 		return (error);
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	dsize = ndid * sizeof (door_desc_t);
23957c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size != 0) {
23967c478bd9Sstevel@tonic-gate 		if (ct->d_args.data_size <= door_max_arg) {
23977c478bd9Sstevel@tonic-gate 			/*
23987c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
23997c478bd9Sstevel@tonic-gate 			 *
24007c478bd9Sstevel@tonic-gate 			 * Allocate a little more than we need for the
24017c478bd9Sstevel@tonic-gate 			 * args, in the hope that the results will fit
24027c478bd9Sstevel@tonic-gate 			 * without having to reallocate a buffer
24037c478bd9Sstevel@tonic-gate 			 */
24047c478bd9Sstevel@tonic-gate 			ASSERT(ct->d_buf == NULL);
24057c478bd9Sstevel@tonic-gate 			ct->d_bufsize = roundup(ct->d_args.data_size,
24067c478bd9Sstevel@tonic-gate 			    DOOR_ROUND);
24077c478bd9Sstevel@tonic-gate 			ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
24087c478bd9Sstevel@tonic-gate 			if (copyin(ct->d_args.data_ptr,
24097c478bd9Sstevel@tonic-gate 			    ct->d_buf, ct->d_args.data_size) != 0) {
24107c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
24117c478bd9Sstevel@tonic-gate 				ct->d_buf = NULL;
24127c478bd9Sstevel@tonic-gate 				ct->d_bufsize = 0;
24137c478bd9Sstevel@tonic-gate 				return (EFAULT);
24147c478bd9Sstevel@tonic-gate 			}
24157c478bd9Sstevel@tonic-gate 		} else {
24167c478bd9Sstevel@tonic-gate 			struct as	*as;
24177c478bd9Sstevel@tonic-gate 			caddr_t		src;
24187c478bd9Sstevel@tonic-gate 			caddr_t		dest;
24197c478bd9Sstevel@tonic-gate 			size_t		len = ct->d_args.data_size;
24207c478bd9Sstevel@tonic-gate 			uintptr_t	base;
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 			/*
24237c478bd9Sstevel@tonic-gate 			 * Use a 1 copy method
24247c478bd9Sstevel@tonic-gate 			 */
24257c478bd9Sstevel@tonic-gate 			as = ttoproc(server)->p_as;
24267c478bd9Sstevel@tonic-gate 			src = ct->d_args.data_ptr;
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 			dest = st->d_layout.dl_datap;
24297c478bd9Sstevel@tonic-gate 			base = (uintptr_t)dest;
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 			/*
24327c478bd9Sstevel@tonic-gate 			 * Copy data directly into server.  We proceed
24337c478bd9Sstevel@tonic-gate 			 * downward from the top of the stack, to mimic
24347c478bd9Sstevel@tonic-gate 			 * normal stack usage. This allows the guard page
24357c478bd9Sstevel@tonic-gate 			 * to stop us before we corrupt anything.
24367c478bd9Sstevel@tonic-gate 			 */
24377c478bd9Sstevel@tonic-gate 			while (len != 0) {
24387c478bd9Sstevel@tonic-gate 				uintptr_t start;
24397c478bd9Sstevel@tonic-gate 				uintptr_t end;
24407c478bd9Sstevel@tonic-gate 				uintptr_t offset;
24417c478bd9Sstevel@tonic-gate 				size_t	amount;
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 				/*
24447c478bd9Sstevel@tonic-gate 				 * Locate the next part to copy.
24457c478bd9Sstevel@tonic-gate 				 */
24467c478bd9Sstevel@tonic-gate 				end = base + len;
24477c478bd9Sstevel@tonic-gate 				start = P2ALIGN(end - 1, PAGESIZE);
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 				/*
24507c478bd9Sstevel@tonic-gate 				 * if we are on the final (first) page, fix
24517c478bd9Sstevel@tonic-gate 				 * up the start position.
24527c478bd9Sstevel@tonic-gate 				 */
24537c478bd9Sstevel@tonic-gate 				if (P2ALIGN(base, PAGESIZE) == start)
24547c478bd9Sstevel@tonic-gate 					start = base;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 				offset = start - base;	/* the copy offset */
24577c478bd9Sstevel@tonic-gate 				amount = end - start;	/* # bytes to copy */
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 				ASSERT(amount > 0 && amount <= len &&
24607c478bd9Sstevel@tonic-gate 				    amount <= PAGESIZE);
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 				error = door_copy(as, src + offset,
24637c478bd9Sstevel@tonic-gate 				    dest + offset, amount);
24647c478bd9Sstevel@tonic-gate 				if (error != 0)
24657c478bd9Sstevel@tonic-gate 					return (error);
24667c478bd9Sstevel@tonic-gate 				len -= amount;
24677c478bd9Sstevel@tonic-gate 			}
24687c478bd9Sstevel@tonic-gate 		}
24697c478bd9Sstevel@tonic-gate 	}
24707c478bd9Sstevel@tonic-gate 	/*
24717c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into files
24727c478bd9Sstevel@tonic-gate 	 */
24737c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
24747c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
24757c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
24767c478bd9Sstevel@tonic-gate 		struct file	**fpp;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 		if (copyin(ct->d_args.desc_ptr, didpp, dsize)) {
24817c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
24827c478bd9Sstevel@tonic-gate 			return (EFAULT);
24837c478bd9Sstevel@tonic-gate 		}
24847c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
24857c478bd9Sstevel@tonic-gate 		ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
24867c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
24877c478bd9Sstevel@tonic-gate 		while (ndid--) {
24887c478bd9Sstevel@tonic-gate 			struct file *fp;
24897c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 			/* We only understand file descriptors as passed objs */
24927c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
24937c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
24947c478bd9Sstevel@tonic-gate 				/* close translated references */
24957c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
24967c478bd9Sstevel@tonic-gate 				/* close untranslated references */
24977c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
24987c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
24997c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
25007c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
25017c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
25027c478bd9Sstevel@tonic-gate 				return (EINVAL);
25037c478bd9Sstevel@tonic-gate 			}
25047c478bd9Sstevel@tonic-gate 			/* Hold the fp */
25057c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
25067c478bd9Sstevel@tonic-gate 			fp->f_count++;
25077c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 			*fpp = fp;
25107c478bd9Sstevel@tonic-gate 			releasef(fd);
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
25137c478bd9Sstevel@tonic-gate 				/* release passed reference */
25147c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
25157c478bd9Sstevel@tonic-gate 			}
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
25187c478bd9Sstevel@tonic-gate 		}
25197c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
25207c478bd9Sstevel@tonic-gate 	}
25217c478bd9Sstevel@tonic-gate 	return (0);
25227c478bd9Sstevel@tonic-gate }
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate /*
25257c478bd9Sstevel@tonic-gate  * Transfer arguments from a user client to a kernel server.  This copies in
25267c478bd9Sstevel@tonic-gate  * descriptors and translates them into door handles.  It doesn't touch the
25277c478bd9Sstevel@tonic-gate  * other data, letting the kernel server deal with that (to avoid needing
25287c478bd9Sstevel@tonic-gate  * to copy the data twice).
25297c478bd9Sstevel@tonic-gate  */
25307c478bd9Sstevel@tonic-gate static int
25317c478bd9Sstevel@tonic-gate door_translate_in(void)
25327c478bd9Sstevel@tonic-gate {
25337c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
25347c478bd9Sstevel@tonic-gate 	uint_t	ndid;
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
25377c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
25387c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
25397c478bd9Sstevel@tonic-gate 		return (E2BIG);
25407c478bd9Sstevel@tonic-gate 	/*
25417c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into door handles.
25427c478bd9Sstevel@tonic-gate 	 */
25437c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
25447c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
25457c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
25467c478bd9Sstevel@tonic-gate 		size_t		dsize = ndid * sizeof (door_desc_t);
25477c478bd9Sstevel@tonic-gate 		struct file	*fp;
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 		if (copyin(ct->d_args.desc_ptr, didpp, dsize)) {
25527c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
25537c478bd9Sstevel@tonic-gate 			return (EFAULT);
25547c478bd9Sstevel@tonic-gate 		}
25557c478bd9Sstevel@tonic-gate 		while (ndid--) {
25567c478bd9Sstevel@tonic-gate 			vnode_t	*vp;
25577c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 			/*
25607c478bd9Sstevel@tonic-gate 			 * We only understand file descriptors as passed objs
25617c478bd9Sstevel@tonic-gate 			 */
25627c478bd9Sstevel@tonic-gate 			if ((didpp->d_attributes & DOOR_DESCRIPTOR) &&
25637c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) != NULL) {
25647c478bd9Sstevel@tonic-gate 				didpp->d_data.d_handle = FTODH(fp);
25657c478bd9Sstevel@tonic-gate 				/* Hold the door */
25667c478bd9Sstevel@tonic-gate 				door_ki_hold(didpp->d_data.d_handle);
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 				releasef(fd);
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
25717c478bd9Sstevel@tonic-gate 					/* release passed reference */
25727c478bd9Sstevel@tonic-gate 					(void) closeandsetf(fd, NULL);
25737c478bd9Sstevel@tonic-gate 				}
25747c478bd9Sstevel@tonic-gate 
2575da6c28aaSamw 				if (VOP_REALVP(fp->f_vnode, &vp, NULL))
25767c478bd9Sstevel@tonic-gate 					vp = fp->f_vnode;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 				/* Set attributes */
25797c478bd9Sstevel@tonic-gate 				didpp->d_attributes = DOOR_HANDLE |
25807c478bd9Sstevel@tonic-gate 				    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
25817c478bd9Sstevel@tonic-gate 			} else {
25827c478bd9Sstevel@tonic-gate 				/* close translated references */
25837c478bd9Sstevel@tonic-gate 				door_fd_close(start, didpp - start);
25847c478bd9Sstevel@tonic-gate 				/* close untranslated references */
25857c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
25867c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
25877c478bd9Sstevel@tonic-gate 				return (EINVAL);
25887c478bd9Sstevel@tonic-gate 			}
25897c478bd9Sstevel@tonic-gate 			didpp++;
25907c478bd9Sstevel@tonic-gate 		}
25917c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = start;
25927c478bd9Sstevel@tonic-gate 	}
25937c478bd9Sstevel@tonic-gate 	return (0);
25947c478bd9Sstevel@tonic-gate }
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate /*
25977c478bd9Sstevel@tonic-gate  * Translate door arguments from kernel to user.  This copies the passed
25987c478bd9Sstevel@tonic-gate  * door handles.  It doesn't touch other data.  It is used by door_upcall,
25997c478bd9Sstevel@tonic-gate  * and for data returned by a door_call to a kernel server.
26007c478bd9Sstevel@tonic-gate  */
26017c478bd9Sstevel@tonic-gate static int
26027c478bd9Sstevel@tonic-gate door_translate_out(void)
26037c478bd9Sstevel@tonic-gate {
26047c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
26057c478bd9Sstevel@tonic-gate 	uint_t	ndid;
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
26087c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
26097c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc) {
26107c478bd9Sstevel@tonic-gate 		door_fd_rele(ct->d_args.desc_ptr, ndid, 1);
26117c478bd9Sstevel@tonic-gate 		return (E2BIG);
26127c478bd9Sstevel@tonic-gate 	}
26137c478bd9Sstevel@tonic-gate 	/*
26147c478bd9Sstevel@tonic-gate 	 * Translate the door args into files
26157c478bd9Sstevel@tonic-gate 	 */
26167c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
26177c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp = ct->d_args.desc_ptr;
26187c478bd9Sstevel@tonic-gate 		struct file	**fpp;
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
26217c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
26227c478bd9Sstevel@tonic-gate 		while (ndid--) {
26237c478bd9Sstevel@tonic-gate 			struct file *fp = NULL;
26247c478bd9Sstevel@tonic-gate 			int fd = -1;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 			/*
26277c478bd9Sstevel@tonic-gate 			 * We understand file descriptors and door
26287c478bd9Sstevel@tonic-gate 			 * handles as passed objs.
26297c478bd9Sstevel@tonic-gate 			 */
26307c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_DESCRIPTOR) {
26317c478bd9Sstevel@tonic-gate 				fd = didpp->d_data.d_desc.d_descriptor;
26327c478bd9Sstevel@tonic-gate 				fp = getf(fd);
26337c478bd9Sstevel@tonic-gate 			} else if (didpp->d_attributes & DOOR_HANDLE)
26347c478bd9Sstevel@tonic-gate 				fp = DHTOF(didpp->d_data.d_handle);
26357c478bd9Sstevel@tonic-gate 			if (fp != NULL) {
26367c478bd9Sstevel@tonic-gate 				/* Hold the fp */
26377c478bd9Sstevel@tonic-gate 				mutex_enter(&fp->f_tlock);
26387c478bd9Sstevel@tonic-gate 				fp->f_count++;
26397c478bd9Sstevel@tonic-gate 				mutex_exit(&fp->f_tlock);
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate 				*fpp = fp;
26427c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_DESCRIPTOR)
26437c478bd9Sstevel@tonic-gate 					releasef(fd);
26447c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
26457c478bd9Sstevel@tonic-gate 					/* release passed reference */
26467c478bd9Sstevel@tonic-gate 					if (fd >= 0)
26477c478bd9Sstevel@tonic-gate 						(void) closeandsetf(fd, NULL);
26487c478bd9Sstevel@tonic-gate 					else
26497c478bd9Sstevel@tonic-gate 						(void) closef(fp);
26507c478bd9Sstevel@tonic-gate 				}
26517c478bd9Sstevel@tonic-gate 			} else {
26527c478bd9Sstevel@tonic-gate 				/* close translated references */
26537c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
26547c478bd9Sstevel@tonic-gate 				/* close untranslated references */
26557c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 1);
26567c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
26577c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
26587c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
26597c478bd9Sstevel@tonic-gate 				return (EINVAL);
26607c478bd9Sstevel@tonic-gate 			}
26617c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
26627c478bd9Sstevel@tonic-gate 		}
26637c478bd9Sstevel@tonic-gate 	}
26647c478bd9Sstevel@tonic-gate 	return (0);
26657c478bd9Sstevel@tonic-gate }
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate /*
26687c478bd9Sstevel@tonic-gate  * Move the results from the server to the client
26697c478bd9Sstevel@tonic-gate  */
26707c478bd9Sstevel@tonic-gate static int
26717c478bd9Sstevel@tonic-gate door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
26727c478bd9Sstevel@tonic-gate 		door_desc_t *desc_ptr, uint_t desc_num)
26737c478bd9Sstevel@tonic-gate {
26747c478bd9Sstevel@tonic-gate 	door_client_t	*ct = DOOR_CLIENT(caller->t_door);
26757c478bd9Sstevel@tonic-gate 	size_t		dsize;
26767c478bd9Sstevel@tonic-gate 	size_t		rlen;
26777c478bd9Sstevel@tonic-gate 	size_t		result_size;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct));
26807c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
26837c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* No results expected */
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	if (desc_num > door_max_desc)
26867c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* Too many descriptors */
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
26897c478bd9Sstevel@tonic-gate 	/*
26907c478bd9Sstevel@tonic-gate 	 * Check if the results are bigger than the clients buffer
26917c478bd9Sstevel@tonic-gate 	 */
26927c478bd9Sstevel@tonic-gate 	if (dsize)
26937c478bd9Sstevel@tonic-gate 		rlen = roundup(data_size, sizeof (door_desc_t));
26947c478bd9Sstevel@tonic-gate 	else
26957c478bd9Sstevel@tonic-gate 		rlen = data_size;
26967c478bd9Sstevel@tonic-gate 	if ((result_size = rlen + dsize) == 0)
26977c478bd9Sstevel@tonic-gate 		return (0);
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 	if (ct->d_upcall) {
27007c478bd9Sstevel@tonic-gate 		/*
27017c478bd9Sstevel@tonic-gate 		 * Handle upcalls
27027c478bd9Sstevel@tonic-gate 		 */
27037c478bd9Sstevel@tonic-gate 		if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) {
27047c478bd9Sstevel@tonic-gate 			/*
27057c478bd9Sstevel@tonic-gate 			 * If there's no return buffer or the buffer is too
27067c478bd9Sstevel@tonic-gate 			 * small, allocate a new one.  The old buffer (if it
27077c478bd9Sstevel@tonic-gate 			 * exists) will be freed by the upcall client.
27087c478bd9Sstevel@tonic-gate 			 */
27097c478bd9Sstevel@tonic-gate 			if (result_size > door_max_upcall_reply)
27107c478bd9Sstevel@tonic-gate 				return (E2BIG);
27117c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = result_size;
27127c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP);
27137c478bd9Sstevel@tonic-gate 		}
27147c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
27157c478bd9Sstevel@tonic-gate 		if (data_size != 0 &&
27167c478bd9Sstevel@tonic-gate 		    copyin(data_ptr, ct->d_args.data_ptr, data_size) != 0)
27177c478bd9Sstevel@tonic-gate 			return (EFAULT);
27187c478bd9Sstevel@tonic-gate 	} else if (result_size > ct->d_args.rsize) {
27197c478bd9Sstevel@tonic-gate 		return (door_overflow(caller, data_ptr, data_size,
27207c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num));
27217c478bd9Sstevel@tonic-gate 	} else if (data_size != 0) {
27227c478bd9Sstevel@tonic-gate 		if (data_size <= door_max_arg) {
27237c478bd9Sstevel@tonic-gate 			/*
27247c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
27257c478bd9Sstevel@tonic-gate 			 */
27267c478bd9Sstevel@tonic-gate 			if (ct->d_buf == NULL) {
27277c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27287c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27297c478bd9Sstevel@tonic-gate 			} else if (ct->d_bufsize < data_size) {
27307c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
27317c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27327c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27337c478bd9Sstevel@tonic-gate 			}
27347c478bd9Sstevel@tonic-gate 			if (copyin(data_ptr, ct->d_buf, data_size) != 0)
27357c478bd9Sstevel@tonic-gate 				return (EFAULT);
27367c478bd9Sstevel@tonic-gate 		} else {
27377c478bd9Sstevel@tonic-gate 			struct as *as = ttoproc(caller)->p_as;
27387c478bd9Sstevel@tonic-gate 			caddr_t	dest = ct->d_args.rbuf;
27397c478bd9Sstevel@tonic-gate 			caddr_t	src = data_ptr;
27407c478bd9Sstevel@tonic-gate 			size_t	len = data_size;
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 			/* Copy data directly into client */
27437c478bd9Sstevel@tonic-gate 			while (len != 0) {
27447c478bd9Sstevel@tonic-gate 				uint_t	amount;
27457c478bd9Sstevel@tonic-gate 				uint_t	max;
27467c478bd9Sstevel@tonic-gate 				uint_t	off;
27477c478bd9Sstevel@tonic-gate 				int	error;
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 				off = (uintptr_t)dest & PAGEOFFSET;
27507c478bd9Sstevel@tonic-gate 				if (off)
27517c478bd9Sstevel@tonic-gate 					max = PAGESIZE - off;
27527c478bd9Sstevel@tonic-gate 				else
27537c478bd9Sstevel@tonic-gate 					max = PAGESIZE;
27547c478bd9Sstevel@tonic-gate 				amount = len > max ? max : len;
27557c478bd9Sstevel@tonic-gate 				error = door_copy(as, src, dest, amount);
27567c478bd9Sstevel@tonic-gate 				if (error != 0)
27577c478bd9Sstevel@tonic-gate 					return (error);
27587c478bd9Sstevel@tonic-gate 				dest += amount;
27597c478bd9Sstevel@tonic-gate 				src += amount;
27607c478bd9Sstevel@tonic-gate 				len -= amount;
27617c478bd9Sstevel@tonic-gate 			}
27627c478bd9Sstevel@tonic-gate 		}
27637c478bd9Sstevel@tonic-gate 	}
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	/*
27667c478bd9Sstevel@tonic-gate 	 * Copyin the returned door ids and translate them into door_node_t
27677c478bd9Sstevel@tonic-gate 	 */
27687c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
27697c478bd9Sstevel@tonic-gate 		door_desc_t *start;
27707c478bd9Sstevel@tonic-gate 		door_desc_t *didpp;
27717c478bd9Sstevel@tonic-gate 		struct file **fpp;
27727c478bd9Sstevel@tonic-gate 		size_t	fpp_size;
27737c478bd9Sstevel@tonic-gate 		uint_t	i;
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate 		/* First, check if we would overflow client */
27767c478bd9Sstevel@tonic-gate 		if (!ufcanalloc(ttoproc(caller), desc_num))
27777c478bd9Sstevel@tonic-gate 			return (EMFILE);
27787c478bd9Sstevel@tonic-gate 
27797c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
27807c478bd9Sstevel@tonic-gate 		if (copyin(desc_ptr, didpp, dsize)) {
27817c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
27827c478bd9Sstevel@tonic-gate 			return (EFAULT);
27837c478bd9Sstevel@tonic-gate 		}
27847c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
27857c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
27867c478bd9Sstevel@tonic-gate 			/* make more space */
27877c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
27887c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
27897c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
27907c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP);
27917c478bd9Sstevel@tonic-gate 		}
27927c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
27957c478bd9Sstevel@tonic-gate 			struct file *fp;
27967c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
27977c478bd9Sstevel@tonic-gate 
27987c478bd9Sstevel@tonic-gate 			/* Only understand file descriptor results */
27997c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
28007c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
28017c478bd9Sstevel@tonic-gate 				/* close translated references */
28027c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
28037c478bd9Sstevel@tonic-gate 				/* close untranslated references */
28047c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
28057c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
28067c478bd9Sstevel@tonic-gate 				return (EINVAL);
28077c478bd9Sstevel@tonic-gate 			}
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
28107c478bd9Sstevel@tonic-gate 			fp->f_count++;
28117c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 			*fpp = fp;
28147c478bd9Sstevel@tonic-gate 			releasef(fd);
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
28177c478bd9Sstevel@tonic-gate 				/* release passed reference */
28187c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
28197c478bd9Sstevel@tonic-gate 			}
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
28227c478bd9Sstevel@tonic-gate 		}
28237c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
28247c478bd9Sstevel@tonic-gate 	}
28257c478bd9Sstevel@tonic-gate 	return (0);
28267c478bd9Sstevel@tonic-gate }
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate /*
28297c478bd9Sstevel@tonic-gate  * Close all the descriptors.
28307c478bd9Sstevel@tonic-gate  */
28317c478bd9Sstevel@tonic-gate static void
28327c478bd9Sstevel@tonic-gate door_fd_close(door_desc_t *d, uint_t n)
28337c478bd9Sstevel@tonic-gate {
28347c478bd9Sstevel@tonic-gate 	uint_t	i;
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
28377c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
28387c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_DESCRIPTOR) {
28397c478bd9Sstevel@tonic-gate 			(void) closeandsetf(
28407c478bd9Sstevel@tonic-gate 			    d->d_data.d_desc.d_descriptor, NULL);
28417c478bd9Sstevel@tonic-gate 		} else if (d->d_attributes & DOOR_HANDLE) {
28427c478bd9Sstevel@tonic-gate 			door_ki_rele(d->d_data.d_handle);
28437c478bd9Sstevel@tonic-gate 		}
28447c478bd9Sstevel@tonic-gate 		d++;
28457c478bd9Sstevel@tonic-gate 	}
28467c478bd9Sstevel@tonic-gate }
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate /*
28497c478bd9Sstevel@tonic-gate  * Close descriptors that have the DOOR_RELEASE attribute set.
28507c478bd9Sstevel@tonic-gate  */
28517c478bd9Sstevel@tonic-gate void
28527c478bd9Sstevel@tonic-gate door_fd_rele(door_desc_t *d, uint_t n, int from_kernel)
28537c478bd9Sstevel@tonic-gate {
28547c478bd9Sstevel@tonic-gate 	uint_t	i;
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
28577c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
28587c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_RELEASE) {
28597c478bd9Sstevel@tonic-gate 			if (d->d_attributes & DOOR_DESCRIPTOR) {
28607c478bd9Sstevel@tonic-gate 				(void) closeandsetf(
28617c478bd9Sstevel@tonic-gate 				    d->d_data.d_desc.d_descriptor, NULL);
28627c478bd9Sstevel@tonic-gate 			} else if (from_kernel &&
28637c478bd9Sstevel@tonic-gate 			    (d->d_attributes & DOOR_HANDLE)) {
28647c478bd9Sstevel@tonic-gate 				door_ki_rele(d->d_data.d_handle);
28657c478bd9Sstevel@tonic-gate 			}
28667c478bd9Sstevel@tonic-gate 		}
28677c478bd9Sstevel@tonic-gate 		d++;
28687c478bd9Sstevel@tonic-gate 	}
28697c478bd9Sstevel@tonic-gate }
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate /*
28727c478bd9Sstevel@tonic-gate  * Copy descriptors into the kernel so we can release any marked
28737c478bd9Sstevel@tonic-gate  * DOOR_RELEASE.
28747c478bd9Sstevel@tonic-gate  */
28757c478bd9Sstevel@tonic-gate int
28767c478bd9Sstevel@tonic-gate door_release_fds(door_desc_t *desc_ptr, uint_t ndesc)
28777c478bd9Sstevel@tonic-gate {
28787c478bd9Sstevel@tonic-gate 	size_t dsize;
28797c478bd9Sstevel@tonic-gate 	door_desc_t *didpp;
28807c478bd9Sstevel@tonic-gate 	uint_t desc_num;
28817c478bd9Sstevel@tonic-gate 
28827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
28837c478bd9Sstevel@tonic-gate 	ASSERT(ndesc != 0);
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 	desc_num = MIN(ndesc, door_max_desc);
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
28887c478bd9Sstevel@tonic-gate 	didpp = kmem_alloc(dsize, KM_SLEEP);
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate 	while (ndesc > 0) {
28917c478bd9Sstevel@tonic-gate 		uint_t count = MIN(ndesc, desc_num);
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 		if (copyin(desc_ptr, didpp, count * sizeof (door_desc_t))) {
28947c478bd9Sstevel@tonic-gate 			kmem_free(didpp, dsize);
28957c478bd9Sstevel@tonic-gate 			return (EFAULT);
28967c478bd9Sstevel@tonic-gate 		}
28977c478bd9Sstevel@tonic-gate 		door_fd_rele(didpp, count, 0);
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 		ndesc -= count;
29007c478bd9Sstevel@tonic-gate 		desc_ptr += count;
29017c478bd9Sstevel@tonic-gate 	}
29027c478bd9Sstevel@tonic-gate 	kmem_free(didpp, dsize);
29037c478bd9Sstevel@tonic-gate 	return (0);
29047c478bd9Sstevel@tonic-gate }
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate /*
29077c478bd9Sstevel@tonic-gate  * Decrement ref count on all the files passed
29087c478bd9Sstevel@tonic-gate  */
29097c478bd9Sstevel@tonic-gate static void
29107c478bd9Sstevel@tonic-gate door_fp_close(struct file **fp, uint_t n)
29117c478bd9Sstevel@tonic-gate {
29127c478bd9Sstevel@tonic-gate 	uint_t	i;
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++)
29177c478bd9Sstevel@tonic-gate 		(void) closef(fp[i]);
29187c478bd9Sstevel@tonic-gate }
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate /*
29217c478bd9Sstevel@tonic-gate  * Copy data from 'src' in current address space to 'dest' in 'as' for 'len'
29227c478bd9Sstevel@tonic-gate  * bytes.
29237c478bd9Sstevel@tonic-gate  *
29247c478bd9Sstevel@tonic-gate  * Performs this using 1 mapin and 1 copy operation.
29257c478bd9Sstevel@tonic-gate  *
29267c478bd9Sstevel@tonic-gate  * We really should do more than 1 page at a time to improve
29277c478bd9Sstevel@tonic-gate  * performance, but for now this is treated as an anomalous condition.
29287c478bd9Sstevel@tonic-gate  */
29297c478bd9Sstevel@tonic-gate static int
29307c478bd9Sstevel@tonic-gate door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len)
29317c478bd9Sstevel@tonic-gate {
29327c478bd9Sstevel@tonic-gate 	caddr_t	kaddr;
29337c478bd9Sstevel@tonic-gate 	caddr_t	rdest;
29347c478bd9Sstevel@tonic-gate 	uint_t	off;
29357c478bd9Sstevel@tonic-gate 	page_t	**pplist;
29367c478bd9Sstevel@tonic-gate 	page_t	*pp = NULL;
29377c478bd9Sstevel@tonic-gate 	int	error = 0;
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 	ASSERT(len <= PAGESIZE);
29407c478bd9Sstevel@tonic-gate 	off = (uintptr_t)dest & PAGEOFFSET;	/* offset within the page */
29417c478bd9Sstevel@tonic-gate 	rdest = (caddr_t)((uintptr_t)dest &
29427c478bd9Sstevel@tonic-gate 	    (uintptr_t)PAGEMASK);	/* Page boundary */
29437c478bd9Sstevel@tonic-gate 	ASSERT(off + len <= PAGESIZE);
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 	/*
29467c478bd9Sstevel@tonic-gate 	 * Lock down destination page.
29477c478bd9Sstevel@tonic-gate 	 */
29487c478bd9Sstevel@tonic-gate 	if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE))
29497c478bd9Sstevel@tonic-gate 		return (E2BIG);
29507c478bd9Sstevel@tonic-gate 	/*
29517c478bd9Sstevel@tonic-gate 	 * Check if we have a shadow page list from as_pagelock. If not,
29527c478bd9Sstevel@tonic-gate 	 * we took the slow path and have to find our page struct the hard
29537c478bd9Sstevel@tonic-gate 	 * way.
29547c478bd9Sstevel@tonic-gate 	 */
29557c478bd9Sstevel@tonic-gate 	if (pplist == NULL) {
29567c478bd9Sstevel@tonic-gate 		pfn_t	pfnum;
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 		/* MMU mapping is already locked down */
29597c478bd9Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
29607c478bd9Sstevel@tonic-gate 		pfnum = hat_getpfnum(as->a_hat, rdest);
29617c478bd9Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate 		/*
29647c478bd9Sstevel@tonic-gate 		 * TODO: The pfn step should not be necessary - need
29657c478bd9Sstevel@tonic-gate 		 * a hat_getpp() function.
29667c478bd9Sstevel@tonic-gate 		 */
29677c478bd9Sstevel@tonic-gate 		if (pf_is_memory(pfnum)) {
29687c478bd9Sstevel@tonic-gate 			pp = page_numtopp_nolock(pfnum);
29697c478bd9Sstevel@tonic-gate 			ASSERT(pp == NULL || PAGE_LOCKED(pp));
29707c478bd9Sstevel@tonic-gate 		} else
29717c478bd9Sstevel@tonic-gate 			pp = NULL;
29727c478bd9Sstevel@tonic-gate 		if (pp == NULL) {
29737c478bd9Sstevel@tonic-gate 			as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
29747c478bd9Sstevel@tonic-gate 			return (E2BIG);
29757c478bd9Sstevel@tonic-gate 		}
29767c478bd9Sstevel@tonic-gate 	} else {
29777c478bd9Sstevel@tonic-gate 		pp = *pplist;
29787c478bd9Sstevel@tonic-gate 	}
29797c478bd9Sstevel@tonic-gate 	/*
29807c478bd9Sstevel@tonic-gate 	 * Map destination page into kernel address
29817c478bd9Sstevel@tonic-gate 	 */
29827c478bd9Sstevel@tonic-gate 	kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE, (caddr_t)-1);
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate 	/*
29857c478bd9Sstevel@tonic-gate 	 * Copy from src to dest
29867c478bd9Sstevel@tonic-gate 	 */
29877c478bd9Sstevel@tonic-gate 	if (copyin(src, kaddr + off, len) != 0)
29887c478bd9Sstevel@tonic-gate 		error = EFAULT;
29897c478bd9Sstevel@tonic-gate 	/*
29907c478bd9Sstevel@tonic-gate 	 * Unmap destination page from kernel
29917c478bd9Sstevel@tonic-gate 	 */
29927c478bd9Sstevel@tonic-gate 	ppmapout(kaddr);
29937c478bd9Sstevel@tonic-gate 	/*
29947c478bd9Sstevel@tonic-gate 	 * Unlock destination page
29957c478bd9Sstevel@tonic-gate 	 */
29967c478bd9Sstevel@tonic-gate 	as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
29977c478bd9Sstevel@tonic-gate 	return (error);
29987c478bd9Sstevel@tonic-gate }
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate /*
30017c478bd9Sstevel@tonic-gate  * General kernel upcall using doors
30027c478bd9Sstevel@tonic-gate  *	Returns 0 on success, errno for failures.
30037c478bd9Sstevel@tonic-gate  *	Caller must have a hold on the door based vnode, and on any
30047c478bd9Sstevel@tonic-gate  *	references passed in desc_ptr.  The references are released
30057c478bd9Sstevel@tonic-gate  *	in the event of an error, and passed without duplication
30067c478bd9Sstevel@tonic-gate  *	otherwise.  Note that param->rbuf must be 64-bit aligned in
30077c478bd9Sstevel@tonic-gate  *	a 64-bit kernel, since it may be used to store door descriptors
30087c478bd9Sstevel@tonic-gate  *	if they are returned by the server.
30097c478bd9Sstevel@tonic-gate  */
30107c478bd9Sstevel@tonic-gate int
30117c478bd9Sstevel@tonic-gate door_upcall(vnode_t *vp, door_arg_t *param)
30127c478bd9Sstevel@tonic-gate {
30137c478bd9Sstevel@tonic-gate 	/* Locals */
30147c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
30157c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
30167c478bd9Sstevel@tonic-gate 	int		error = 0;
30177c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
30187c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
30197c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
30207c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
3021*a574db85Sraf 	int		cancel_pending;
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
30247c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30257c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30267c478bd9Sstevel@tonic-gate 		return (EINVAL);
30277c478bd9Sstevel@tonic-gate 	}
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
30307c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
30317c478bd9Sstevel@tonic-gate 	dp = VTOD(vp);	/* Convert to a door_node_t */
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
30347c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
30357c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30367c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30377c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30387c478bd9Sstevel@tonic-gate 		error = EBADF;
30397c478bd9Sstevel@tonic-gate 		goto out;
30407c478bd9Sstevel@tonic-gate 	}
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
30437c478bd9Sstevel@tonic-gate 		/* Can't do an upcall to a kernel server */
30447c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30457c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30467c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30477c478bd9Sstevel@tonic-gate 		error = EINVAL;
30487c478bd9Sstevel@tonic-gate 		goto out;
30497c478bd9Sstevel@tonic-gate 	}
30507c478bd9Sstevel@tonic-gate 
30517c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, param, 1);
30527c478bd9Sstevel@tonic-gate 	if (error != 0) {
30537c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30547c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30557c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30567c478bd9Sstevel@tonic-gate 		goto out;
30577c478bd9Sstevel@tonic-gate 	}
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	/*
30607c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
30617c478bd9Sstevel@tonic-gate 	 */
30627c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
30637c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
30647c478bd9Sstevel@tonic-gate 			error = EBADF;
30657c478bd9Sstevel@tonic-gate 		else
30667c478bd9Sstevel@tonic-gate 			error = EAGAIN;
30677c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30687c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30697c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30707c478bd9Sstevel@tonic-gate 		goto out;
30717c478bd9Sstevel@tonic-gate 	}
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
30747c478bd9Sstevel@tonic-gate 	ct->d_buf = param->data_ptr;
30757c478bd9Sstevel@tonic-gate 	ct->d_bufsize = param->data_size;
30767c478bd9Sstevel@tonic-gate 	ct->d_args = *param;	/* structure assignment */
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
30797c478bd9Sstevel@tonic-gate 		/*
30807c478bd9Sstevel@tonic-gate 		 * Move data from client to server
30817c478bd9Sstevel@tonic-gate 		 */
30827c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
30837c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30847c478bd9Sstevel@tonic-gate 		error = door_translate_out();
30857c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
30867c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
30877c478bd9Sstevel@tonic-gate 		if (error) {
30887c478bd9Sstevel@tonic-gate 			/*
30897c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
30907c478bd9Sstevel@tonic-gate 			 */
30917c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
30927c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
30937c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
30947c478bd9Sstevel@tonic-gate 			goto out;
30957c478bd9Sstevel@tonic-gate 		}
30967c478bd9Sstevel@tonic-gate 	}
30977c478bd9Sstevel@tonic-gate 
30987c478bd9Sstevel@tonic-gate 	ct->d_upcall = 1;
30997c478bd9Sstevel@tonic-gate 	if (param->rsize == 0)
31007c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
31017c478bd9Sstevel@tonic-gate 	else
31027c478bd9Sstevel@tonic-gate 		ct->d_noresults = 0;
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 	dp->door_active++;
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
31077c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
31087c478bd9Sstevel@tonic-gate 	st->d_active = dp;
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
31117c478bd9Sstevel@tonic-gate 
31127c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
31137c478bd9Sstevel@tonic-gate shuttle_return:
31147c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
31157c478bd9Sstevel@tonic-gate 		/*
31167c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
31177c478bd9Sstevel@tonic-gate 		 */
31187c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
3119*a574db85Sraf 		cancel_pending = 0;
3120*a574db85Sraf 		if (lwp && (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
3121*a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
3122*a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0)) {
31237c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
3124*a574db85Sraf 			if (cancel_pending)
3125*a574db85Sraf 				schedctl_cancel_eintr();
31267c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
31277c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
31287c478bd9Sstevel@tonic-gate 			error = EINTR;
31297c478bd9Sstevel@tonic-gate 			/*
31307c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
31317c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
31327c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
31337c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
31347c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
31357c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
31367c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
31377c478bd9Sstevel@tonic-gate 			 */
31387c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
31397c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
31407c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
31437c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
31447c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
31457c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
31467c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
31497c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
31507c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
31537c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
31547c478bd9Sstevel@tonic-gate 				}
31557c478bd9Sstevel@tonic-gate 			}
31567c478bd9Sstevel@tonic-gate 		} else {
31577c478bd9Sstevel@tonic-gate 			/*
31587c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
31597c478bd9Sstevel@tonic-gate 			 *
31607c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
31617c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
31627c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
31637c478bd9Sstevel@tonic-gate 			 * is updated by the server.
31647c478bd9Sstevel@tonic-gate 			 */
31657c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
31667c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
31677c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
31687c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
31697c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
31707c478bd9Sstevel@tonic-gate 				if (lwp)
31717c478bd9Sstevel@tonic-gate 					lwp->lwp_asleep = 0;
31727c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
31737c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
31747c478bd9Sstevel@tonic-gate 				/* Server exit */
31757c478bd9Sstevel@tonic-gate 				error = EINTR;
31767c478bd9Sstevel@tonic-gate 			} else {
31777c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
31787c478bd9Sstevel@tonic-gate 				error = ct->d_error;
31797c478bd9Sstevel@tonic-gate 			}
31807c478bd9Sstevel@tonic-gate 		}
31817c478bd9Sstevel@tonic-gate 		/*
31827c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
31837c478bd9Sstevel@tonic-gate 		 * results for me
31847c478bd9Sstevel@tonic-gate 		 */
31857c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
31867c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 		/*
31897c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
31907c478bd9Sstevel@tonic-gate 		 */
31917c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
31927c478bd9Sstevel@tonic-gate 			gotresults = 1;
31937c478bd9Sstevel@tonic-gate 	}
31947c478bd9Sstevel@tonic-gate 	if (lwp) {
31957c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;		/* /proc */
31967c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 0;		/* /proc */
31977c478bd9Sstevel@tonic-gate 	}
31987c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
31997c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
32007c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 	/*
32037c478bd9Sstevel@tonic-gate 	 * Translate returned doors (if any)
32047c478bd9Sstevel@tonic-gate 	 */
32057c478bd9Sstevel@tonic-gate 
32067c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
32077c478bd9Sstevel@tonic-gate 		goto out;
32087c478bd9Sstevel@tonic-gate 
32097c478bd9Sstevel@tonic-gate 	if (error) {
32107c478bd9Sstevel@tonic-gate 		/*
32117c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
32127c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
32137c478bd9Sstevel@tonic-gate 		 */
32147c478bd9Sstevel@tonic-gate 		if (gotresults) {
32157c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
32167c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
32177c478bd9Sstevel@tonic-gate 		}
32187c478bd9Sstevel@tonic-gate 		goto out;
32197c478bd9Sstevel@tonic-gate 	}
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
32227c478bd9Sstevel@tonic-gate 		struct file	**fpp;
32237c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
32247c478bd9Sstevel@tonic-gate 		vnode_t		*vp;
32257c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate 		didpp = ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
32287c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
32297c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 		while (n--) {
32327c478bd9Sstevel@tonic-gate 			struct file *fp;
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 			fp = *fpp;
3235da6c28aaSamw 			if (VOP_REALVP(fp->f_vnode, &vp, NULL))
32367c478bd9Sstevel@tonic-gate 				vp = fp->f_vnode;
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate 			didpp->d_attributes = DOOR_HANDLE |
32397c478bd9Sstevel@tonic-gate 			    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
32407c478bd9Sstevel@tonic-gate 			didpp->d_data.d_handle = FTODH(fp);
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
32437c478bd9Sstevel@tonic-gate 		}
32447c478bd9Sstevel@tonic-gate 	}
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate 	/* on return data is in rbuf */
32477c478bd9Sstevel@tonic-gate 	*param = ct->d_args;		/* structure assignment */
32487c478bd9Sstevel@tonic-gate 
32497c478bd9Sstevel@tonic-gate out:
32507c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
32517c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
32527c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
32537c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
32547c478bd9Sstevel@tonic-gate 	}
32557c478bd9Sstevel@tonic-gate 
32567c478bd9Sstevel@tonic-gate 	ct->d_upcall = 0;
32577c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
32587c478bd9Sstevel@tonic-gate 	ct->d_buf = NULL;
32597c478bd9Sstevel@tonic-gate 	ct->d_bufsize = 0;
32607c478bd9Sstevel@tonic-gate 	return (error);
32617c478bd9Sstevel@tonic-gate }
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate /*
32647c478bd9Sstevel@tonic-gate  * Add a door to the per-process list of active doors for which the
32657c478bd9Sstevel@tonic-gate  * process is a server.
32667c478bd9Sstevel@tonic-gate  */
32677c478bd9Sstevel@tonic-gate static void
32687c478bd9Sstevel@tonic-gate door_list_insert(door_node_t *dp)
32697c478bd9Sstevel@tonic-gate {
32707c478bd9Sstevel@tonic-gate 	proc_t *p = dp->door_target;
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
32737c478bd9Sstevel@tonic-gate 	dp->door_list = p->p_door_list;
32747c478bd9Sstevel@tonic-gate 	p->p_door_list = dp;
32757c478bd9Sstevel@tonic-gate }
32767c478bd9Sstevel@tonic-gate 
32777c478bd9Sstevel@tonic-gate /*
32787c478bd9Sstevel@tonic-gate  * Remove a door from the per-process list of active doors.
32797c478bd9Sstevel@tonic-gate  */
32807c478bd9Sstevel@tonic-gate void
32817c478bd9Sstevel@tonic-gate door_list_delete(door_node_t *dp)
32827c478bd9Sstevel@tonic-gate {
32837c478bd9Sstevel@tonic-gate 	door_node_t **pp;
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
32867c478bd9Sstevel@tonic-gate 	/*
32877c478bd9Sstevel@tonic-gate 	 * Find the door in the list.  If the door belongs to another process,
32887c478bd9Sstevel@tonic-gate 	 * it's OK to use p_door_list since that process can't exit until all
32897c478bd9Sstevel@tonic-gate 	 * doors have been taken off the list (see door_exit).
32907c478bd9Sstevel@tonic-gate 	 */
32917c478bd9Sstevel@tonic-gate 	pp = &(dp->door_target->p_door_list);
32927c478bd9Sstevel@tonic-gate 	while (*pp != dp)
32937c478bd9Sstevel@tonic-gate 		pp = &((*pp)->door_list);
32947c478bd9Sstevel@tonic-gate 
32957c478bd9Sstevel@tonic-gate 	/* found it, take it off the list */
32967c478bd9Sstevel@tonic-gate 	*pp = dp->door_list;
32977c478bd9Sstevel@tonic-gate }
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 
33007c478bd9Sstevel@tonic-gate /*
33017c478bd9Sstevel@tonic-gate  * External kernel interfaces for doors.  These functions are available
33027c478bd9Sstevel@tonic-gate  * outside the doorfs module for use in creating and using doors from
33037c478bd9Sstevel@tonic-gate  * within the kernel.
33047c478bd9Sstevel@tonic-gate  */
33057c478bd9Sstevel@tonic-gate 
33067c478bd9Sstevel@tonic-gate /*
33077c478bd9Sstevel@tonic-gate  * door_ki_upcall invokes a user-level door server from the kernel.
33087c478bd9Sstevel@tonic-gate  */
33097c478bd9Sstevel@tonic-gate int
33107c478bd9Sstevel@tonic-gate door_ki_upcall(door_handle_t dh, door_arg_t *param)
33117c478bd9Sstevel@tonic-gate {
33127c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
33137c478bd9Sstevel@tonic-gate 	vnode_t *realvp;
33147c478bd9Sstevel@tonic-gate 
3315da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
33167c478bd9Sstevel@tonic-gate 		realvp = fp->f_vnode;
33177c478bd9Sstevel@tonic-gate 	return (door_upcall(realvp, param));
33187c478bd9Sstevel@tonic-gate }
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate /*
33217c478bd9Sstevel@tonic-gate  * Function call to create a "kernel" door server.  A kernel door
33227c478bd9Sstevel@tonic-gate  * server provides a way for a user-level process to invoke a function
33237c478bd9Sstevel@tonic-gate  * in the kernel through a door_call.  From the caller's point of
33247c478bd9Sstevel@tonic-gate  * view, a kernel door server looks the same as a user-level one
33257c478bd9Sstevel@tonic-gate  * (except the server pid is 0).  Unlike normal door calls, the
33267c478bd9Sstevel@tonic-gate  * kernel door function is invoked via a normal function call in the
33277c478bd9Sstevel@tonic-gate  * same thread and context as the caller.
33287c478bd9Sstevel@tonic-gate  */
33297c478bd9Sstevel@tonic-gate int
33307c478bd9Sstevel@tonic-gate door_ki_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
33317c478bd9Sstevel@tonic-gate     door_handle_t *dhp)
33327c478bd9Sstevel@tonic-gate {
33337c478bd9Sstevel@tonic-gate 	int err;
33347c478bd9Sstevel@tonic-gate 	file_t *fp;
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate 	/* no DOOR_PRIVATE */
33377c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_KI_CREATE_MASK) ||
33387c478bd9Sstevel@tonic-gate 	    (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
33397c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI))
33407c478bd9Sstevel@tonic-gate 		return (EINVAL);
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate 	err = door_create_common(pc_cookie, data_cookie, attributes,
33437c478bd9Sstevel@tonic-gate 	    1, NULL, &fp);
33447c478bd9Sstevel@tonic-gate 	if (err == 0 && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) &&
33457c478bd9Sstevel@tonic-gate 	    p0.p_unref_thread == 0) {
33467c478bd9Sstevel@tonic-gate 		/* need to create unref thread for process 0 */
33477c478bd9Sstevel@tonic-gate 		(void) thread_create(NULL, 0, door_unref_kernel, NULL, 0, &p0,
33487c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
33497c478bd9Sstevel@tonic-gate 	}
33507c478bd9Sstevel@tonic-gate 	if (err == 0) {
33517c478bd9Sstevel@tonic-gate 		*dhp = FTODH(fp);
33527c478bd9Sstevel@tonic-gate 	}
33537c478bd9Sstevel@tonic-gate 	return (err);
33547c478bd9Sstevel@tonic-gate }
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate void
33577c478bd9Sstevel@tonic-gate door_ki_hold(door_handle_t dh)
33587c478bd9Sstevel@tonic-gate {
33597c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
33627c478bd9Sstevel@tonic-gate 	fp->f_count++;
33637c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate void
33677c478bd9Sstevel@tonic-gate door_ki_rele(door_handle_t dh)
33687c478bd9Sstevel@tonic-gate {
33697c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate 	(void) closef(fp);
33727c478bd9Sstevel@tonic-gate }
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate int
33757c478bd9Sstevel@tonic-gate door_ki_open(char *pathname, door_handle_t *dhp)
33767c478bd9Sstevel@tonic-gate {
33777c478bd9Sstevel@tonic-gate 	file_t *fp;
33787c478bd9Sstevel@tonic-gate 	vnode_t *vp;
33797c478bd9Sstevel@tonic-gate 	int err;
33807c478bd9Sstevel@tonic-gate 
33817c478bd9Sstevel@tonic-gate 	if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
33827c478bd9Sstevel@tonic-gate 		return (err);
3383da6c28aaSamw 	if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
33847c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
33857c478bd9Sstevel@tonic-gate 		return (err);
33867c478bd9Sstevel@tonic-gate 	}
33877c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
33887c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
33897c478bd9Sstevel@tonic-gate 		return (EINVAL);
33907c478bd9Sstevel@tonic-gate 	}
33917c478bd9Sstevel@tonic-gate 	if ((err = falloc(vp, FREAD | FWRITE, &fp, NULL)) != 0) {
33927c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
33937c478bd9Sstevel@tonic-gate 		return (err);
33947c478bd9Sstevel@tonic-gate 	}
33957c478bd9Sstevel@tonic-gate 	/* falloc returns with f_tlock held on success */
33967c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
33977c478bd9Sstevel@tonic-gate 	*dhp = FTODH(fp);
33987c478bd9Sstevel@tonic-gate 	return (0);
33997c478bd9Sstevel@tonic-gate }
34007c478bd9Sstevel@tonic-gate 
34017c478bd9Sstevel@tonic-gate int
34027c478bd9Sstevel@tonic-gate door_ki_info(door_handle_t dh, struct door_info *dip)
34037c478bd9Sstevel@tonic-gate {
34047c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34057c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34067c478bd9Sstevel@tonic-gate 
3407da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
34087c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
34097c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
34107c478bd9Sstevel@tonic-gate 		return (EINVAL);
34117c478bd9Sstevel@tonic-gate 	door_info_common(VTOD(vp), dip, fp);
34127c478bd9Sstevel@tonic-gate 	return (0);
34137c478bd9Sstevel@tonic-gate }
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate door_handle_t
34167c478bd9Sstevel@tonic-gate door_ki_lookup(int did)
34177c478bd9Sstevel@tonic-gate {
34187c478bd9Sstevel@tonic-gate 	file_t *fp;
34197c478bd9Sstevel@tonic-gate 	door_handle_t dh;
34207c478bd9Sstevel@tonic-gate 
34217c478bd9Sstevel@tonic-gate 	/* is the descriptor really a door? */
34227c478bd9Sstevel@tonic-gate 	if (door_lookup(did, &fp) == NULL)
34237c478bd9Sstevel@tonic-gate 		return (NULL);
34247c478bd9Sstevel@tonic-gate 	/* got the door, put a hold on it and release the fd */
34257c478bd9Sstevel@tonic-gate 	dh = FTODH(fp);
34267c478bd9Sstevel@tonic-gate 	door_ki_hold(dh);
34277c478bd9Sstevel@tonic-gate 	releasef(did);
34287c478bd9Sstevel@tonic-gate 	return (dh);
34297c478bd9Sstevel@tonic-gate }
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate int
34327c478bd9Sstevel@tonic-gate door_ki_setparam(door_handle_t dh, int type, size_t val)
34337c478bd9Sstevel@tonic-gate {
34347c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34357c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34367c478bd9Sstevel@tonic-gate 
3437da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
34387c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
34397c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
34407c478bd9Sstevel@tonic-gate 		return (EINVAL);
34417c478bd9Sstevel@tonic-gate 	return (door_setparam_common(VTOD(vp), 1, type, val));
34427c478bd9Sstevel@tonic-gate }
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate int
34457c478bd9Sstevel@tonic-gate door_ki_getparam(door_handle_t dh, int type, size_t *out)
34467c478bd9Sstevel@tonic-gate {
34477c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34487c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34497c478bd9Sstevel@tonic-gate 
3450da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
34517c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
34527c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
34537c478bd9Sstevel@tonic-gate 		return (EINVAL);
34547c478bd9Sstevel@tonic-gate 	return (door_getparam_common(VTOD(vp), type, out));
34557c478bd9Sstevel@tonic-gate }
3456