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