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 /*
235ab67823SVivek Gavaskar  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * System call I/F to doors (outside of vnodes I/F) and misc support
297c478bd9Sstevel@tonic-gate  * routines
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/door.h>
347c478bd9Sstevel@tonic-gate #include <sys/door_data.h>
357c478bd9Sstevel@tonic-gate #include <sys/proc.h>
367c478bd9Sstevel@tonic-gate #include <sys/thread.h>
37c12957e9Sraf #include <sys/prsystm.h>
38c12957e9Sraf #include <sys/procfs.h>
397c478bd9Sstevel@tonic-gate #include <sys/class.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/stack.h>
447c478bd9Sstevel@tonic-gate #include <sys/debug.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
487c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
497c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
50aa59c4cbSrsb #include <sys/vfs_opreg.h>
517c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
527c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
537c478bd9Sstevel@tonic-gate #include <sys/callb.h>
547c478bd9Sstevel@tonic-gate #include <sys/ucred.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <sys/mman.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
587c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
597c478bd9Sstevel@tonic-gate #include <vm/as.h>
607c478bd9Sstevel@tonic-gate #include <vm/hat.h>
617c478bd9Sstevel@tonic-gate #include <vm/page.h>
627c478bd9Sstevel@tonic-gate #include <vm/seg.h>
637c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
647c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
655ab67823SVivek Gavaskar #include <vm/seg_kpm.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
687c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
697c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
707c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
73da6c28aaSamw  * The maximum amount of data (in bytes) that will be transferred using
747c478bd9Sstevel@tonic-gate  * an intermediate kernel buffer.  For sizes greater than this we map
757c478bd9Sstevel@tonic-gate  * in the destination pages and perform a 1-copy transfer.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate size_t	door_max_arg = 16 * 1024;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
80da6c28aaSamw  * Maximum amount of data that will be transferred in a reply to a
817c478bd9Sstevel@tonic-gate  * door_upcall.  Need to guard against a process returning huge amounts
827c478bd9Sstevel@tonic-gate  * of data and getting the kernel stuck in kmem_alloc.
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate size_t	door_max_upcall_reply = 1024 * 1024;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * Maximum number of descriptors allowed to be passed in a single
887c478bd9Sstevel@tonic-gate  * door_call or door_return.  We need to allocate kernel memory
897c478bd9Sstevel@tonic-gate  * for all of them at once, so we can't let it scale without limit.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate uint_t door_max_desc = 1024;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Definition of a door handle, used by other kernel subsystems when
957c478bd9Sstevel@tonic-gate  * calling door functions.  This is really a file structure but we
967c478bd9Sstevel@tonic-gate  * want to hide that fact.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate struct __door_handle {
997c478bd9Sstevel@tonic-gate 	file_t dh_file;
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #define	DHTOF(dh) ((file_t *)(dh))
1037c478bd9Sstevel@tonic-gate #define	FTODH(fp) ((door_handle_t)(fp))
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static int doorfs(long, long, long, long, long, long);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static struct sysent door_sysent = {
1087c478bd9Sstevel@tonic-gate 	6,
1097c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1107c478bd9Sstevel@tonic-gate 	(int (*)())doorfs,
1117c478bd9Sstevel@tonic-gate };
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1147c478bd9Sstevel@tonic-gate 	&mod_syscallops, "doors", &door_sysent
1157c478bd9Sstevel@tonic-gate };
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static int
1207c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
1217c478bd9Sstevel@tonic-gate     int32_t arg5, int32_t subcode);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static struct sysent door_sysent32 = {
1247c478bd9Sstevel@tonic-gate 	6,
1257c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1267c478bd9Sstevel@tonic-gate 	(int (*)())doorfs32,
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1307c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
1317c478bd9Sstevel@tonic-gate 	"32-bit door syscalls",
1327c478bd9Sstevel@tonic-gate 	&door_sysent32
1337c478bd9Sstevel@tonic-gate };
1347c478bd9Sstevel@tonic-gate #endif
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1377c478bd9Sstevel@tonic-gate 	MODREV_1,
1387c478bd9Sstevel@tonic-gate 	&modlsys,
1397c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1407c478bd9Sstevel@tonic-gate 	&modlsys32,
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 	NULL
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate dev_t	doordev;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate extern	struct vfs door_vfs;
1487c478bd9Sstevel@tonic-gate extern	struct vnodeops *door_vnodeops;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
1517c478bd9Sstevel@tonic-gate _init(void)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t door_vfsops_template[] = {
1547c478bd9Sstevel@tonic-gate 		NULL, NULL
1557c478bd9Sstevel@tonic-gate 	};
1567c478bd9Sstevel@tonic-gate 	extern const fs_operation_def_t door_vnodeops_template[];
1577c478bd9Sstevel@tonic-gate 	vfsops_t *door_vfsops;
1587c478bd9Sstevel@tonic-gate 	major_t major;
1597c478bd9Sstevel@tonic-gate 	int error;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
1627c478bd9Sstevel@tonic-gate 	if ((major = getudev()) == (major_t)-1)
1637c478bd9Sstevel@tonic-gate 		return (ENXIO);
1647c478bd9Sstevel@tonic-gate 	doordev = makedevice(major, 0);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* Create a dummy vfs */
1677c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(door_vfsops_template, &door_vfsops);
1687c478bd9Sstevel@tonic-gate 	if (error != 0) {
1697c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vfs ops");
1707c478bd9Sstevel@tonic-gate 		return (error);
1717c478bd9Sstevel@tonic-gate 	}
172da6c28aaSamw 	VFS_INIT(&door_vfs, door_vfsops, NULL);
1737c478bd9Sstevel@tonic-gate 	door_vfs.vfs_flag = VFS_RDONLY;
1747c478bd9Sstevel@tonic-gate 	door_vfs.vfs_dev = doordev;
1757c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
1787c478bd9Sstevel@tonic-gate 	if (error != 0) {
1797c478bd9Sstevel@tonic-gate 		vfs_freevfsops(door_vfsops);
1807c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vnode ops");
1817c478bd9Sstevel@tonic-gate 		return (error);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate int
1877c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /* system call functions */
1937c478bd9Sstevel@tonic-gate static int door_call(int, void *);
1947c478bd9Sstevel@tonic-gate static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
1957c478bd9Sstevel@tonic-gate static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
1967c478bd9Sstevel@tonic-gate     uint_t), void *data_cookie, uint_t);
1977c478bd9Sstevel@tonic-gate static int door_revoke(int);
1987c478bd9Sstevel@tonic-gate static int door_info(int, struct door_info *);
1997c478bd9Sstevel@tonic-gate static int door_ucred(struct ucred_s *);
2007c478bd9Sstevel@tonic-gate static int door_bind(int);
2017c478bd9Sstevel@tonic-gate static int door_unbind(void);
2027c478bd9Sstevel@tonic-gate static int door_unref(void);
2037c478bd9Sstevel@tonic-gate static int door_getparam(int, int, size_t *);
2047c478bd9Sstevel@tonic-gate static int door_setparam(int, int, size_t);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate #define	DOOR_RETURN_OLD	4		/* historic value, for s10 */
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate static int
2127c478bd9Sstevel@tonic-gate doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	switch (subcode) {
2157c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2167c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)arg2));
2177c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2187c478bd9Sstevel@tonic-gate 		door_return_desc_t *drdp = (door_return_desc_t *)arg3;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2217c478bd9Sstevel@tonic-gate 			door_return_desc_t drd;
2227c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2237c478bd9Sstevel@tonic-gate 				return (EFAULT);
2247c478bd9Sstevel@tonic-gate 			return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
2257c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)arg4, arg5));
2267c478bd9Sstevel@tonic-gate 		}
2277c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, NULL,
2287c478bd9Sstevel@tonic-gate 		    0, (caddr_t)arg4, arg5));
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2317c478bd9Sstevel@tonic-gate 		/*
2327c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2337c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2347c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2357c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2367c478bd9Sstevel@tonic-gate 		 */
2377c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
2387c478bd9Sstevel@tonic-gate 		    arg4, (caddr_t)arg5, 0));
2397c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
2407c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())arg1, (void *)arg2, arg3));
2417c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
2427c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
2437c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
2447c478bd9Sstevel@tonic-gate 		return (door_info(arg1, (struct door_info *)arg2));
2457c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
2467c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
2477c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
2487c478bd9Sstevel@tonic-gate 		return (door_unbind());
2497c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
2507c478bd9Sstevel@tonic-gate 		return (door_unref());
2517c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
2527c478bd9Sstevel@tonic-gate 		return (door_ucred((struct ucred_s *)arg1));
2537c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
2547c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2, (size_t *)arg3));
2557c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
2567c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, arg3));
2577c478bd9Sstevel@tonic-gate 	default:
2587c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls from 32-bit programs.
2657c478bd9Sstevel@tonic-gate  * Needed at the moment because of the casts - they undo some damage
2667c478bd9Sstevel@tonic-gate  * that truss causes (sign-extending the stack pointer) when truss'ing
2677c478bd9Sstevel@tonic-gate  * a 32-bit program using doors.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate static int
2707c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
2717c478bd9Sstevel@tonic-gate     int32_t arg4, int32_t arg5, int32_t subcode)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	switch (subcode) {
2747c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2757c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
2767c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2777c478bd9Sstevel@tonic-gate 		door_return_desc32_t *drdp =
2787c478bd9Sstevel@tonic-gate 		    (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
2797c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2807c478bd9Sstevel@tonic-gate 			door_return_desc32_t drd;
2817c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2827c478bd9Sstevel@tonic-gate 				return (EFAULT);
2837c478bd9Sstevel@tonic-gate 			return (door_return(
2847c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
2857c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)drd.desc_ptr,
2867c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2877c478bd9Sstevel@tonic-gate 			    (size_t)(uintptr_t)(size32_t)arg5));
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
2907c478bd9Sstevel@tonic-gate 		    arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2917c478bd9Sstevel@tonic-gate 		    (size_t)(uintptr_t)(size32_t)arg5));
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2947c478bd9Sstevel@tonic-gate 		/*
2957c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2967c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2977c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2987c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2997c478bd9Sstevel@tonic-gate 		 */
3007c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
3017c478bd9Sstevel@tonic-gate 		    (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
3027c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
3037c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
3047c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
3057c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)(caddr32_t)arg2, arg3));
3067c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
3077c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
3087c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
3097c478bd9Sstevel@tonic-gate 		return (door_info(arg1,
3107c478bd9Sstevel@tonic-gate 		    (struct door_info *)(uintptr_t)(caddr32_t)arg2));
3117c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
3127c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
3137c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
3147c478bd9Sstevel@tonic-gate 		return (door_unbind());
3157c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
3167c478bd9Sstevel@tonic-gate 		return (door_unref());
3177c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
3187c478bd9Sstevel@tonic-gate 		return (door_ucred(
3197c478bd9Sstevel@tonic-gate 		    (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
3207c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
3217c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2,
3227c478bd9Sstevel@tonic-gate 		    (size_t *)(uintptr_t)(caddr32_t)arg3));
3237c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
3247c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	default:
3277c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate #endif
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate void shuttle_resume(kthread_t *, kmutex_t *);
3337c478bd9Sstevel@tonic-gate void shuttle_swtch(kmutex_t *);
3347c478bd9Sstevel@tonic-gate void shuttle_sleep(kthread_t *);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * Support routines
3387c478bd9Sstevel@tonic-gate  */
3397c478bd9Sstevel@tonic-gate static int door_create_common(void (*)(), void *, uint_t, int, int *,
3407c478bd9Sstevel@tonic-gate     file_t **);
3417c478bd9Sstevel@tonic-gate static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3427c478bd9Sstevel@tonic-gate static int door_args(kthread_t *, int);
3437c478bd9Sstevel@tonic-gate static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3447c478bd9Sstevel@tonic-gate static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
345c4ace179Sdm static void	door_server_exit(proc_t *, kthread_t *);
3467c478bd9Sstevel@tonic-gate static void	door_release_server(door_node_t *, kthread_t *);
3477c478bd9Sstevel@tonic-gate static kthread_t	*door_get_server(door_node_t *);
3487c478bd9Sstevel@tonic-gate static door_node_t	*door_lookup(int, file_t **);
3497c478bd9Sstevel@tonic-gate static int	door_translate_in(void);
3507c478bd9Sstevel@tonic-gate static int	door_translate_out(void);
3517c478bd9Sstevel@tonic-gate static void	door_fd_rele(door_desc_t *, uint_t, int);
3527c478bd9Sstevel@tonic-gate static void	door_list_insert(door_node_t *);
3537c478bd9Sstevel@tonic-gate static void	door_info_common(door_node_t *, door_info_t *, file_t *);
3547c478bd9Sstevel@tonic-gate static int	door_release_fds(door_desc_t *, uint_t);
3557c478bd9Sstevel@tonic-gate static void	door_fd_close(door_desc_t *, uint_t);
3567c478bd9Sstevel@tonic-gate static void	door_fp_close(struct file **, uint_t);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate static door_data_t *
3597c478bd9Sstevel@tonic-gate door_my_data(int create_if_missing)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	door_data_t *ddp;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	ddp = curthread->t_door;
3647c478bd9Sstevel@tonic-gate 	if (create_if_missing && ddp == NULL)
3657c478bd9Sstevel@tonic-gate 		ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	return (ddp);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate static door_server_t *
3717c478bd9Sstevel@tonic-gate door_my_server(int create_if_missing)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate static door_client_t *
3797c478bd9Sstevel@tonic-gate door_my_client(int create_if_missing)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
3877c478bd9Sstevel@tonic-gate  * System call to create a door
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate int
3907c478bd9Sstevel@tonic-gate door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	int fd;
3937c478bd9Sstevel@tonic-gate 	int err;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_CREATE_MASK) ||
3967c478bd9Sstevel@tonic-gate 	    ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3977c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI)))
3987c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
4017c478bd9Sstevel@tonic-gate 	    &fd, NULL)) != 0)
4027c478bd9Sstevel@tonic-gate 		return (set_errno(err));
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	f_setfd(fd, FD_CLOEXEC);
4057c478bd9Sstevel@tonic-gate 	return (fd);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * Common code for creating user and kernel doors.  If a door was
4107c478bd9Sstevel@tonic-gate  * created, stores a file structure pointer in the location pointed
4117c478bd9Sstevel@tonic-gate  * to by fpp (if fpp is non-NULL) and returns 0.  Also, if a non-NULL
4127c478bd9Sstevel@tonic-gate  * pointer to a file descriptor is passed in as fdp, allocates a file
4137c478bd9Sstevel@tonic-gate  * descriptor representing the door.  If a door could not be created,
4147c478bd9Sstevel@tonic-gate  * returns an error.
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate static int
4177c478bd9Sstevel@tonic-gate door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
4187c478bd9Sstevel@tonic-gate     int from_kernel, int *fdp, file_t **fpp)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
4217c478bd9Sstevel@tonic-gate 	vnode_t		*vp;
4227c478bd9Sstevel@tonic-gate 	struct file	*fp;
4237c478bd9Sstevel@tonic-gate 	static door_id_t index = 0;
4247c478bd9Sstevel@tonic-gate 	proc_t		*p = (from_kernel)? &p0 : curproc;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	dp->door_vnode = vn_alloc(KM_SLEEP);
4297c478bd9Sstevel@tonic-gate 	dp->door_target = p;
4307c478bd9Sstevel@tonic-gate 	dp->door_data = data_cookie;
4317c478bd9Sstevel@tonic-gate 	dp->door_pc = pc_cookie;
4327c478bd9Sstevel@tonic-gate 	dp->door_flags = attributes;
4337c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4347c478bd9Sstevel@tonic-gate 	if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
4357c478bd9Sstevel@tonic-gate 		dp->door_data_max = UINT32_MAX;
4367c478bd9Sstevel@tonic-gate 	else
4377c478bd9Sstevel@tonic-gate #endif
4387c478bd9Sstevel@tonic-gate 		dp->door_data_max = SIZE_MAX;
4397c478bd9Sstevel@tonic-gate 	dp->door_data_min = 0UL;
4407c478bd9Sstevel@tonic-gate 	dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	vp = DTOV(dp);
4437c478bd9Sstevel@tonic-gate 	vn_setops(vp, door_vnodeops);
4447c478bd9Sstevel@tonic-gate 	vp->v_type = VDOOR;
4457c478bd9Sstevel@tonic-gate 	vp->v_vfsp = &door_vfs;
4467c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)dp;
4477c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
4487c478bd9Sstevel@tonic-gate 	dp->door_index = index++;
4497c478bd9Sstevel@tonic-gate 	/* add to per-process door list */
4507c478bd9Sstevel@tonic-gate 	door_list_insert(dp);
4517c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
4547c478bd9Sstevel@tonic-gate 		/*
4557c478bd9Sstevel@tonic-gate 		 * If the file table is full, remove the door from the
4567c478bd9Sstevel@tonic-gate 		 * per-process list, free the door, and return NULL.
4577c478bd9Sstevel@tonic-gate 		 */
4587c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
4597c478bd9Sstevel@tonic-gate 		door_list_delete(dp);
4607c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
4617c478bd9Sstevel@tonic-gate 		vn_free(vp);
4627c478bd9Sstevel@tonic-gate 		kmem_free(dp, sizeof (door_node_t));
4637c478bd9Sstevel@tonic-gate 		return (EMFILE);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	vn_exists(vp);
4667c478bd9Sstevel@tonic-gate 	if (fdp != NULL)
4677c478bd9Sstevel@tonic-gate 		setf(*fdp, fp);
4687c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
4717c478bd9Sstevel@tonic-gate 		*fpp = fp;
4727c478bd9Sstevel@tonic-gate 	return (0);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static int
4767c478bd9Sstevel@tonic-gate door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/* we allow unref upcalls through, despite any minimum */
4817c478bd9Sstevel@tonic-gate 	if (da->data_size < dp->door_data_min &&
4827c478bd9Sstevel@tonic-gate 	    !(upcall && da->data_ptr == DOOR_UNREF_DATA))
4837c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if (da->data_size > dp->door_data_max)
4867c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
4897c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (da->desc_num > dp->door_desc_max)
4927c478bd9Sstevel@tonic-gate 		return (ENFILE);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	return (0);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate /*
4987c478bd9Sstevel@tonic-gate  * Door invocation.
4997c478bd9Sstevel@tonic-gate  */
5007c478bd9Sstevel@tonic-gate int
5017c478bd9Sstevel@tonic-gate door_call(int did, void *args)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	/* Locals */
5047c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
5057c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
5067c478bd9Sstevel@tonic-gate 	int		error = 0;
5077c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
5087c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
5097c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
5107c478bd9Sstevel@tonic-gate 	door_desc_t	*start = NULL;
5117c478bd9Sstevel@tonic-gate 	uint_t		ncopied = 0;
5127c478bd9Sstevel@tonic-gate 	size_t		dsize;
5137c478bd9Sstevel@tonic-gate 	/* destructor for data returned by a kernel server */
5147c478bd9Sstevel@tonic-gate 	void		(*destfn)() = NULL;
5157c478bd9Sstevel@tonic-gate 	void		*destarg;
5167c478bd9Sstevel@tonic-gate 	model_t		datamodel;
5177c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
518751c7f73Sjwadams 	int		needcleanup = 0;
519a574db85Sraf 	int		cancel_pending;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
5227c478bd9Sstevel@tonic-gate 	datamodel = lwp_getdatamodel(lwp);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * Get the arguments
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 	if (args) {
5307c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
5317c478bd9Sstevel@tonic-gate 			if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
5327c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5337c478bd9Sstevel@tonic-gate 		} else {
5347c478bd9Sstevel@tonic-gate 			door_arg32_t    da32;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 			if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
5377c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5387c478bd9Sstevel@tonic-gate 			ct->d_args.data_ptr =
5397c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.data_ptr;
5407c478bd9Sstevel@tonic-gate 			ct->d_args.data_size = da32.data_size;
5417c478bd9Sstevel@tonic-gate 			ct->d_args.desc_ptr =
5427c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)da32.desc_ptr;
5437c478bd9Sstevel@tonic-gate 			ct->d_args.desc_num = da32.desc_num;
5447c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf =
5457c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.rbuf;
5467c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = da32.rsize;
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 	} else {
5497c478bd9Sstevel@tonic-gate 		/* No arguments, and no results allowed */
5507c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
5517c478bd9Sstevel@tonic-gate 		ct->d_args.data_size = 0;
5527c478bd9Sstevel@tonic-gate 		ct->d_args.desc_num = 0;
5537c478bd9Sstevel@tonic-gate 		ct->d_args.rsize = 0;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
5577c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
5587c478bd9Sstevel@tonic-gate 
559289175a0Sjwadams 	/*
560289175a0Sjwadams 	 * We don't want to hold the door FD over the entire operation;
561289175a0Sjwadams 	 * instead, we put a hold on the door vnode and release the FD
562289175a0Sjwadams 	 * immediately
563289175a0Sjwadams 	 */
564289175a0Sjwadams 	VN_HOLD(DTOV(dp));
565289175a0Sjwadams 	releasef(did);
566289175a0Sjwadams 
567c12957e9Sraf 	/*
568c12957e9Sraf 	 * This should be done in shuttle_resume(), just before going to
569c12957e9Sraf 	 * sleep, but we want to avoid overhead while holding door_knob.
570c12957e9Sraf 	 * prstop() is just a no-op if we don't really go to sleep.
571e28ad609SRoger A. Faulkner 	 * We test not-kernel-address-space for the sake of clustering code.
572c12957e9Sraf 	 */
573e28ad609SRoger A. Faulkner 	if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
574c12957e9Sraf 		prstop(PR_REQUESTED, 0);
575c12957e9Sraf 
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 	/*
1385c12957e9Sraf 	 * This should be done in shuttle_resume(), just before going to
1386c12957e9Sraf 	 * sleep, but we want to avoid overhead while holding door_knob.
1387c12957e9Sraf 	 * prstop() is just a no-op if we don't really go to sleep.
1388e28ad609SRoger A. Faulkner 	 * We test not-kernel-address-space for the sake of clustering code.
13897c478bd9Sstevel@tonic-gate 	 */
1390c12957e9Sraf 	lwp = ttolwp(curthread);
1391e28ad609SRoger A. Faulkner 	if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
1392c12957e9Sraf 		prstop(PR_REQUESTED, 0);
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	/* Make sure the caller hasn't gone away */
13957c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
13967c478bd9Sstevel@tonic-gate 	if ((caller = st->d_caller) == NULL || caller->t_door == NULL) {
13977c478bd9Sstevel@tonic-gate 		if (desc_num != 0) {
13987c478bd9Sstevel@tonic-gate 			/* close any DOOR_RELEASE descriptors */
13997c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
14007c478bd9Sstevel@tonic-gate 			error = door_release_fds(desc_ptr, desc_num);
14017c478bd9Sstevel@tonic-gate 			if (error)
14027c478bd9Sstevel@tonic-gate 				return (set_errno(error));
14037c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 		goto out;
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	ct->d_args.data_size = data_size;
14107c478bd9Sstevel@tonic-gate 	ct->d_args.desc_num = desc_num;
14117c478bd9Sstevel@tonic-gate 	/*
14127c478bd9Sstevel@tonic-gate 	 * Transfer results, if any, to the client
14137c478bd9Sstevel@tonic-gate 	 */
14147c478bd9Sstevel@tonic-gate 	if (data_size != 0 || desc_num != 0) {
14157c478bd9Sstevel@tonic-gate 		/*
14167c478bd9Sstevel@tonic-gate 		 * Prevent the client from exiting until we have finished
14177c478bd9Sstevel@tonic-gate 		 * moving results.
14187c478bd9Sstevel@tonic-gate 		 */
14197c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
14207c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14217c478bd9Sstevel@tonic-gate 		error = door_results(caller, data_ptr, data_size,
14227c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num);
14237c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14247c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
14257c478bd9Sstevel@tonic-gate 		/*
14267c478bd9Sstevel@tonic-gate 		 * Pass EOVERFLOW errors back to the client
14277c478bd9Sstevel@tonic-gate 		 */
14287c478bd9Sstevel@tonic-gate 		if (error && error != EOVERFLOW) {
14297c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
14307c478bd9Sstevel@tonic-gate 			return (set_errno(error));
14317c478bd9Sstevel@tonic-gate 		}
14327c478bd9Sstevel@tonic-gate 	}
14337c478bd9Sstevel@tonic-gate out:
14347c478bd9Sstevel@tonic-gate 	/* Put ourselves on the available server thread list */
14357c478bd9Sstevel@tonic-gate 	door_release_server(st->d_pool, curthread);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	/*
14387c478bd9Sstevel@tonic-gate 	 * Make sure the caller is still waiting to be resumed
14397c478bd9Sstevel@tonic-gate 	 */
14407c478bd9Sstevel@tonic-gate 	if (caller) {
14417c478bd9Sstevel@tonic-gate 		disp_lock_t *tlp;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		thread_lock(caller);
14447c478bd9Sstevel@tonic-gate 		ct->d_error = error;		/* Return any errors */
14457c478bd9Sstevel@tonic-gate 		if (caller->t_state == TS_SLEEP &&
14467c478bd9Sstevel@tonic-gate 		    SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) {
14477c478bd9Sstevel@tonic-gate 			cpu_t *cp = CPU;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 			tlp = caller->t_lockp;
14507c478bd9Sstevel@tonic-gate 			/*
14517c478bd9Sstevel@tonic-gate 			 * Setting t_disp_queue prevents erroneous preemptions
14527c478bd9Sstevel@tonic-gate 			 * if this thread is still in execution on another
14537c478bd9Sstevel@tonic-gate 			 * processor
14547c478bd9Sstevel@tonic-gate 			 */
14557c478bd9Sstevel@tonic-gate 			caller->t_disp_queue = cp->cpu_disp;
14567c478bd9Sstevel@tonic-gate 			CL_ACTIVE(caller);
14577c478bd9Sstevel@tonic-gate 			/*
14587c478bd9Sstevel@tonic-gate 			 * We are calling thread_onproc() instead of
14597c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC() because compiler can reorder
14607c478bd9Sstevel@tonic-gate 			 * the two stores of t_state and t_lockp in
14617c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC().
14627c478bd9Sstevel@tonic-gate 			 */
14637c478bd9Sstevel@tonic-gate 			thread_onproc(caller, cp);
14647c478bd9Sstevel@tonic-gate 			disp_lock_exit_high(tlp);
14657c478bd9Sstevel@tonic-gate 			shuttle_resume(caller, &door_knob);
14667c478bd9Sstevel@tonic-gate 		} else {
14677c478bd9Sstevel@tonic-gate 			/* May have been setrun or in stop state */
14687c478bd9Sstevel@tonic-gate 			thread_unlock(caller);
14697c478bd9Sstevel@tonic-gate 			shuttle_swtch(&door_knob);
14707c478bd9Sstevel@tonic-gate 		}
14717c478bd9Sstevel@tonic-gate 	} else {
14727c478bd9Sstevel@tonic-gate 		shuttle_swtch(&door_knob);
14737c478bd9Sstevel@tonic-gate 	}
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	/*
14767c478bd9Sstevel@tonic-gate 	 * We've sprung to life. Determine if we are part of a door
14777c478bd9Sstevel@tonic-gate 	 * invocation, or just interrupted
14787c478bd9Sstevel@tonic-gate 	 */
14797c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
14807c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
14817c478bd9Sstevel@tonic-gate 		/*
14827c478bd9Sstevel@tonic-gate 		 * Normal door invocation. Return any error condition
14837c478bd9Sstevel@tonic-gate 		 * encountered while trying to pass args to the server
14847c478bd9Sstevel@tonic-gate 		 * thread.
14857c478bd9Sstevel@tonic-gate 		 */
14867c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
14877c478bd9Sstevel@tonic-gate 		/*
14887c478bd9Sstevel@tonic-gate 		 * Prevent the caller from leaving us while we
14897c478bd9Sstevel@tonic-gate 		 * are copying out the arguments from it's buffer.
14907c478bd9Sstevel@tonic-gate 		 */
14917c478bd9Sstevel@tonic-gate 		ASSERT(st->d_caller != NULL);
14927c478bd9Sstevel@tonic-gate 		ct = DOOR_CLIENT(st->d_caller->t_door);
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
14957c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14967c478bd9Sstevel@tonic-gate 		error = door_server_dispatch(ct, dp);
14977c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14987c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
14997c478bd9Sstevel@tonic-gate 
1500*48bbca81SDaniel Hoffman 		/* let the client know we have processed its message */
1501289175a0Sjwadams 		ct->d_args_done = 1;
1502289175a0Sjwadams 
15037c478bd9Sstevel@tonic-gate 		if (error) {
15047c478bd9Sstevel@tonic-gate 			caller = st->d_caller;
15057c478bd9Sstevel@tonic-gate 			if (caller)
15067c478bd9Sstevel@tonic-gate 				ct = DOOR_CLIENT(caller->t_door);
15077c478bd9Sstevel@tonic-gate 			else
15087c478bd9Sstevel@tonic-gate 				ct = NULL;
15097c478bd9Sstevel@tonic-gate 			goto out;
15107c478bd9Sstevel@tonic-gate 		}
15117c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
15127c478bd9Sstevel@tonic-gate 		return (0);
15137c478bd9Sstevel@tonic-gate 	} else {
15147c478bd9Sstevel@tonic-gate 		/*
15157c478bd9Sstevel@tonic-gate 		 * We are not involved in a door_invocation.
15167c478bd9Sstevel@tonic-gate 		 * Check for /proc related activity...
15177c478bd9Sstevel@tonic-gate 		 */
15187c478bd9Sstevel@tonic-gate 		st->d_caller = NULL;
1519c4ace179Sdm 		door_server_exit(curproc, curthread);
15207c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
1521a574db85Sraf 		cancel_pending = 0;
1522a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
1523a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
1524a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
1525a574db85Sraf 			if (cancel_pending)
1526a574db85Sraf 				schedctl_cancel_eintr();
15277c478bd9Sstevel@tonic-gate 			lwp->lwp_asleep = 0;
15287c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
15297c478bd9Sstevel@tonic-gate 			return (set_errno(EINTR));
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 		/* Go back and wait for another request */
15327c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
15337c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
15347c478bd9Sstevel@tonic-gate 		caller = NULL;
15357c478bd9Sstevel@tonic-gate 		goto out;
15367c478bd9Sstevel@tonic-gate 	}
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate /*
15407c478bd9Sstevel@tonic-gate  * Revoke any future invocations on this door
15417c478bd9Sstevel@tonic-gate  */
15427c478bd9Sstevel@tonic-gate int
15437c478bd9Sstevel@tonic-gate door_revoke(int did)
15447c478bd9Sstevel@tonic-gate {
15457c478bd9Sstevel@tonic-gate 	door_node_t	*d;
15467c478bd9Sstevel@tonic-gate 	int		error;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	if ((d = door_lookup(did, NULL)) == NULL)
15497c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
15527c478bd9Sstevel@tonic-gate 	if (d->door_target != curproc) {
15537c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
15547c478bd9Sstevel@tonic-gate 		releasef(did);
15557c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
15567c478bd9Sstevel@tonic-gate 	}
15577c478bd9Sstevel@tonic-gate 	d->door_flags |= DOOR_REVOKED;
15587c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_PRIVATE)
15597c478bd9Sstevel@tonic-gate 		cv_broadcast(&d->door_servers.dp_cv);
15607c478bd9Sstevel@tonic-gate 	else
15617c478bd9Sstevel@tonic-gate 		cv_broadcast(&curproc->p_server_threads.dp_cv);
15627c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
15637c478bd9Sstevel@tonic-gate 	releasef(did);
15647c478bd9Sstevel@tonic-gate 	/* Invalidate the descriptor */
15657c478bd9Sstevel@tonic-gate 	if ((error = closeandsetf(did, NULL)) != 0)
15667c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15677c478bd9Sstevel@tonic-gate 	return (0);
15687c478bd9Sstevel@tonic-gate }
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate int
15717c478bd9Sstevel@tonic-gate door_info(int did, struct door_info *d_info)
15727c478bd9Sstevel@tonic-gate {
15737c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
15747c478bd9Sstevel@tonic-gate 	door_info_t	di;
15757c478bd9Sstevel@tonic-gate 	door_server_t	*st;
15767c478bd9Sstevel@tonic-gate 	file_t		*fp = NULL;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	if (did == DOOR_QUERY) {
15797c478bd9Sstevel@tonic-gate 		/* Get information on door current thread is bound to */
15807c478bd9Sstevel@tonic-gate 		if ((st = door_my_server(0)) == NULL ||
15817c478bd9Sstevel@tonic-gate 		    (dp = st->d_pool) == NULL)
15827c478bd9Sstevel@tonic-gate 			/* Thread isn't bound to a door */
15837c478bd9Sstevel@tonic-gate 			return (set_errno(EBADF));
15847c478bd9Sstevel@tonic-gate 	} else if ((dp = door_lookup(did, &fp)) == NULL) {
15857c478bd9Sstevel@tonic-gate 		/* Not a door */
15867c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15877c478bd9Sstevel@tonic-gate 	}
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	door_info_common(dp, &di, fp);
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	if (did != DOOR_QUERY)
15927c478bd9Sstevel@tonic-gate 		releasef(did);
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	if (copyout(&di, d_info, sizeof (struct door_info)))
15957c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
15967c478bd9Sstevel@tonic-gate 	return (0);
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate /*
16007c478bd9Sstevel@tonic-gate  * Common code for getting information about a door either via the
16017c478bd9Sstevel@tonic-gate  * door_info system call or the door_ki_info kernel call.
16027c478bd9Sstevel@tonic-gate  */
16037c478bd9Sstevel@tonic-gate void
16047c478bd9Sstevel@tonic-gate door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp)
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate 	int unref_count;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	bzero(dip, sizeof (door_info_t));
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16117c478bd9Sstevel@tonic-gate 	if (dp->door_target == NULL)
16127c478bd9Sstevel@tonic-gate 		dip->di_target = -1;
16137c478bd9Sstevel@tonic-gate 	else
16147c478bd9Sstevel@tonic-gate 		dip->di_target = dp->door_target->p_pid;
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 	dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK;
16177c478bd9Sstevel@tonic-gate 	if (dp->door_target == curproc)
16187c478bd9Sstevel@tonic-gate 		dip->di_attributes |= DOOR_LOCAL;
16197c478bd9Sstevel@tonic-gate 	dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
16207c478bd9Sstevel@tonic-gate 	dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data;
16217c478bd9Sstevel@tonic-gate 	dip->di_uniquifier = dp->door_index;
16227c478bd9Sstevel@tonic-gate 	/*
16237c478bd9Sstevel@tonic-gate 	 * If this door is in the middle of having an unreferenced
16247c478bd9Sstevel@tonic-gate 	 * notification delivered, don't count the VN_HOLD by
16257c478bd9Sstevel@tonic-gate 	 * door_deliver_unref in determining if it is unreferenced.
16267c478bd9Sstevel@tonic-gate 	 * This handles the case where door_info is called from the
16277c478bd9Sstevel@tonic-gate 	 * thread delivering the unref notification.
16287c478bd9Sstevel@tonic-gate 	 */
16297c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_UNREF_ACTIVE)
16307c478bd9Sstevel@tonic-gate 		unref_count = 2;
16317c478bd9Sstevel@tonic-gate 	else
16327c478bd9Sstevel@tonic-gate 		unref_count = 1;
16337c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
16367c478bd9Sstevel@tonic-gate 		/*
16377c478bd9Sstevel@tonic-gate 		 * If this thread is bound to the door, then we can just
16387c478bd9Sstevel@tonic-gate 		 * check the vnode; a ref count of 1 (or 2 if this is
16397c478bd9Sstevel@tonic-gate 		 * handling an unref notification) means that the hold
16407c478bd9Sstevel@tonic-gate 		 * from the door_bind is the only reference to the door
16417c478bd9Sstevel@tonic-gate 		 * (no file descriptor refers to it).
16427c478bd9Sstevel@tonic-gate 		 */
16437c478bd9Sstevel@tonic-gate 		if (DTOV(dp)->v_count == unref_count)
16447c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16457c478bd9Sstevel@tonic-gate 	} else {
16467c478bd9Sstevel@tonic-gate 		/*
16477c478bd9Sstevel@tonic-gate 		 * If we're working from a file descriptor or door handle
16487c478bd9Sstevel@tonic-gate 		 * we need to look at the file structure count.  We don't
16497c478bd9Sstevel@tonic-gate 		 * need to hold the vnode lock since this is just a snapshot.
16507c478bd9Sstevel@tonic-gate 		 */
16517c478bd9Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
16527c478bd9Sstevel@tonic-gate 		if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count)
16537c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16547c478bd9Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
16557c478bd9Sstevel@tonic-gate 	}
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate /*
16597c478bd9Sstevel@tonic-gate  * Return credentials of the door caller (if any) for this invocation
16607c478bd9Sstevel@tonic-gate  */
16617c478bd9Sstevel@tonic-gate int
16627c478bd9Sstevel@tonic-gate door_ucred(struct ucred_s *uch)
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate 	kthread_t	*caller;
16657c478bd9Sstevel@tonic-gate 	door_server_t	*st;
16667c478bd9Sstevel@tonic-gate 	door_client_t	*ct;
1667323a81d9Sjwadams 	door_upcall_t	*dup;
16687c478bd9Sstevel@tonic-gate 	struct proc	*p;
16697c478bd9Sstevel@tonic-gate 	struct ucred_s	*res;
16707c478bd9Sstevel@tonic-gate 	int		err;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16737c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL ||
16747c478bd9Sstevel@tonic-gate 	    (caller = st->d_caller) == NULL) {
16757c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
16767c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
16777c478bd9Sstevel@tonic-gate 	}
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	ASSERT(caller->t_door != NULL);
16807c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/* Prevent caller from exiting while we examine the cred */
16837c478bd9Sstevel@tonic-gate 	DOOR_T_HOLD(ct);
16847c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	p = ttoproc(caller);
16877c478bd9Sstevel@tonic-gate 
1688024b0a25Sseb 	/*
1689024b0a25Sseb 	 * If the credentials are not specified by the client, get the one
1690024b0a25Sseb 	 * associated with the calling process.
1691024b0a25Sseb 	 */
1692323a81d9Sjwadams 	if ((dup = ct->d_upcall) != NULL)
1693323a81d9Sjwadams 		res = cred2ucred(dup->du_cred, p0.p_pid, NULL, CRED());
1694323a81d9Sjwadams 	else
1695323a81d9Sjwadams 		res = cred2ucred(caller->t_cred, p->p_pid, NULL, CRED());
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16987c478bd9Sstevel@tonic-gate 	DOOR_T_RELEASE(ct);
16997c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	err = copyout(res, uch, res->uc_size);
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	kmem_free(res, res->uc_size);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	if (err != 0)
17067c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	return (0);
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate /*
17127c478bd9Sstevel@tonic-gate  * Bind the current lwp to the server thread pool associated with 'did'
17137c478bd9Sstevel@tonic-gate  */
17147c478bd9Sstevel@tonic-gate int
17157c478bd9Sstevel@tonic-gate door_bind(int did)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
17187c478bd9Sstevel@tonic-gate 	door_server_t	*st;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL) {
17217c478bd9Sstevel@tonic-gate 		/* Not a door */
17227c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	/*
17267c478bd9Sstevel@tonic-gate 	 * Can't bind to a non-private door, and can't bind to a door
17277c478bd9Sstevel@tonic-gate 	 * served by another process.
17287c478bd9Sstevel@tonic-gate 	 */
17297c478bd9Sstevel@tonic-gate 	if ((dp->door_flags & DOOR_PRIVATE) == 0 ||
17307c478bd9Sstevel@tonic-gate 	    dp->door_target != curproc) {
17317c478bd9Sstevel@tonic-gate 		releasef(did);
17327c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	st = door_my_server(1);
17367c478bd9Sstevel@tonic-gate 	if (st->d_pool)
17377c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);
17387c478bd9Sstevel@tonic-gate 	st->d_pool = dp;
17397c478bd9Sstevel@tonic-gate 	st->d_invbound = 0;
17407c478bd9Sstevel@tonic-gate 	door_bind_thread(dp);
17417c478bd9Sstevel@tonic-gate 	releasef(did);
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	return (0);
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate /*
17477c478bd9Sstevel@tonic-gate  * Unbind the current lwp from it's server thread pool
17487c478bd9Sstevel@tonic-gate  */
17497c478bd9Sstevel@tonic-gate int
17507c478bd9Sstevel@tonic-gate door_unbind(void)
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate 	door_server_t *st;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL)
17557c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	if (st->d_invbound) {
17587c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool == NULL);
17597c478bd9Sstevel@tonic-gate 		st->d_invbound = 0;
17607c478bd9Sstevel@tonic-gate 		return (0);
17617c478bd9Sstevel@tonic-gate 	}
17627c478bd9Sstevel@tonic-gate 	if (st->d_pool == NULL)
17637c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17647c478bd9Sstevel@tonic-gate 	door_unbind_thread(st->d_pool);
17657c478bd9Sstevel@tonic-gate 	st->d_pool = NULL;
17667c478bd9Sstevel@tonic-gate 	return (0);
17677c478bd9Sstevel@tonic-gate }
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate /*
17707c478bd9Sstevel@tonic-gate  * Create a descriptor for the associated file and fill in the
17717c478bd9Sstevel@tonic-gate  * attributes associated with it.
17727c478bd9Sstevel@tonic-gate  *
17737c478bd9Sstevel@tonic-gate  * Return 0 for success, -1 otherwise;
17747c478bd9Sstevel@tonic-gate  */
17757c478bd9Sstevel@tonic-gate int
17767c478bd9Sstevel@tonic-gate door_insert(struct file *fp, door_desc_t *dp)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate 	struct vnode *vp;
17797c478bd9Sstevel@tonic-gate 	int	fd;
17807c478bd9Sstevel@tonic-gate 	door_attr_t attributes = DOOR_DESCRIPTOR;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
17837c478bd9Sstevel@tonic-gate 	if ((fd = ufalloc(0)) == -1)
17847c478bd9Sstevel@tonic-gate 		return (-1);
17857c478bd9Sstevel@tonic-gate 	setf(fd, fp);
17867c478bd9Sstevel@tonic-gate 	dp->d_data.d_desc.d_descriptor = fd;
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	/* Fill in the attributes */
1789da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
17907c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
17917c478bd9Sstevel@tonic-gate 	if (vp && vp->v_type == VDOOR) {
17927c478bd9Sstevel@tonic-gate 		if (VTOD(vp)->door_target == curproc)
17937c478bd9Sstevel@tonic-gate 			attributes |= DOOR_LOCAL;
17947c478bd9Sstevel@tonic-gate 		attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK;
17957c478bd9Sstevel@tonic-gate 		dp->d_data.d_desc.d_id = VTOD(vp)->door_index;
17967c478bd9Sstevel@tonic-gate 	}
17977c478bd9Sstevel@tonic-gate 	dp->d_attributes = attributes;
17987c478bd9Sstevel@tonic-gate 	return (0);
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate /*
18027c478bd9Sstevel@tonic-gate  * Return an available thread for this server.  A NULL return value indicates
18037c478bd9Sstevel@tonic-gate  * that either:
18047c478bd9Sstevel@tonic-gate  *	The door has been revoked, or
18057c478bd9Sstevel@tonic-gate  *	a signal was received.
18067c478bd9Sstevel@tonic-gate  * The two conditions can be differentiated using DOOR_INVALID(dp).
18077c478bd9Sstevel@tonic-gate  */
18087c478bd9Sstevel@tonic-gate static kthread_t *
18097c478bd9Sstevel@tonic-gate door_get_server(door_node_t *dp)
18107c478bd9Sstevel@tonic-gate {
18117c478bd9Sstevel@tonic-gate 	kthread_t **ktp;
18127c478bd9Sstevel@tonic-gate 	kthread_t *server_t;
18137c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
18147c478bd9Sstevel@tonic-gate 	door_server_t *st;
18157c478bd9Sstevel@tonic-gate 	int signalled;
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	disp_lock_t *tlp;
18187c478bd9Sstevel@tonic-gate 	cpu_t *cp;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_PRIVATE)
18237c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
18247c478bd9Sstevel@tonic-gate 	else
18257c478bd9Sstevel@tonic-gate 		pool = &dp->door_target->p_server_threads;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	for (;;) {
18287c478bd9Sstevel@tonic-gate 		/*
18297c478bd9Sstevel@tonic-gate 		 * We search the thread pool, looking for a server thread
18307c478bd9Sstevel@tonic-gate 		 * ready to take an invocation (i.e. one which is still
18317c478bd9Sstevel@tonic-gate 		 * sleeping on a shuttle object).  If none are available,
18327c478bd9Sstevel@tonic-gate 		 * we sleep on the pool's CV, and will be signaled when a
18337c478bd9Sstevel@tonic-gate 		 * thread is added to the pool.
18347c478bd9Sstevel@tonic-gate 		 *
18357c478bd9Sstevel@tonic-gate 		 * This relies on the fact that once a thread in the thread
18367c478bd9Sstevel@tonic-gate 		 * pool wakes up, it *must* remove and add itself to the pool
18377c478bd9Sstevel@tonic-gate 		 * before it can receive door calls.
18387c478bd9Sstevel@tonic-gate 		 */
18397c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
18407c478bd9Sstevel@tonic-gate 			return (NULL);	/* Target has become invalid */
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 		for (ktp = &pool->dp_threads;
18437c478bd9Sstevel@tonic-gate 		    (server_t = *ktp) != NULL;
18447c478bd9Sstevel@tonic-gate 		    ktp = &st->d_servers) {
18457c478bd9Sstevel@tonic-gate 			st = DOOR_SERVER(server_t->t_door);
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 			thread_lock(server_t);
18487c478bd9Sstevel@tonic-gate 			if (server_t->t_state == TS_SLEEP &&
18497c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE)
18507c478bd9Sstevel@tonic-gate 				break;
18517c478bd9Sstevel@tonic-gate 			thread_unlock(server_t);
18527c478bd9Sstevel@tonic-gate 		}
18537c478bd9Sstevel@tonic-gate 		if (server_t != NULL)
18547c478bd9Sstevel@tonic-gate 			break;		/* we've got a live one! */
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
18577c478bd9Sstevel@tonic-gate 		    &signalled)) {
18587c478bd9Sstevel@tonic-gate 			/*
1859da6c28aaSamw 			 * If we were signaled and the door is still
18607c478bd9Sstevel@tonic-gate 			 * valid, pass the signal on to another waiter.
18617c478bd9Sstevel@tonic-gate 			 */
18627c478bd9Sstevel@tonic-gate 			if (signalled && !DOOR_INVALID(dp))
18637c478bd9Sstevel@tonic-gate 				cv_signal(&pool->dp_cv);
18647c478bd9Sstevel@tonic-gate 			return (NULL);	/* Got a signal */
18657c478bd9Sstevel@tonic-gate 		}
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	/*
18697c478bd9Sstevel@tonic-gate 	 * We've got a thread_lock()ed thread which is still on the
18707c478bd9Sstevel@tonic-gate 	 * shuttle.  Take it off the list of available server threads
18717c478bd9Sstevel@tonic-gate 	 * and mark it as ONPROC.  We are committed to resuming this
18727c478bd9Sstevel@tonic-gate 	 * thread now.
18737c478bd9Sstevel@tonic-gate 	 */
18747c478bd9Sstevel@tonic-gate 	tlp = server_t->t_lockp;
18757c478bd9Sstevel@tonic-gate 	cp = CPU;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	*ktp = st->d_servers;
18787c478bd9Sstevel@tonic-gate 	st->d_servers = NULL;
18797c478bd9Sstevel@tonic-gate 	/*
18807c478bd9Sstevel@tonic-gate 	 * Setting t_disp_queue prevents erroneous preemptions
18817c478bd9Sstevel@tonic-gate 	 * if this thread is still in execution on another processor
18827c478bd9Sstevel@tonic-gate 	 */
18837c478bd9Sstevel@tonic-gate 	server_t->t_disp_queue = cp->cpu_disp;
18847c478bd9Sstevel@tonic-gate 	CL_ACTIVE(server_t);
18857c478bd9Sstevel@tonic-gate 	/*
18867c478bd9Sstevel@tonic-gate 	 * We are calling thread_onproc() instead of
18877c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC() because compiler can reorder
18887c478bd9Sstevel@tonic-gate 	 * the two stores of t_state and t_lockp in
18897c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC().
18907c478bd9Sstevel@tonic-gate 	 */
18917c478bd9Sstevel@tonic-gate 	thread_onproc(server_t, cp);
18927c478bd9Sstevel@tonic-gate 	disp_lock_exit(tlp);
18937c478bd9Sstevel@tonic-gate 	return (server_t);
18947c478bd9Sstevel@tonic-gate }
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate /*
18977c478bd9Sstevel@tonic-gate  * Put a server thread back in the pool.
18987c478bd9Sstevel@tonic-gate  */
18997c478bd9Sstevel@tonic-gate static void
19007c478bd9Sstevel@tonic-gate door_release_server(door_node_t *dp, kthread_t *t)
19017c478bd9Sstevel@tonic-gate {
19027c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
19037c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
19067c478bd9Sstevel@tonic-gate 	st->d_active = NULL;
19077c478bd9Sstevel@tonic-gate 	st->d_caller = NULL;
19087c478bd9Sstevel@tonic-gate 	st->d_layout_done = 0;
19097c478bd9Sstevel@tonic-gate 	if (dp && (dp->door_flags & DOOR_PRIVATE)) {
19107c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == NULL ||
19117c478bd9Sstevel@tonic-gate 		    dp->door_target == ttoproc(t));
19127c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
19137c478bd9Sstevel@tonic-gate 	} else {
19147c478bd9Sstevel@tonic-gate 		pool = &ttoproc(t)->p_server_threads;
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate 	st->d_servers = pool->dp_threads;
19187c478bd9Sstevel@tonic-gate 	pool->dp_threads = t;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/* If someone is waiting for a server thread, wake him up */
19217c478bd9Sstevel@tonic-gate 	cv_signal(&pool->dp_cv);
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate /*
19257c478bd9Sstevel@tonic-gate  * Remove a server thread from the pool if present.
19267c478bd9Sstevel@tonic-gate  */
1927c4ace179Sdm static void
19287c478bd9Sstevel@tonic-gate door_server_exit(proc_t *p, kthread_t *t)
19297c478bd9Sstevel@tonic-gate {
19307c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
19317c478bd9Sstevel@tonic-gate 	kthread_t **next;
19327c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
19357c478bd9Sstevel@tonic-gate 	if (st->d_pool != NULL) {
19367c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool->door_flags & DOOR_PRIVATE);
19377c478bd9Sstevel@tonic-gate 		pool = &st->d_pool->door_servers;
19387c478bd9Sstevel@tonic-gate 	} else {
19397c478bd9Sstevel@tonic-gate 		pool = &p->p_server_threads;
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	next = &pool->dp_threads;
19437c478bd9Sstevel@tonic-gate 	while (*next != NULL) {
19447c478bd9Sstevel@tonic-gate 		if (*next == t) {
19457c478bd9Sstevel@tonic-gate 			*next = DOOR_SERVER(t->t_door)->d_servers;
1946c4ace179Sdm 			return;
19477c478bd9Sstevel@tonic-gate 		}
19487c478bd9Sstevel@tonic-gate 		next = &(DOOR_SERVER((*next)->t_door)->d_servers);
19497c478bd9Sstevel@tonic-gate 	}
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate /*
19537c478bd9Sstevel@tonic-gate  * Lookup the door descriptor. Caller must call releasef when finished
19547c478bd9Sstevel@tonic-gate  * with associated door.
19557c478bd9Sstevel@tonic-gate  */
19567c478bd9Sstevel@tonic-gate static door_node_t *
19577c478bd9Sstevel@tonic-gate door_lookup(int did, file_t **fpp)
19587c478bd9Sstevel@tonic-gate {
19597c478bd9Sstevel@tonic-gate 	vnode_t	*vp;
19607c478bd9Sstevel@tonic-gate 	file_t *fp;
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
19637c478bd9Sstevel@tonic-gate 	if ((fp = getf(did)) == NULL)
19647c478bd9Sstevel@tonic-gate 		return (NULL);
19657c478bd9Sstevel@tonic-gate 	/*
19667c478bd9Sstevel@tonic-gate 	 * Use the underlying vnode (we may be namefs mounted)
19677c478bd9Sstevel@tonic-gate 	 */
1968da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
19697c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_type != VDOOR) {
19727c478bd9Sstevel@tonic-gate 		releasef(did);
19737c478bd9Sstevel@tonic-gate 		return (NULL);
19747c478bd9Sstevel@tonic-gate 	}
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	if (fpp)
19777c478bd9Sstevel@tonic-gate 		*fpp = fp;
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	return (VTOD(vp));
19807c478bd9Sstevel@tonic-gate }
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate /*
19837c478bd9Sstevel@tonic-gate  * The current thread is exiting, so clean up any pending
19847c478bd9Sstevel@tonic-gate  * invocation details
19857c478bd9Sstevel@tonic-gate  */
19867c478bd9Sstevel@tonic-gate void
19877c478bd9Sstevel@tonic-gate door_slam(void)
19887c478bd9Sstevel@tonic-gate {
19897c478bd9Sstevel@tonic-gate 	door_node_t *dp;
19907c478bd9Sstevel@tonic-gate 	door_data_t *dt;
19917c478bd9Sstevel@tonic-gate 	door_client_t *ct;
19927c478bd9Sstevel@tonic-gate 	door_server_t *st;
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	/*
19957c478bd9Sstevel@tonic-gate 	 * If we are an active door server, notify our
19967c478bd9Sstevel@tonic-gate 	 * client that we are exiting and revoke our door.
19977c478bd9Sstevel@tonic-gate 	 */
19987c478bd9Sstevel@tonic-gate 	if ((dt = door_my_data(0)) == NULL)
19997c478bd9Sstevel@tonic-gate 		return;
20007c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(dt);
20017c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(dt);
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20047c478bd9Sstevel@tonic-gate 	for (;;) {
20057c478bd9Sstevel@tonic-gate 		if (DOOR_T_HELD(ct))
20067c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
20077c478bd9Sstevel@tonic-gate 		else if (DOOR_T_HELD(st))
20087c478bd9Sstevel@tonic-gate 			cv_wait(&st->d_cv, &door_knob);
20097c478bd9Sstevel@tonic-gate 		else
20107c478bd9Sstevel@tonic-gate 			break;			/* neither flag is set */
20117c478bd9Sstevel@tonic-gate 	}
20127c478bd9Sstevel@tonic-gate 	curthread->t_door = NULL;
20137c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
20147c478bd9Sstevel@tonic-gate 		kthread_t *t = st->d_caller;
20157c478bd9Sstevel@tonic-gate 		proc_t *p = curproc;
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 		/* Revoke our door if the process is exiting */
201897eda132Sraf 		if (dp->door_target == p && (p->p_flag & SEXITING)) {
20197c478bd9Sstevel@tonic-gate 			door_list_delete(dp);
20207c478bd9Sstevel@tonic-gate 			dp->door_target = NULL;
20217c478bd9Sstevel@tonic-gate 			dp->door_flags |= DOOR_REVOKED;
20227c478bd9Sstevel@tonic-gate 			if (dp->door_flags & DOOR_PRIVATE)
20237c478bd9Sstevel@tonic-gate 				cv_broadcast(&dp->door_servers.dp_cv);
20247c478bd9Sstevel@tonic-gate 			else
20257c478bd9Sstevel@tonic-gate 				cv_broadcast(&p->p_server_threads.dp_cv);
20267c478bd9Sstevel@tonic-gate 		}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 		if (t != NULL) {
20297c478bd9Sstevel@tonic-gate 			/*
20307c478bd9Sstevel@tonic-gate 			 * Let the caller know we are gone
20317c478bd9Sstevel@tonic-gate 			 */
20327c478bd9Sstevel@tonic-gate 			DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT;
20337c478bd9Sstevel@tonic-gate 			thread_lock(t);
20347c478bd9Sstevel@tonic-gate 			if (t->t_state == TS_SLEEP &&
20357c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE)
20367c478bd9Sstevel@tonic-gate 				setrun_locked(t);
20377c478bd9Sstevel@tonic-gate 			thread_unlock(t);
20387c478bd9Sstevel@tonic-gate 		}
20397c478bd9Sstevel@tonic-gate 	}
20407c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20417c478bd9Sstevel@tonic-gate 	if (st->d_pool)
20427c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);	/* Implicit door_unbind */
20437c478bd9Sstevel@tonic-gate 	kmem_free(dt, sizeof (door_data_t));
20447c478bd9Sstevel@tonic-gate }
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate /*
20477c478bd9Sstevel@tonic-gate  * Set DOOR_REVOKED for all doors of the current process. This is called
20487c478bd9Sstevel@tonic-gate  * on exit before all lwp's are being terminated so that door calls will
20497c478bd9Sstevel@tonic-gate  * return with an error.
20507c478bd9Sstevel@tonic-gate  */
20517c478bd9Sstevel@tonic-gate void
20527c478bd9Sstevel@tonic-gate door_revoke_all()
20537c478bd9Sstevel@tonic-gate {
20547c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20557c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20587c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20597c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == p);
20607c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20617c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20627c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20637c478bd9Sstevel@tonic-gate 	}
20647c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20657c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20667c478bd9Sstevel@tonic-gate }
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate /*
20697c478bd9Sstevel@tonic-gate  * The process is exiting, and all doors it created need to be revoked.
20707c478bd9Sstevel@tonic-gate  */
20717c478bd9Sstevel@tonic-gate void
20727c478bd9Sstevel@tonic-gate door_exit(void)
20737c478bd9Sstevel@tonic-gate {
20747c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20757c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1);
20787c478bd9Sstevel@tonic-gate 	/*
20797c478bd9Sstevel@tonic-gate 	 * Walk the list of active doors created by this process and
20807c478bd9Sstevel@tonic-gate 	 * revoke them all.
20817c478bd9Sstevel@tonic-gate 	 */
20827c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20837c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20847c478bd9Sstevel@tonic-gate 		dp->door_target = NULL;
20857c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20867c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20877c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20887c478bd9Sstevel@tonic-gate 	}
20897c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20907c478bd9Sstevel@tonic-gate 	/* Clear the list */
20917c478bd9Sstevel@tonic-gate 	p->p_door_list = NULL;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	/* Clean up the unref list */
20947c478bd9Sstevel@tonic-gate 	while ((dp = p->p_unref_list) != NULL) {
20957c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
20967c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
20977c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
20987c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
20997c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21007c478bd9Sstevel@tonic-gate 	}
21017c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate /*
21067c478bd9Sstevel@tonic-gate  * The process is executing forkall(), and we need to flag threads that
21077c478bd9Sstevel@tonic-gate  * are bound to a door in the child.  This will make the child threads
21087c478bd9Sstevel@tonic-gate  * return an error to door_return unless they call door_unbind first.
21097c478bd9Sstevel@tonic-gate  */
21107c478bd9Sstevel@tonic-gate void
21117c478bd9Sstevel@tonic-gate door_fork(kthread_t *parent, kthread_t *child)
21127c478bd9Sstevel@tonic-gate {
21137c478bd9Sstevel@tonic-gate 	door_data_t *pt = parent->t_door;
21147c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(pt);
21157c478bd9Sstevel@tonic-gate 	door_data_t *dt;
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
21187c478bd9Sstevel@tonic-gate 	if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) {
21197c478bd9Sstevel@tonic-gate 		/* parent thread is bound to a door */
21207c478bd9Sstevel@tonic-gate 		dt = child->t_door =
21217c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sizeof (door_data_t), KM_SLEEP);
21227c478bd9Sstevel@tonic-gate 		DOOR_SERVER(dt)->d_invbound = 1;
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate }
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate /*
21277c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to appropriate door server.
21287c478bd9Sstevel@tonic-gate  */
21297c478bd9Sstevel@tonic-gate static int
21307c478bd9Sstevel@tonic-gate door_unref(void)
21317c478bd9Sstevel@tonic-gate {
21327c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
21337c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
21347c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	/* make sure there's only one unref thread per process */
21377c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
21387c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
21397c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21407c478bd9Sstevel@tonic-gate 		return (set_errno(EALREADY));
21417c478bd9Sstevel@tonic-gate 	}
21427c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
21437c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);			/* create info, if necessary */
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 	for (;;) {
21487c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
21517c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
21527c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) {
21537c478bd9Sstevel@tonic-gate 				/*
21547c478bd9Sstevel@tonic-gate 				 * Interrupted.
21557c478bd9Sstevel@tonic-gate 				 * Return so we can finish forkall() or exit().
21567c478bd9Sstevel@tonic-gate 				 */
21577c478bd9Sstevel@tonic-gate 				p->p_unref_thread = 0;
21587c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
21597c478bd9Sstevel@tonic-gate 				return (set_errno(EINTR));
21607c478bd9Sstevel@tonic-gate 			}
21617c478bd9Sstevel@tonic-gate 		}
21627c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
21637c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
21647c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
21657c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21667c478bd9Sstevel@tonic-gate 
2167323a81d9Sjwadams 		(void) door_upcall(DTOV(dp), &unref_args, NULL, SIZE_MAX, 0);
2168323a81d9Sjwadams 
2169323a81d9Sjwadams 		if (unref_args.rbuf != 0) {
2170323a81d9Sjwadams 			kmem_free(unref_args.rbuf, unref_args.rsize);
2171323a81d9Sjwadams 			unref_args.rbuf = NULL;
2172323a81d9Sjwadams 			unref_args.rsize = 0;
2173323a81d9Sjwadams 		}
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21767c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
21777c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
21787c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21797c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
21807c478bd9Sstevel@tonic-gate 	}
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate /*
21857c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to kernel door server.
21867c478bd9Sstevel@tonic-gate  */
21877c478bd9Sstevel@tonic-gate /* ARGSUSED */
21887c478bd9Sstevel@tonic-gate static void
21897c478bd9Sstevel@tonic-gate door_unref_kernel(caddr_t arg)
21907c478bd9Sstevel@tonic-gate {
21917c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
21927c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
21937c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
21947c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	/* should only be one of these */
21977c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
21987c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
21997c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
22007c478bd9Sstevel@tonic-gate 		return;
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
22037c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);		/* make sure we have a door_data_t */
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref");
22087c478bd9Sstevel@tonic-gate 	for (;;) {
22097c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
22107c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
22117c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
22127c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
22137c478bd9Sstevel@tonic-gate 			cv_wait(&p->p_unref_cv, &door_knob);
22147c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &door_knob);
22157c478bd9Sstevel@tonic-gate 		}
22167c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
22177c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
22187c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
22197c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL);
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
22247c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
22257c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
22267c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
22277c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
22287c478bd9Sstevel@tonic-gate 	}
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate /*
22337c478bd9Sstevel@tonic-gate  * Queue an unref invocation for processing for the current process
22347c478bd9Sstevel@tonic-gate  * The door may or may not be revoked at this point.
22357c478bd9Sstevel@tonic-gate  */
22367c478bd9Sstevel@tonic-gate void
22377c478bd9Sstevel@tonic-gate door_deliver_unref(door_node_t *d)
22387c478bd9Sstevel@tonic-gate {
22397c478bd9Sstevel@tonic-gate 	struct proc *server = d->door_target;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
22427c478bd9Sstevel@tonic-gate 	ASSERT(d->door_active == 0);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if (server == NULL)
22457c478bd9Sstevel@tonic-gate 		return;
22467c478bd9Sstevel@tonic-gate 	/*
22477c478bd9Sstevel@tonic-gate 	 * Create a lwp to deliver unref calls if one isn't already running.
22487c478bd9Sstevel@tonic-gate 	 *
22497c478bd9Sstevel@tonic-gate 	 * A separate thread is used to deliver unrefs since the current
22507c478bd9Sstevel@tonic-gate 	 * thread may be holding resources (e.g. locks) in user land that
22517c478bd9Sstevel@tonic-gate 	 * may be needed by the unref processing. This would cause a
22527c478bd9Sstevel@tonic-gate 	 * deadlock.
22537c478bd9Sstevel@tonic-gate 	 */
22547c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
22557c478bd9Sstevel@tonic-gate 		/* multiple unrefs */
22567c478bd9Sstevel@tonic-gate 		d->door_flags &= ~DOOR_DELAY;
22577c478bd9Sstevel@tonic-gate 	} else {
22587c478bd9Sstevel@tonic-gate 		/* Only 1 unref per door */
22597c478bd9Sstevel@tonic-gate 		d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY);
22607c478bd9Sstevel@tonic-gate 	}
22617c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	/*
22647c478bd9Sstevel@tonic-gate 	 * Need to bump the vnode count before putting the door on the
22657c478bd9Sstevel@tonic-gate 	 * list so it doesn't get prematurely released by door_unref.
22667c478bd9Sstevel@tonic-gate 	 */
22677c478bd9Sstevel@tonic-gate 	VN_HOLD(DTOV(d));
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
22707c478bd9Sstevel@tonic-gate 	/* is this door already on the unref list? */
22717c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
22727c478bd9Sstevel@tonic-gate 		door_node_t *dp;
22737c478bd9Sstevel@tonic-gate 		for (dp = server->p_unref_list; dp != NULL;
22747c478bd9Sstevel@tonic-gate 		    dp = dp->door_ulist) {
22757c478bd9Sstevel@tonic-gate 			if (d == dp) {
22767c478bd9Sstevel@tonic-gate 				/* already there, don't need to add another */
22777c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
22787c478bd9Sstevel@tonic-gate 				VN_RELE(DTOV(d));
22797c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
22807c478bd9Sstevel@tonic-gate 				return;
22817c478bd9Sstevel@tonic-gate 			}
22827c478bd9Sstevel@tonic-gate 		}
22837c478bd9Sstevel@tonic-gate 	}
22847c478bd9Sstevel@tonic-gate 	ASSERT(d->door_ulist == NULL);
22857c478bd9Sstevel@tonic-gate 	d->door_ulist = server->p_unref_list;
22867c478bd9Sstevel@tonic-gate 	server->p_unref_list = d;
22877c478bd9Sstevel@tonic-gate 	cv_broadcast(&server->p_unref_cv);
22887c478bd9Sstevel@tonic-gate }
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate /*
22917c478bd9Sstevel@tonic-gate  * The callers buffer isn't big enough for all of the data/fd's. Allocate
22927c478bd9Sstevel@tonic-gate  * space in the callers address space for the results and copy the data
22937c478bd9Sstevel@tonic-gate  * there.
22947c478bd9Sstevel@tonic-gate  *
22957c478bd9Sstevel@tonic-gate  * For EOVERFLOW, we must clean up the server's door descriptors.
22967c478bd9Sstevel@tonic-gate  */
22977c478bd9Sstevel@tonic-gate static int
22987c478bd9Sstevel@tonic-gate door_overflow(
22997c478bd9Sstevel@tonic-gate 	kthread_t	*caller,
23007c478bd9Sstevel@tonic-gate 	caddr_t		data_ptr,	/* data location */
23017c478bd9Sstevel@tonic-gate 	size_t		data_size,	/* data size */
23027c478bd9Sstevel@tonic-gate 	door_desc_t	*desc_ptr,	/* descriptor location */
23037c478bd9Sstevel@tonic-gate 	uint_t		desc_num)	/* descriptor size */
23047c478bd9Sstevel@tonic-gate {
23057c478bd9Sstevel@tonic-gate 	proc_t *callerp = ttoproc(caller);
23067c478bd9Sstevel@tonic-gate 	struct as *as = callerp->p_as;
23077c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(caller->t_door);
23087c478bd9Sstevel@tonic-gate 	caddr_t	addr;			/* Resulting address in target */
23097c478bd9Sstevel@tonic-gate 	size_t	rlen;			/* Rounded len */
23107c478bd9Sstevel@tonic-gate 	size_t	len;
23117c478bd9Sstevel@tonic-gate 	uint_t	i;
23127c478bd9Sstevel@tonic-gate 	size_t	ds = desc_num * sizeof (door_desc_t);
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
23157c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct) || ct->d_kernel);
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	/* Do initial overflow check */
23187c478bd9Sstevel@tonic-gate 	if (!ufcanalloc(callerp, desc_num))
23197c478bd9Sstevel@tonic-gate 		return (EMFILE);
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	/*
23227c478bd9Sstevel@tonic-gate 	 * Allocate space for this stuff in the callers address space
23237c478bd9Sstevel@tonic-gate 	 */
23247c478bd9Sstevel@tonic-gate 	rlen = roundup(data_size + ds, PAGESIZE);
23257c478bd9Sstevel@tonic-gate 	as_rangelock(as);
23267c478bd9Sstevel@tonic-gate 	map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0);
23277c478bd9Sstevel@tonic-gate 	if (addr == NULL ||
23287c478bd9Sstevel@tonic-gate 	    as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) {
23297c478bd9Sstevel@tonic-gate 		/* No virtual memory available, or anon mapping failed */
23307c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
23317c478bd9Sstevel@tonic-gate 		if (!ct->d_kernel && desc_num > 0) {
23327c478bd9Sstevel@tonic-gate 			int error = door_release_fds(desc_ptr, desc_num);
23337c478bd9Sstevel@tonic-gate 			if (error)
23347c478bd9Sstevel@tonic-gate 				return (error);
23357c478bd9Sstevel@tonic-gate 		}
23367c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
23377c478bd9Sstevel@tonic-gate 	}
23387c478bd9Sstevel@tonic-gate 	as_rangeunlock(as);
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	if (ct->d_kernel)
23417c478bd9Sstevel@tonic-gate 		goto out;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	if (data_size != 0) {
23447c478bd9Sstevel@tonic-gate 		caddr_t	src = data_ptr;
23457c478bd9Sstevel@tonic-gate 		caddr_t saddr = addr;
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 		/* Copy any data */
23487c478bd9Sstevel@tonic-gate 		len = data_size;
23497c478bd9Sstevel@tonic-gate 		while (len != 0) {
23507c478bd9Sstevel@tonic-gate 			int	amount;
23517c478bd9Sstevel@tonic-gate 			int	error;
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 			amount = len > PAGESIZE ? PAGESIZE : len;
23547c478bd9Sstevel@tonic-gate 			if ((error = door_copy(as, src, saddr, amount)) != 0) {
23557c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23567c478bd9Sstevel@tonic-gate 				return (error);
23577c478bd9Sstevel@tonic-gate 			}
23587c478bd9Sstevel@tonic-gate 			saddr += amount;
23597c478bd9Sstevel@tonic-gate 			src += amount;
23607c478bd9Sstevel@tonic-gate 			len -= amount;
23617c478bd9Sstevel@tonic-gate 		}
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 	/* Copy any fd's */
23647c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
23657c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp, *start;
23667c478bd9Sstevel@tonic-gate 		struct file	**fpp;
23677c478bd9Sstevel@tonic-gate 		int		fpp_size;
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(ds, KM_SLEEP);
2370289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp, ds)) {
23717c478bd9Sstevel@tonic-gate 			kmem_free(start, ds);
23727c478bd9Sstevel@tonic-gate 			(void) as_unmap(as, addr, rlen);
23737c478bd9Sstevel@tonic-gate 			return (EFAULT);
23747c478bd9Sstevel@tonic-gate 		}
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
23777c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
23787c478bd9Sstevel@tonic-gate 			/* make more space */
23797c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
23807c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
23817c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
23827c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
23837c478bd9Sstevel@tonic-gate 		}
23847c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
23877c478bd9Sstevel@tonic-gate 			struct file *fp;
23887c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
23917c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
23927c478bd9Sstevel@tonic-gate 				/* close translated references */
23937c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
23947c478bd9Sstevel@tonic-gate 				/* close untranslated references */
23957c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
23967c478bd9Sstevel@tonic-gate 				kmem_free(start, ds);
23977c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23987c478bd9Sstevel@tonic-gate 				return (EINVAL);
23997c478bd9Sstevel@tonic-gate 			}
24007c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
24017c478bd9Sstevel@tonic-gate 			fp->f_count++;
24027c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 			*fpp = fp;
24057c478bd9Sstevel@tonic-gate 			releasef(fd);
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
24087c478bd9Sstevel@tonic-gate 				/* release passed reference */
24097c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
24107c478bd9Sstevel@tonic-gate 			}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
24137c478bd9Sstevel@tonic-gate 		}
24147c478bd9Sstevel@tonic-gate 		kmem_free(start, ds);
24157c478bd9Sstevel@tonic-gate 	}
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate out:
24187c478bd9Sstevel@tonic-gate 	ct->d_overflow = 1;
24197c478bd9Sstevel@tonic-gate 	ct->d_args.rbuf = addr;
24207c478bd9Sstevel@tonic-gate 	ct->d_args.rsize = rlen;
24217c478bd9Sstevel@tonic-gate 	return (0);
24227c478bd9Sstevel@tonic-gate }
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate /*
24257c478bd9Sstevel@tonic-gate  * Transfer arguments from the client to the server.
24267c478bd9Sstevel@tonic-gate  */
24277c478bd9Sstevel@tonic-gate static int
24287c478bd9Sstevel@tonic-gate door_args(kthread_t *server, int is_private)
24297c478bd9Sstevel@tonic-gate {
24307c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(server->t_door);
24317c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
24327c478bd9Sstevel@tonic-gate 	uint_t	ndid;
24337c478bd9Sstevel@tonic-gate 	size_t	dsize;
24347c478bd9Sstevel@tonic-gate 	int	error;
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(st));
24377c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
24407c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
24417c478bd9Sstevel@tonic-gate 		return (E2BIG);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	/*
24447c478bd9Sstevel@tonic-gate 	 * Get the stack layout, and fail now if it won't fit.
24457c478bd9Sstevel@tonic-gate 	 */
24467c478bd9Sstevel@tonic-gate 	error = door_layout(server, ct->d_args.data_size, ndid, is_private);
24477c478bd9Sstevel@tonic-gate 	if (error != 0)
24487c478bd9Sstevel@tonic-gate 		return (error);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	dsize = ndid * sizeof (door_desc_t);
24517c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size != 0) {
24527c478bd9Sstevel@tonic-gate 		if (ct->d_args.data_size <= door_max_arg) {
24537c478bd9Sstevel@tonic-gate 			/*
24547c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
24557c478bd9Sstevel@tonic-gate 			 *
24567c478bd9Sstevel@tonic-gate 			 * Allocate a little more than we need for the
24577c478bd9Sstevel@tonic-gate 			 * args, in the hope that the results will fit
24587c478bd9Sstevel@tonic-gate 			 * without having to reallocate a buffer
24597c478bd9Sstevel@tonic-gate 			 */
24607c478bd9Sstevel@tonic-gate 			ASSERT(ct->d_buf == NULL);
24617c478bd9Sstevel@tonic-gate 			ct->d_bufsize = roundup(ct->d_args.data_size,
24627c478bd9Sstevel@tonic-gate 			    DOOR_ROUND);
24637c478bd9Sstevel@tonic-gate 			ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2464289175a0Sjwadams 			if (copyin_nowatch(ct->d_args.data_ptr,
24657c478bd9Sstevel@tonic-gate 			    ct->d_buf, ct->d_args.data_size) != 0) {
24667c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
24677c478bd9Sstevel@tonic-gate 				ct->d_buf = NULL;
24687c478bd9Sstevel@tonic-gate 				ct->d_bufsize = 0;
24697c478bd9Sstevel@tonic-gate 				return (EFAULT);
24707c478bd9Sstevel@tonic-gate 			}
24717c478bd9Sstevel@tonic-gate 		} else {
24727c478bd9Sstevel@tonic-gate 			struct as	*as;
24737c478bd9Sstevel@tonic-gate 			caddr_t		src;
24747c478bd9Sstevel@tonic-gate 			caddr_t		dest;
24757c478bd9Sstevel@tonic-gate 			size_t		len = ct->d_args.data_size;
24767c478bd9Sstevel@tonic-gate 			uintptr_t	base;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 			/*
24797c478bd9Sstevel@tonic-gate 			 * Use a 1 copy method
24807c478bd9Sstevel@tonic-gate 			 */
24817c478bd9Sstevel@tonic-gate 			as = ttoproc(server)->p_as;
24827c478bd9Sstevel@tonic-gate 			src = ct->d_args.data_ptr;
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 			dest = st->d_layout.dl_datap;
24857c478bd9Sstevel@tonic-gate 			base = (uintptr_t)dest;
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 			/*
24887c478bd9Sstevel@tonic-gate 			 * Copy data directly into server.  We proceed
24897c478bd9Sstevel@tonic-gate 			 * downward from the top of the stack, to mimic
24907c478bd9Sstevel@tonic-gate 			 * normal stack usage. This allows the guard page
24917c478bd9Sstevel@tonic-gate 			 * to stop us before we corrupt anything.
24927c478bd9Sstevel@tonic-gate 			 */
24937c478bd9Sstevel@tonic-gate 			while (len != 0) {
24947c478bd9Sstevel@tonic-gate 				uintptr_t start;
24957c478bd9Sstevel@tonic-gate 				uintptr_t end;
24967c478bd9Sstevel@tonic-gate 				uintptr_t offset;
24977c478bd9Sstevel@tonic-gate 				size_t	amount;
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 				/*
25007c478bd9Sstevel@tonic-gate 				 * Locate the next part to copy.
25017c478bd9Sstevel@tonic-gate 				 */
25027c478bd9Sstevel@tonic-gate 				end = base + len;
25037c478bd9Sstevel@tonic-gate 				start = P2ALIGN(end - 1, PAGESIZE);
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 				/*
25067c478bd9Sstevel@tonic-gate 				 * if we are on the final (first) page, fix
25077c478bd9Sstevel@tonic-gate 				 * up the start position.
25087c478bd9Sstevel@tonic-gate 				 */
25097c478bd9Sstevel@tonic-gate 				if (P2ALIGN(base, PAGESIZE) == start)
25107c478bd9Sstevel@tonic-gate 					start = base;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 				offset = start - base;	/* the copy offset */
25137c478bd9Sstevel@tonic-gate 				amount = end - start;	/* # bytes to copy */
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate 				ASSERT(amount > 0 && amount <= len &&
25167c478bd9Sstevel@tonic-gate 				    amount <= PAGESIZE);
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 				error = door_copy(as, src + offset,
25197c478bd9Sstevel@tonic-gate 				    dest + offset, amount);
25207c478bd9Sstevel@tonic-gate 				if (error != 0)
25217c478bd9Sstevel@tonic-gate 					return (error);
25227c478bd9Sstevel@tonic-gate 				len -= amount;
25237c478bd9Sstevel@tonic-gate 			}
25247c478bd9Sstevel@tonic-gate 		}
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 	/*
25277c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into files
25287c478bd9Sstevel@tonic-gate 	 */
25297c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
25307c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
25317c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
25327c478bd9Sstevel@tonic-gate 		struct file	**fpp;
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
25357c478bd9Sstevel@tonic-gate 
2536289175a0Sjwadams 		if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
25377c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
25387c478bd9Sstevel@tonic-gate 			return (EFAULT);
25397c478bd9Sstevel@tonic-gate 		}
25407c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
25417c478bd9Sstevel@tonic-gate 		ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
25427c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
25437c478bd9Sstevel@tonic-gate 		while (ndid--) {
25447c478bd9Sstevel@tonic-gate 			struct file *fp;
25457c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 			/* We only understand file descriptors as passed objs */
25487c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
25497c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
25507c478bd9Sstevel@tonic-gate 				/* close translated references */
25517c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
25527c478bd9Sstevel@tonic-gate 				/* close untranslated references */
25537c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
25547c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
25557c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
25567c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
25577c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
25587c478bd9Sstevel@tonic-gate 				return (EINVAL);
25597c478bd9Sstevel@tonic-gate 			}
25607c478bd9Sstevel@tonic-gate 			/* Hold the fp */
25617c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
25627c478bd9Sstevel@tonic-gate 			fp->f_count++;
25637c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 			*fpp = fp;
25667c478bd9Sstevel@tonic-gate 			releasef(fd);
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
25697c478bd9Sstevel@tonic-gate 				/* release passed reference */
25707c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
25717c478bd9Sstevel@tonic-gate 			}
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
25747c478bd9Sstevel@tonic-gate 		}
25757c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 	return (0);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate /*
25817c478bd9Sstevel@tonic-gate  * Transfer arguments from a user client to a kernel server.  This copies in
25827c478bd9Sstevel@tonic-gate  * descriptors and translates them into door handles.  It doesn't touch the
25837c478bd9Sstevel@tonic-gate  * other data, letting the kernel server deal with that (to avoid needing
25847c478bd9Sstevel@tonic-gate  * to copy the data twice).
25857c478bd9Sstevel@tonic-gate  */
25867c478bd9Sstevel@tonic-gate static int
25877c478bd9Sstevel@tonic-gate door_translate_in(void)
25887c478bd9Sstevel@tonic-gate {
25897c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
25907c478bd9Sstevel@tonic-gate 	uint_t	ndid;
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
25937c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
25947c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
25957c478bd9Sstevel@tonic-gate 		return (E2BIG);
25967c478bd9Sstevel@tonic-gate 	/*
25977c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into door handles.
25987c478bd9Sstevel@tonic-gate 	 */
25997c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
26007c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
26017c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
26027c478bd9Sstevel@tonic-gate 		size_t		dsize = ndid * sizeof (door_desc_t);
26037c478bd9Sstevel@tonic-gate 		struct file	*fp;
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
26067c478bd9Sstevel@tonic-gate 
2607289175a0Sjwadams 		if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
26087c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
26097c478bd9Sstevel@tonic-gate 			return (EFAULT);
26107c478bd9Sstevel@tonic-gate 		}
26117c478bd9Sstevel@tonic-gate 		while (ndid--) {
26127c478bd9Sstevel@tonic-gate 			vnode_t	*vp;
26137c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 			/*
26167c478bd9Sstevel@tonic-gate 			 * We only understand file descriptors as passed objs
26177c478bd9Sstevel@tonic-gate 			 */
26187c478bd9Sstevel@tonic-gate 			if ((didpp->d_attributes & DOOR_DESCRIPTOR) &&
26197c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) != NULL) {
26207c478bd9Sstevel@tonic-gate 				didpp->d_data.d_handle = FTODH(fp);
26217c478bd9Sstevel@tonic-gate 				/* Hold the door */
26227c478bd9Sstevel@tonic-gate 				door_ki_hold(didpp->d_data.d_handle);
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 				releasef(fd);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
26277c478bd9Sstevel@tonic-gate 					/* release passed reference */
26287c478bd9Sstevel@tonic-gate 					(void) closeandsetf(fd, NULL);
26297c478bd9Sstevel@tonic-gate 				}
26307c478bd9Sstevel@tonic-gate 
2631da6c28aaSamw 				if (VOP_REALVP(fp->f_vnode, &vp, NULL))
26327c478bd9Sstevel@tonic-gate 					vp = fp->f_vnode;
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 				/* Set attributes */
26357c478bd9Sstevel@tonic-gate 				didpp->d_attributes = DOOR_HANDLE |
26367c478bd9Sstevel@tonic-gate 				    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
26377c478bd9Sstevel@tonic-gate 			} else {
26387c478bd9Sstevel@tonic-gate 				/* close translated references */
26397c478bd9Sstevel@tonic-gate 				door_fd_close(start, didpp - start);
26407c478bd9Sstevel@tonic-gate 				/* close untranslated references */
26417c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
26427c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
26437c478bd9Sstevel@tonic-gate 				return (EINVAL);
26447c478bd9Sstevel@tonic-gate 			}
26457c478bd9Sstevel@tonic-gate 			didpp++;
26467c478bd9Sstevel@tonic-gate 		}
26477c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = start;
26487c478bd9Sstevel@tonic-gate 	}
26497c478bd9Sstevel@tonic-gate 	return (0);
26507c478bd9Sstevel@tonic-gate }
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate /*
26537c478bd9Sstevel@tonic-gate  * Translate door arguments from kernel to user.  This copies the passed
26547c478bd9Sstevel@tonic-gate  * door handles.  It doesn't touch other data.  It is used by door_upcall,
26557c478bd9Sstevel@tonic-gate  * and for data returned by a door_call to a kernel server.
26567c478bd9Sstevel@tonic-gate  */
26577c478bd9Sstevel@tonic-gate static int
26587c478bd9Sstevel@tonic-gate door_translate_out(void)
26597c478bd9Sstevel@tonic-gate {
26607c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
26617c478bd9Sstevel@tonic-gate 	uint_t	ndid;
26627c478bd9Sstevel@tonic-gate 
26637c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
26647c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
26657c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc) {
26667c478bd9Sstevel@tonic-gate 		door_fd_rele(ct->d_args.desc_ptr, ndid, 1);
26677c478bd9Sstevel@tonic-gate 		return (E2BIG);
26687c478bd9Sstevel@tonic-gate 	}
26697c478bd9Sstevel@tonic-gate 	/*
26707c478bd9Sstevel@tonic-gate 	 * Translate the door args into files
26717c478bd9Sstevel@tonic-gate 	 */
26727c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
26737c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp = ct->d_args.desc_ptr;
26747c478bd9Sstevel@tonic-gate 		struct file	**fpp;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
26777c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
26787c478bd9Sstevel@tonic-gate 		while (ndid--) {
26797c478bd9Sstevel@tonic-gate 			struct file *fp = NULL;
26807c478bd9Sstevel@tonic-gate 			int fd = -1;
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 			/*
26837c478bd9Sstevel@tonic-gate 			 * We understand file descriptors and door
26847c478bd9Sstevel@tonic-gate 			 * handles as passed objs.
26857c478bd9Sstevel@tonic-gate 			 */
26867c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_DESCRIPTOR) {
26877c478bd9Sstevel@tonic-gate 				fd = didpp->d_data.d_desc.d_descriptor;
26887c478bd9Sstevel@tonic-gate 				fp = getf(fd);
26897c478bd9Sstevel@tonic-gate 			} else if (didpp->d_attributes & DOOR_HANDLE)
26907c478bd9Sstevel@tonic-gate 				fp = DHTOF(didpp->d_data.d_handle);
26917c478bd9Sstevel@tonic-gate 			if (fp != NULL) {
26927c478bd9Sstevel@tonic-gate 				/* Hold the fp */
26937c478bd9Sstevel@tonic-gate 				mutex_enter(&fp->f_tlock);
26947c478bd9Sstevel@tonic-gate 				fp->f_count++;
26957c478bd9Sstevel@tonic-gate 				mutex_exit(&fp->f_tlock);
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 				*fpp = fp;
26987c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_DESCRIPTOR)
26997c478bd9Sstevel@tonic-gate 					releasef(fd);
27007c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
27017c478bd9Sstevel@tonic-gate 					/* release passed reference */
27027c478bd9Sstevel@tonic-gate 					if (fd >= 0)
27037c478bd9Sstevel@tonic-gate 						(void) closeandsetf(fd, NULL);
27047c478bd9Sstevel@tonic-gate 					else
27057c478bd9Sstevel@tonic-gate 						(void) closef(fp);
27067c478bd9Sstevel@tonic-gate 				}
27077c478bd9Sstevel@tonic-gate 			} else {
27087c478bd9Sstevel@tonic-gate 				/* close translated references */
27097c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
27107c478bd9Sstevel@tonic-gate 				/* close untranslated references */
27117c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 1);
27127c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
27137c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
27147c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
27157c478bd9Sstevel@tonic-gate 				return (EINVAL);
27167c478bd9Sstevel@tonic-gate 			}
27177c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
27187c478bd9Sstevel@tonic-gate 		}
27197c478bd9Sstevel@tonic-gate 	}
27207c478bd9Sstevel@tonic-gate 	return (0);
27217c478bd9Sstevel@tonic-gate }
27227c478bd9Sstevel@tonic-gate 
27237c478bd9Sstevel@tonic-gate /*
27247c478bd9Sstevel@tonic-gate  * Move the results from the server to the client
27257c478bd9Sstevel@tonic-gate  */
27267c478bd9Sstevel@tonic-gate static int
27277c478bd9Sstevel@tonic-gate door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
27287c478bd9Sstevel@tonic-gate 		door_desc_t *desc_ptr, uint_t desc_num)
27297c478bd9Sstevel@tonic-gate {
27307c478bd9Sstevel@tonic-gate 	door_client_t	*ct = DOOR_CLIENT(caller->t_door);
2731323a81d9Sjwadams 	door_upcall_t	*dup = ct->d_upcall;
27327c478bd9Sstevel@tonic-gate 	size_t		dsize;
27337c478bd9Sstevel@tonic-gate 	size_t		rlen;
27347c478bd9Sstevel@tonic-gate 	size_t		result_size;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct));
27377c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
27407c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* No results expected */
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	if (desc_num > door_max_desc)
27437c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* Too many descriptors */
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
27467c478bd9Sstevel@tonic-gate 	/*
27477c478bd9Sstevel@tonic-gate 	 * Check if the results are bigger than the clients buffer
27487c478bd9Sstevel@tonic-gate 	 */
27497c478bd9Sstevel@tonic-gate 	if (dsize)
27507c478bd9Sstevel@tonic-gate 		rlen = roundup(data_size, sizeof (door_desc_t));
27517c478bd9Sstevel@tonic-gate 	else
27527c478bd9Sstevel@tonic-gate 		rlen = data_size;
27537c478bd9Sstevel@tonic-gate 	if ((result_size = rlen + dsize) == 0)
27547c478bd9Sstevel@tonic-gate 		return (0);
27557c478bd9Sstevel@tonic-gate 
2756323a81d9Sjwadams 	if (dup != NULL) {
2757323a81d9Sjwadams 		if (desc_num > dup->du_max_descs)
2758323a81d9Sjwadams 			return (EMFILE);
2759323a81d9Sjwadams 
2760323a81d9Sjwadams 		if (data_size > dup->du_max_data)
2761323a81d9Sjwadams 			return (E2BIG);
2762323a81d9Sjwadams 
27637c478bd9Sstevel@tonic-gate 		/*
27647c478bd9Sstevel@tonic-gate 		 * Handle upcalls
27657c478bd9Sstevel@tonic-gate 		 */
27667c478bd9Sstevel@tonic-gate 		if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) {
27677c478bd9Sstevel@tonic-gate 			/*
27687c478bd9Sstevel@tonic-gate 			 * If there's no return buffer or the buffer is too
27697c478bd9Sstevel@tonic-gate 			 * small, allocate a new one.  The old buffer (if it
27707c478bd9Sstevel@tonic-gate 			 * exists) will be freed by the upcall client.
27717c478bd9Sstevel@tonic-gate 			 */
27727c478bd9Sstevel@tonic-gate 			if (result_size > door_max_upcall_reply)
27737c478bd9Sstevel@tonic-gate 				return (E2BIG);
27747c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = result_size;
27757c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP);
27767c478bd9Sstevel@tonic-gate 		}
27777c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
27787c478bd9Sstevel@tonic-gate 		if (data_size != 0 &&
2779289175a0Sjwadams 		    copyin_nowatch(data_ptr, ct->d_args.data_ptr,
2780289175a0Sjwadams 		    data_size) != 0)
27817c478bd9Sstevel@tonic-gate 			return (EFAULT);
27827c478bd9Sstevel@tonic-gate 	} else if (result_size > ct->d_args.rsize) {
27837c478bd9Sstevel@tonic-gate 		return (door_overflow(caller, data_ptr, data_size,
27847c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num));
27857c478bd9Sstevel@tonic-gate 	} else if (data_size != 0) {
27867c478bd9Sstevel@tonic-gate 		if (data_size <= door_max_arg) {
27877c478bd9Sstevel@tonic-gate 			/*
27887c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
27897c478bd9Sstevel@tonic-gate 			 */
27907c478bd9Sstevel@tonic-gate 			if (ct->d_buf == NULL) {
27917c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27927c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27937c478bd9Sstevel@tonic-gate 			} else if (ct->d_bufsize < data_size) {
27947c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
27957c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27967c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27977c478bd9Sstevel@tonic-gate 			}
2798289175a0Sjwadams 			if (copyin_nowatch(data_ptr, ct->d_buf, data_size) != 0)
27997c478bd9Sstevel@tonic-gate 				return (EFAULT);
28007c478bd9Sstevel@tonic-gate 		} else {
28017c478bd9Sstevel@tonic-gate 			struct as *as = ttoproc(caller)->p_as;
28027c478bd9Sstevel@tonic-gate 			caddr_t	dest = ct->d_args.rbuf;
28037c478bd9Sstevel@tonic-gate 			caddr_t	src = data_ptr;
28047c478bd9Sstevel@tonic-gate 			size_t	len = data_size;
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 			/* Copy data directly into client */
28077c478bd9Sstevel@tonic-gate 			while (len != 0) {
28087c478bd9Sstevel@tonic-gate 				uint_t	amount;
28097c478bd9Sstevel@tonic-gate 				uint_t	max;
28107c478bd9Sstevel@tonic-gate 				uint_t	off;
28117c478bd9Sstevel@tonic-gate 				int	error;
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 				off = (uintptr_t)dest & PAGEOFFSET;
28147c478bd9Sstevel@tonic-gate 				if (off)
28157c478bd9Sstevel@tonic-gate 					max = PAGESIZE - off;
28167c478bd9Sstevel@tonic-gate 				else
28177c478bd9Sstevel@tonic-gate 					max = PAGESIZE;
28187c478bd9Sstevel@tonic-gate 				amount = len > max ? max : len;
28197c478bd9Sstevel@tonic-gate 				error = door_copy(as, src, dest, amount);
28207c478bd9Sstevel@tonic-gate 				if (error != 0)
28217c478bd9Sstevel@tonic-gate 					return (error);
28227c478bd9Sstevel@tonic-gate 				dest += amount;
28237c478bd9Sstevel@tonic-gate 				src += amount;
28247c478bd9Sstevel@tonic-gate 				len -= amount;
28257c478bd9Sstevel@tonic-gate 			}
28267c478bd9Sstevel@tonic-gate 		}
28277c478bd9Sstevel@tonic-gate 	}
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	/*
28307c478bd9Sstevel@tonic-gate 	 * Copyin the returned door ids and translate them into door_node_t
28317c478bd9Sstevel@tonic-gate 	 */
28327c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
28337c478bd9Sstevel@tonic-gate 		door_desc_t *start;
28347c478bd9Sstevel@tonic-gate 		door_desc_t *didpp;
28357c478bd9Sstevel@tonic-gate 		struct file **fpp;
28367c478bd9Sstevel@tonic-gate 		size_t	fpp_size;
28377c478bd9Sstevel@tonic-gate 		uint_t	i;
28387c478bd9Sstevel@tonic-gate 
28397c478bd9Sstevel@tonic-gate 		/* First, check if we would overflow client */
28407c478bd9Sstevel@tonic-gate 		if (!ufcanalloc(ttoproc(caller), desc_num))
28417c478bd9Sstevel@tonic-gate 			return (EMFILE);
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
2844289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp, dsize)) {
28457c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
28467c478bd9Sstevel@tonic-gate 			return (EFAULT);
28477c478bd9Sstevel@tonic-gate 		}
28487c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
28497c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
28507c478bd9Sstevel@tonic-gate 			/* make more space */
28517c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
28527c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
28537c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
28547c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP);
28557c478bd9Sstevel@tonic-gate 		}
28567c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
28597c478bd9Sstevel@tonic-gate 			struct file *fp;
28607c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate 			/* Only understand file descriptor results */
28637c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
28647c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
28657c478bd9Sstevel@tonic-gate 				/* close translated references */
28667c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
28677c478bd9Sstevel@tonic-gate 				/* close untranslated references */
28687c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
28697c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
28707c478bd9Sstevel@tonic-gate 				return (EINVAL);
28717c478bd9Sstevel@tonic-gate 			}
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
28747c478bd9Sstevel@tonic-gate 			fp->f_count++;
28757c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 			*fpp = fp;
28787c478bd9Sstevel@tonic-gate 			releasef(fd);
28797c478bd9Sstevel@tonic-gate 
28807c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
28817c478bd9Sstevel@tonic-gate 				/* release passed reference */
28827c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
28837c478bd9Sstevel@tonic-gate 			}
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
28867c478bd9Sstevel@tonic-gate 		}
28877c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
28887c478bd9Sstevel@tonic-gate 	}
28897c478bd9Sstevel@tonic-gate 	return (0);
28907c478bd9Sstevel@tonic-gate }
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate /*
28937c478bd9Sstevel@tonic-gate  * Close all the descriptors.
28947c478bd9Sstevel@tonic-gate  */
28957c478bd9Sstevel@tonic-gate static void
28967c478bd9Sstevel@tonic-gate door_fd_close(door_desc_t *d, uint_t n)
28977c478bd9Sstevel@tonic-gate {
28987c478bd9Sstevel@tonic-gate 	uint_t	i;
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29017c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
29027c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_DESCRIPTOR) {
29037c478bd9Sstevel@tonic-gate 			(void) closeandsetf(
29047c478bd9Sstevel@tonic-gate 			    d->d_data.d_desc.d_descriptor, NULL);
29057c478bd9Sstevel@tonic-gate 		} else if (d->d_attributes & DOOR_HANDLE) {
29067c478bd9Sstevel@tonic-gate 			door_ki_rele(d->d_data.d_handle);
29077c478bd9Sstevel@tonic-gate 		}
29087c478bd9Sstevel@tonic-gate 		d++;
29097c478bd9Sstevel@tonic-gate 	}
29107c478bd9Sstevel@tonic-gate }
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate /*
29137c478bd9Sstevel@tonic-gate  * Close descriptors that have the DOOR_RELEASE attribute set.
29147c478bd9Sstevel@tonic-gate  */
29157c478bd9Sstevel@tonic-gate void
29167c478bd9Sstevel@tonic-gate door_fd_rele(door_desc_t *d, uint_t n, int from_kernel)
29177c478bd9Sstevel@tonic-gate {
29187c478bd9Sstevel@tonic-gate 	uint_t	i;
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29217c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
29227c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_RELEASE) {
29237c478bd9Sstevel@tonic-gate 			if (d->d_attributes & DOOR_DESCRIPTOR) {
29247c478bd9Sstevel@tonic-gate 				(void) closeandsetf(
29257c478bd9Sstevel@tonic-gate 				    d->d_data.d_desc.d_descriptor, NULL);
29267c478bd9Sstevel@tonic-gate 			} else if (from_kernel &&
29277c478bd9Sstevel@tonic-gate 			    (d->d_attributes & DOOR_HANDLE)) {
29287c478bd9Sstevel@tonic-gate 				door_ki_rele(d->d_data.d_handle);
29297c478bd9Sstevel@tonic-gate 			}
29307c478bd9Sstevel@tonic-gate 		}
29317c478bd9Sstevel@tonic-gate 		d++;
29327c478bd9Sstevel@tonic-gate 	}
29337c478bd9Sstevel@tonic-gate }
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate /*
29367c478bd9Sstevel@tonic-gate  * Copy descriptors into the kernel so we can release any marked
29377c478bd9Sstevel@tonic-gate  * DOOR_RELEASE.
29387c478bd9Sstevel@tonic-gate  */
29397c478bd9Sstevel@tonic-gate int
29407c478bd9Sstevel@tonic-gate door_release_fds(door_desc_t *desc_ptr, uint_t ndesc)
29417c478bd9Sstevel@tonic-gate {
29427c478bd9Sstevel@tonic-gate 	size_t dsize;
29437c478bd9Sstevel@tonic-gate 	door_desc_t *didpp;
29447c478bd9Sstevel@tonic-gate 	uint_t desc_num;
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29477c478bd9Sstevel@tonic-gate 	ASSERT(ndesc != 0);
29487c478bd9Sstevel@tonic-gate 
29497c478bd9Sstevel@tonic-gate 	desc_num = MIN(ndesc, door_max_desc);
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
29527c478bd9Sstevel@tonic-gate 	didpp = kmem_alloc(dsize, KM_SLEEP);
29537c478bd9Sstevel@tonic-gate 
29547c478bd9Sstevel@tonic-gate 	while (ndesc > 0) {
29557c478bd9Sstevel@tonic-gate 		uint_t count = MIN(ndesc, desc_num);
29567c478bd9Sstevel@tonic-gate 
2957289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp,
2958289175a0Sjwadams 		    count * sizeof (door_desc_t))) {
29597c478bd9Sstevel@tonic-gate 			kmem_free(didpp, dsize);
29607c478bd9Sstevel@tonic-gate 			return (EFAULT);
29617c478bd9Sstevel@tonic-gate 		}
29627c478bd9Sstevel@tonic-gate 		door_fd_rele(didpp, count, 0);
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 		ndesc -= count;
29657c478bd9Sstevel@tonic-gate 		desc_ptr += count;
29667c478bd9Sstevel@tonic-gate 	}
29677c478bd9Sstevel@tonic-gate 	kmem_free(didpp, dsize);
29687c478bd9Sstevel@tonic-gate 	return (0);
29697c478bd9Sstevel@tonic-gate }
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate /*
29727c478bd9Sstevel@tonic-gate  * Decrement ref count on all the files passed
29737c478bd9Sstevel@tonic-gate  */
29747c478bd9Sstevel@tonic-gate static void
29757c478bd9Sstevel@tonic-gate door_fp_close(struct file **fp, uint_t n)
29767c478bd9Sstevel@tonic-gate {
29777c478bd9Sstevel@tonic-gate 	uint_t	i;
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++)
29827c478bd9Sstevel@tonic-gate 		(void) closef(fp[i]);
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate /*
29867c478bd9Sstevel@tonic-gate  * Copy data from 'src' in current address space to 'dest' in 'as' for 'len'
29877c478bd9Sstevel@tonic-gate  * bytes.
29887c478bd9Sstevel@tonic-gate  *
29897c478bd9Sstevel@tonic-gate  * Performs this using 1 mapin and 1 copy operation.
29907c478bd9Sstevel@tonic-gate  *
29917c478bd9Sstevel@tonic-gate  * We really should do more than 1 page at a time to improve
29927c478bd9Sstevel@tonic-gate  * performance, but for now this is treated as an anomalous condition.
29937c478bd9Sstevel@tonic-gate  */
29947c478bd9Sstevel@tonic-gate static int
29957c478bd9Sstevel@tonic-gate door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate 	caddr_t	kaddr;
29987c478bd9Sstevel@tonic-gate 	caddr_t	rdest;
29997c478bd9Sstevel@tonic-gate 	uint_t	off;
30007c478bd9Sstevel@tonic-gate 	page_t	**pplist;
30017c478bd9Sstevel@tonic-gate 	page_t	*pp = NULL;
30027c478bd9Sstevel@tonic-gate 	int	error = 0;
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate 	ASSERT(len <= PAGESIZE);
30057c478bd9Sstevel@tonic-gate 	off = (uintptr_t)dest & PAGEOFFSET;	/* offset within the page */
30067c478bd9Sstevel@tonic-gate 	rdest = (caddr_t)((uintptr_t)dest &
30077c478bd9Sstevel@tonic-gate 	    (uintptr_t)PAGEMASK);	/* Page boundary */
30087c478bd9Sstevel@tonic-gate 	ASSERT(off + len <= PAGESIZE);
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	/*
30117c478bd9Sstevel@tonic-gate 	 * Lock down destination page.
30127c478bd9Sstevel@tonic-gate 	 */
30137c478bd9Sstevel@tonic-gate 	if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE))
30147c478bd9Sstevel@tonic-gate 		return (E2BIG);
30157c478bd9Sstevel@tonic-gate 	/*
30167c478bd9Sstevel@tonic-gate 	 * Check if we have a shadow page list from as_pagelock. If not,
30177c478bd9Sstevel@tonic-gate 	 * we took the slow path and have to find our page struct the hard
30187c478bd9Sstevel@tonic-gate 	 * way.
30197c478bd9Sstevel@tonic-gate 	 */
30207c478bd9Sstevel@tonic-gate 	if (pplist == NULL) {
30217c478bd9Sstevel@tonic-gate 		pfn_t	pfnum;
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 		/* MMU mapping is already locked down */
3024dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_READER);
30257c478bd9Sstevel@tonic-gate 		pfnum = hat_getpfnum(as->a_hat, rdest);
3026dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 		/*
30297c478bd9Sstevel@tonic-gate 		 * TODO: The pfn step should not be necessary - need
30307c478bd9Sstevel@tonic-gate 		 * a hat_getpp() function.
30317c478bd9Sstevel@tonic-gate 		 */
30327c478bd9Sstevel@tonic-gate 		if (pf_is_memory(pfnum)) {
30337c478bd9Sstevel@tonic-gate 			pp = page_numtopp_nolock(pfnum);
30347c478bd9Sstevel@tonic-gate 			ASSERT(pp == NULL || PAGE_LOCKED(pp));
30357c478bd9Sstevel@tonic-gate 		} else
30367c478bd9Sstevel@tonic-gate 			pp = NULL;
30377c478bd9Sstevel@tonic-gate 		if (pp == NULL) {
30387c478bd9Sstevel@tonic-gate 			as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
30397c478bd9Sstevel@tonic-gate 			return (E2BIG);
30407c478bd9Sstevel@tonic-gate 		}
30417c478bd9Sstevel@tonic-gate 	} else {
30427c478bd9Sstevel@tonic-gate 		pp = *pplist;
30437c478bd9Sstevel@tonic-gate 	}
30447c478bd9Sstevel@tonic-gate 	/*
30457c478bd9Sstevel@tonic-gate 	 * Map destination page into kernel address
30467c478bd9Sstevel@tonic-gate 	 */
30475ab67823SVivek Gavaskar 	if (kpm_enable)
30485ab67823SVivek Gavaskar 		kaddr = (caddr_t)hat_kpm_mapin(pp, (struct kpme *)NULL);
30495ab67823SVivek Gavaskar 	else
30505ab67823SVivek Gavaskar 		kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE,
30515ab67823SVivek Gavaskar 		    (caddr_t)-1);
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	/*
30547c478bd9Sstevel@tonic-gate 	 * Copy from src to dest
30557c478bd9Sstevel@tonic-gate 	 */
3056289175a0Sjwadams 	if (copyin_nowatch(src, kaddr + off, len) != 0)
30577c478bd9Sstevel@tonic-gate 		error = EFAULT;
30587c478bd9Sstevel@tonic-gate 	/*
30597c478bd9Sstevel@tonic-gate 	 * Unmap destination page from kernel
30607c478bd9Sstevel@tonic-gate 	 */
30615ab67823SVivek Gavaskar 	if (kpm_enable)
30625ab67823SVivek Gavaskar 		hat_kpm_mapout(pp, (struct kpme *)NULL, kaddr);
30635ab67823SVivek Gavaskar 	else
30645ab67823SVivek Gavaskar 		ppmapout(kaddr);
30657c478bd9Sstevel@tonic-gate 	/*
30667c478bd9Sstevel@tonic-gate 	 * Unlock destination page
30677c478bd9Sstevel@tonic-gate 	 */
30687c478bd9Sstevel@tonic-gate 	as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
30697c478bd9Sstevel@tonic-gate 	return (error);
30707c478bd9Sstevel@tonic-gate }
30717c478bd9Sstevel@tonic-gate 
30727c478bd9Sstevel@tonic-gate /*
30737c478bd9Sstevel@tonic-gate  * General kernel upcall using doors
30747c478bd9Sstevel@tonic-gate  *	Returns 0 on success, errno for failures.
30757c478bd9Sstevel@tonic-gate  *	Caller must have a hold on the door based vnode, and on any
30767c478bd9Sstevel@tonic-gate  *	references passed in desc_ptr.  The references are released
30777c478bd9Sstevel@tonic-gate  *	in the event of an error, and passed without duplication
30787c478bd9Sstevel@tonic-gate  *	otherwise.  Note that param->rbuf must be 64-bit aligned in
30797c478bd9Sstevel@tonic-gate  *	a 64-bit kernel, since it may be used to store door descriptors
3080024b0a25Sseb  *	if they are returned by the server.  The caller is responsible
3081024b0a25Sseb  *	for holding a reference to the cred passed in.
30827c478bd9Sstevel@tonic-gate  */
30837c478bd9Sstevel@tonic-gate int
3084323a81d9Sjwadams door_upcall(vnode_t *vp, door_arg_t *param, struct cred *cred,
3085323a81d9Sjwadams     size_t max_data, uint_t max_descs)
30867c478bd9Sstevel@tonic-gate {
30877c478bd9Sstevel@tonic-gate 	/* Locals */
3088323a81d9Sjwadams 	door_upcall_t	*dup;
30897c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
30907c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
30917c478bd9Sstevel@tonic-gate 	int		error = 0;
30927c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
30937c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
30947c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
30957c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
3096a574db85Sraf 	int		cancel_pending;
30977c478bd9Sstevel@tonic-gate 
30987c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
30997c478bd9Sstevel@tonic-gate 		if (param->desc_num)
31007c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
31017c478bd9Sstevel@tonic-gate 		return (EINVAL);
31027c478bd9Sstevel@tonic-gate 	}
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
31057c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
31067c478bd9Sstevel@tonic-gate 	dp = VTOD(vp);	/* Convert to a door_node_t */
31077c478bd9Sstevel@tonic-gate 
3108323a81d9Sjwadams 	dup = kmem_zalloc(sizeof (*dup), KM_SLEEP);
3109323a81d9Sjwadams 	dup->du_cred = (cred != NULL) ? cred : curthread->t_cred;
3110323a81d9Sjwadams 	dup->du_max_data = max_data;
3111323a81d9Sjwadams 	dup->du_max_descs = max_descs;
3112323a81d9Sjwadams 
3113c12957e9Sraf 	/*
3114c12957e9Sraf 	 * This should be done in shuttle_resume(), just before going to
3115c12957e9Sraf 	 * sleep, but we want to avoid overhead while holding door_knob.
3116c12957e9Sraf 	 * prstop() is just a no-op if we don't really go to sleep.
3117e28ad609SRoger A. Faulkner 	 * We test not-kernel-address-space for the sake of clustering code.
3118c12957e9Sraf 	 */
3119e28ad609SRoger A. Faulkner 	if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
3120c12957e9Sraf 		prstop(PR_REQUESTED, 0);
3121c12957e9Sraf 
31227c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
31237c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
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 = EBADF;
31287c478bd9Sstevel@tonic-gate 		goto out;
31297c478bd9Sstevel@tonic-gate 	}
31307c478bd9Sstevel@tonic-gate 
31317c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
31327c478bd9Sstevel@tonic-gate 		/* Can't do an upcall to a kernel server */
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 		error = EINVAL;
31377c478bd9Sstevel@tonic-gate 		goto out;
31387c478bd9Sstevel@tonic-gate 	}
31397c478bd9Sstevel@tonic-gate 
31407c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, param, 1);
31417c478bd9Sstevel@tonic-gate 	if (error != 0) {
31427c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
31437c478bd9Sstevel@tonic-gate 		if (param->desc_num)
31447c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
31457c478bd9Sstevel@tonic-gate 		goto out;
31467c478bd9Sstevel@tonic-gate 	}
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 	/*
31497c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
31507c478bd9Sstevel@tonic-gate 	 */
31517c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
31527c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
31537c478bd9Sstevel@tonic-gate 			error = EBADF;
31547c478bd9Sstevel@tonic-gate 		else
31557c478bd9Sstevel@tonic-gate 			error = EAGAIN;
31567c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
31577c478bd9Sstevel@tonic-gate 		if (param->desc_num)
31587c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
31597c478bd9Sstevel@tonic-gate 		goto out;
31607c478bd9Sstevel@tonic-gate 	}
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
31637c478bd9Sstevel@tonic-gate 	ct->d_buf = param->data_ptr;
31647c478bd9Sstevel@tonic-gate 	ct->d_bufsize = param->data_size;
31657c478bd9Sstevel@tonic-gate 	ct->d_args = *param;	/* structure assignment */
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
31687c478bd9Sstevel@tonic-gate 		/*
31697c478bd9Sstevel@tonic-gate 		 * Move data from client to server
31707c478bd9Sstevel@tonic-gate 		 */
31717c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
31727c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
31737c478bd9Sstevel@tonic-gate 		error = door_translate_out();
31747c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
31757c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
31767c478bd9Sstevel@tonic-gate 		if (error) {
31777c478bd9Sstevel@tonic-gate 			/*
31787c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
31797c478bd9Sstevel@tonic-gate 			 */
31807c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
31817c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
31827c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
31837c478bd9Sstevel@tonic-gate 			goto out;
31847c478bd9Sstevel@tonic-gate 		}
31857c478bd9Sstevel@tonic-gate 	}
31867c478bd9Sstevel@tonic-gate 
3187323a81d9Sjwadams 	ct->d_upcall = dup;
31887c478bd9Sstevel@tonic-gate 	if (param->rsize == 0)
31897c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
31907c478bd9Sstevel@tonic-gate 	else
31917c478bd9Sstevel@tonic-gate 		ct->d_noresults = 0;
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 	dp->door_active++;
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
31967c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
31977c478bd9Sstevel@tonic-gate 	st->d_active = dp;
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
32007c478bd9Sstevel@tonic-gate 
32017c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
32027c478bd9Sstevel@tonic-gate shuttle_return:
32037c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
32047c478bd9Sstevel@tonic-gate 		/*
32057c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
32067c478bd9Sstevel@tonic-gate 		 */
32077c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
3208a574db85Sraf 		cancel_pending = 0;
3209a574db85Sraf 		if (lwp && (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
3210a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
3211a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0)) {
32127c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
3213a574db85Sraf 			if (cancel_pending)
3214a574db85Sraf 				schedctl_cancel_eintr();
32157c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
32167c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
32177c478bd9Sstevel@tonic-gate 			error = EINTR;
32187c478bd9Sstevel@tonic-gate 			/*
32197c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
32207c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
32217c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
32227c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
32237c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
32247c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
32257c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
32267c478bd9Sstevel@tonic-gate 			 */
32277c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
32287c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
32297c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
32327c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
32337c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
32347c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
32357c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
32387c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
32397c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
32427c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
32437c478bd9Sstevel@tonic-gate 				}
32447c478bd9Sstevel@tonic-gate 			}
32457c478bd9Sstevel@tonic-gate 		} else {
32467c478bd9Sstevel@tonic-gate 			/*
32477c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
32487c478bd9Sstevel@tonic-gate 			 *
32497c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
32507c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
32517c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
32527c478bd9Sstevel@tonic-gate 			 * is updated by the server.
32537c478bd9Sstevel@tonic-gate 			 */
32547c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
32557c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
32567c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
32577c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
32587c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
32597c478bd9Sstevel@tonic-gate 				if (lwp)
32607c478bd9Sstevel@tonic-gate 					lwp->lwp_asleep = 0;
32617c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
32627c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
32637c478bd9Sstevel@tonic-gate 				/* Server exit */
32647c478bd9Sstevel@tonic-gate 				error = EINTR;
32657c478bd9Sstevel@tonic-gate 			} else {
32667c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
32677c478bd9Sstevel@tonic-gate 				error = ct->d_error;
32687c478bd9Sstevel@tonic-gate 			}
32697c478bd9Sstevel@tonic-gate 		}
32707c478bd9Sstevel@tonic-gate 		/*
32717c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
32727c478bd9Sstevel@tonic-gate 		 * results for me
32737c478bd9Sstevel@tonic-gate 		 */
32747c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
32757c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
32767c478bd9Sstevel@tonic-gate 
32777c478bd9Sstevel@tonic-gate 		/*
32787c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
32797c478bd9Sstevel@tonic-gate 		 */
32807c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
32817c478bd9Sstevel@tonic-gate 			gotresults = 1;
32827c478bd9Sstevel@tonic-gate 	}
32837c478bd9Sstevel@tonic-gate 	if (lwp) {
32847c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;		/* /proc */
32857c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 0;		/* /proc */
32867c478bd9Sstevel@tonic-gate 	}
32877c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
32887c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
32897c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate 	/*
32927c478bd9Sstevel@tonic-gate 	 * Translate returned doors (if any)
32937c478bd9Sstevel@tonic-gate 	 */
32947c478bd9Sstevel@tonic-gate 
32957c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
32967c478bd9Sstevel@tonic-gate 		goto out;
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate 	if (error) {
32997c478bd9Sstevel@tonic-gate 		/*
33007c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
33017c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
33027c478bd9Sstevel@tonic-gate 		 */
33037c478bd9Sstevel@tonic-gate 		if (gotresults) {
33047c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
33057c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
33067c478bd9Sstevel@tonic-gate 		}
33077c478bd9Sstevel@tonic-gate 		goto out;
33087c478bd9Sstevel@tonic-gate 	}
33097c478bd9Sstevel@tonic-gate 
33107c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
33117c478bd9Sstevel@tonic-gate 		struct file	**fpp;
33127c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
33137c478bd9Sstevel@tonic-gate 		vnode_t		*vp;
33147c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
33157c478bd9Sstevel@tonic-gate 
33167c478bd9Sstevel@tonic-gate 		didpp = ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
33177c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
33187c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 		while (n--) {
33217c478bd9Sstevel@tonic-gate 			struct file *fp;
33227c478bd9Sstevel@tonic-gate 
33237c478bd9Sstevel@tonic-gate 			fp = *fpp;
3324da6c28aaSamw 			if (VOP_REALVP(fp->f_vnode, &vp, NULL))
33257c478bd9Sstevel@tonic-gate 				vp = fp->f_vnode;
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 			didpp->d_attributes = DOOR_HANDLE |
33287c478bd9Sstevel@tonic-gate 			    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
33297c478bd9Sstevel@tonic-gate 			didpp->d_data.d_handle = FTODH(fp);
33307c478bd9Sstevel@tonic-gate 
33317c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
33327c478bd9Sstevel@tonic-gate 		}
33337c478bd9Sstevel@tonic-gate 	}
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 	/* on return data is in rbuf */
33367c478bd9Sstevel@tonic-gate 	*param = ct->d_args;		/* structure assignment */
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate out:
3339323a81d9Sjwadams 	kmem_free(dup, sizeof (*dup));
3340323a81d9Sjwadams 
33417c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
33427c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
33437c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
33447c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
33457c478bd9Sstevel@tonic-gate 	}
33467c478bd9Sstevel@tonic-gate 
3347323a81d9Sjwadams 	ct->d_upcall = NULL;
33487c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
33497c478bd9Sstevel@tonic-gate 	ct->d_buf = NULL;
33507c478bd9Sstevel@tonic-gate 	ct->d_bufsize = 0;
33517c478bd9Sstevel@tonic-gate 	return (error);
33527c478bd9Sstevel@tonic-gate }
33537c478bd9Sstevel@tonic-gate 
33547c478bd9Sstevel@tonic-gate /*
33557c478bd9Sstevel@tonic-gate  * Add a door to the per-process list of active doors for which the
33567c478bd9Sstevel@tonic-gate  * process is a server.
33577c478bd9Sstevel@tonic-gate  */
33587c478bd9Sstevel@tonic-gate static void
33597c478bd9Sstevel@tonic-gate door_list_insert(door_node_t *dp)
33607c478bd9Sstevel@tonic-gate {
33617c478bd9Sstevel@tonic-gate 	proc_t *p = dp->door_target;
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
33647c478bd9Sstevel@tonic-gate 	dp->door_list = p->p_door_list;
33657c478bd9Sstevel@tonic-gate 	p->p_door_list = dp;
33667c478bd9Sstevel@tonic-gate }
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate /*
33697c478bd9Sstevel@tonic-gate  * Remove a door from the per-process list of active doors.
33707c478bd9Sstevel@tonic-gate  */
33717c478bd9Sstevel@tonic-gate void
33727c478bd9Sstevel@tonic-gate door_list_delete(door_node_t *dp)
33737c478bd9Sstevel@tonic-gate {
33747c478bd9Sstevel@tonic-gate 	door_node_t **pp;
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
33777c478bd9Sstevel@tonic-gate 	/*
33787c478bd9Sstevel@tonic-gate 	 * Find the door in the list.  If the door belongs to another process,
33797c478bd9Sstevel@tonic-gate 	 * it's OK to use p_door_list since that process can't exit until all
33807c478bd9Sstevel@tonic-gate 	 * doors have been taken off the list (see door_exit).
33817c478bd9Sstevel@tonic-gate 	 */
33827c478bd9Sstevel@tonic-gate 	pp = &(dp->door_target->p_door_list);
33837c478bd9Sstevel@tonic-gate 	while (*pp != dp)
33847c478bd9Sstevel@tonic-gate 		pp = &((*pp)->door_list);
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 	/* found it, take it off the list */
33877c478bd9Sstevel@tonic-gate 	*pp = dp->door_list;
33887c478bd9Sstevel@tonic-gate }
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate /*
33927c478bd9Sstevel@tonic-gate  * External kernel interfaces for doors.  These functions are available
33937c478bd9Sstevel@tonic-gate  * outside the doorfs module for use in creating and using doors from
33947c478bd9Sstevel@tonic-gate  * within the kernel.
33957c478bd9Sstevel@tonic-gate  */
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate /*
3398024b0a25Sseb  * door_ki_upcall invokes a user-level door server from the kernel, with
3399024b0a25Sseb  * the credentials associated with curthread.
34007c478bd9Sstevel@tonic-gate  */
34017c478bd9Sstevel@tonic-gate int
34027c478bd9Sstevel@tonic-gate door_ki_upcall(door_handle_t dh, door_arg_t *param)
3403024b0a25Sseb {
3404323a81d9Sjwadams 	return (door_ki_upcall_limited(dh, param, NULL, SIZE_MAX, UINT_MAX));
3405024b0a25Sseb }
3406024b0a25Sseb 
3407024b0a25Sseb /*
3408323a81d9Sjwadams  * door_ki_upcall_limited invokes a user-level door server from the
3409323a81d9Sjwadams  * kernel with the given credentials and reply limits.  If the "cred"
3410323a81d9Sjwadams  * argument is NULL, uses the credentials associated with current
3411323a81d9Sjwadams  * thread.  max_data limits the maximum length of the returned data (the
3412323a81d9Sjwadams  * client will get E2BIG if they go over), and max_desc limits the
3413323a81d9Sjwadams  * number of returned descriptors (the client will get EMFILE if they
3414323a81d9Sjwadams  * go over).
3415024b0a25Sseb  */
3416024b0a25Sseb int
3417323a81d9Sjwadams door_ki_upcall_limited(door_handle_t dh, door_arg_t *param, struct cred *cred,
3418323a81d9Sjwadams     size_t max_data, uint_t max_desc)
34197c478bd9Sstevel@tonic-gate {
34207c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34217c478bd9Sstevel@tonic-gate 	vnode_t *realvp;
34227c478bd9Sstevel@tonic-gate 
3423da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
34247c478bd9Sstevel@tonic-gate 		realvp = fp->f_vnode;
3425323a81d9Sjwadams 	return (door_upcall(realvp, param, cred, max_data, max_desc));
34267c478bd9Sstevel@tonic-gate }
34277c478bd9Sstevel@tonic-gate 
34287c478bd9Sstevel@tonic-gate /*
34297c478bd9Sstevel@tonic-gate  * Function call to create a "kernel" door server.  A kernel door
34307c478bd9Sstevel@tonic-gate  * server provides a way for a user-level process to invoke a function
34317c478bd9Sstevel@tonic-gate  * in the kernel through a door_call.  From the caller's point of
34327c478bd9Sstevel@tonic-gate  * view, a kernel door server looks the same as a user-level one
34337c478bd9Sstevel@tonic-gate  * (except the server pid is 0).  Unlike normal door calls, the
34347c478bd9Sstevel@tonic-gate  * kernel door function is invoked via a normal function call in the
34357c478bd9Sstevel@tonic-gate  * same thread and context as the caller.
34367c478bd9Sstevel@tonic-gate  */
34377c478bd9Sstevel@tonic-gate int
34387c478bd9Sstevel@tonic-gate door_ki_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
34397c478bd9Sstevel@tonic-gate     door_handle_t *dhp)
34407c478bd9Sstevel@tonic-gate {
34417c478bd9Sstevel@tonic-gate 	int err;
34427c478bd9Sstevel@tonic-gate 	file_t *fp;
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate 	/* no DOOR_PRIVATE */
34457c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_KI_CREATE_MASK) ||
34467c478bd9Sstevel@tonic-gate 	    (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
34477c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI))
34487c478bd9Sstevel@tonic-gate 		return (EINVAL);
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 	err = door_create_common(pc_cookie, data_cookie, attributes,
34517c478bd9Sstevel@tonic-gate 	    1, NULL, &fp);
34527c478bd9Sstevel@tonic-gate 	if (err == 0 && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) &&
34537c478bd9Sstevel@tonic-gate 	    p0.p_unref_thread == 0) {
34547c478bd9Sstevel@tonic-gate 		/* need to create unref thread for process 0 */
34557c478bd9Sstevel@tonic-gate 		(void) thread_create(NULL, 0, door_unref_kernel, NULL, 0, &p0,
34567c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
34577c478bd9Sstevel@tonic-gate 	}
34587c478bd9Sstevel@tonic-gate 	if (err == 0) {
34597c478bd9Sstevel@tonic-gate 		*dhp = FTODH(fp);
34607c478bd9Sstevel@tonic-gate 	}
34617c478bd9Sstevel@tonic-gate 	return (err);
34627c478bd9Sstevel@tonic-gate }
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate void
34657c478bd9Sstevel@tonic-gate door_ki_hold(door_handle_t dh)
34667c478bd9Sstevel@tonic-gate {
34677c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34687c478bd9Sstevel@tonic-gate 
34697c478bd9Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
34707c478bd9Sstevel@tonic-gate 	fp->f_count++;
34717c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
34727c478bd9Sstevel@tonic-gate }
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate void
34757c478bd9Sstevel@tonic-gate door_ki_rele(door_handle_t dh)
34767c478bd9Sstevel@tonic-gate {
34777c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34787c478bd9Sstevel@tonic-gate 
34797c478bd9Sstevel@tonic-gate 	(void) closef(fp);
34807c478bd9Sstevel@tonic-gate }
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate int
34837c478bd9Sstevel@tonic-gate door_ki_open(char *pathname, door_handle_t *dhp)
34847c478bd9Sstevel@tonic-gate {
34857c478bd9Sstevel@tonic-gate 	file_t *fp;
34867c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34877c478bd9Sstevel@tonic-gate 	int err;
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 	if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
34907c478bd9Sstevel@tonic-gate 		return (err);
3491da6c28aaSamw 	if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
34927c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
34937c478bd9Sstevel@tonic-gate 		return (err);
34947c478bd9Sstevel@tonic-gate 	}
34957c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
34967c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
34977c478bd9Sstevel@tonic-gate 		return (EINVAL);
34987c478bd9Sstevel@tonic-gate 	}
34997c478bd9Sstevel@tonic-gate 	if ((err = falloc(vp, FREAD | FWRITE, &fp, NULL)) != 0) {
35007c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
35017c478bd9Sstevel@tonic-gate 		return (err);
35027c478bd9Sstevel@tonic-gate 	}
35037c478bd9Sstevel@tonic-gate 	/* falloc returns with f_tlock held on success */
35047c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
35057c478bd9Sstevel@tonic-gate 	*dhp = FTODH(fp);
35067c478bd9Sstevel@tonic-gate 	return (0);
35077c478bd9Sstevel@tonic-gate }
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate int
35107c478bd9Sstevel@tonic-gate door_ki_info(door_handle_t dh, struct door_info *dip)
35117c478bd9Sstevel@tonic-gate {
35127c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
35137c478bd9Sstevel@tonic-gate 	vnode_t *vp;
35147c478bd9Sstevel@tonic-gate 
3515da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
35167c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
35177c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
35187c478bd9Sstevel@tonic-gate 		return (EINVAL);
35197c478bd9Sstevel@tonic-gate 	door_info_common(VTOD(vp), dip, fp);
35207c478bd9Sstevel@tonic-gate 	return (0);
35217c478bd9Sstevel@tonic-gate }
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate door_handle_t
35247c478bd9Sstevel@tonic-gate door_ki_lookup(int did)
35257c478bd9Sstevel@tonic-gate {
35267c478bd9Sstevel@tonic-gate 	file_t *fp;
35277c478bd9Sstevel@tonic-gate 	door_handle_t dh;
35287c478bd9Sstevel@tonic-gate 
35297c478bd9Sstevel@tonic-gate 	/* is the descriptor really a door? */
35307c478bd9Sstevel@tonic-gate 	if (door_lookup(did, &fp) == NULL)
35317c478bd9Sstevel@tonic-gate 		return (NULL);
35327c478bd9Sstevel@tonic-gate 	/* got the door, put a hold on it and release the fd */
35337c478bd9Sstevel@tonic-gate 	dh = FTODH(fp);
35347c478bd9Sstevel@tonic-gate 	door_ki_hold(dh);
35357c478bd9Sstevel@tonic-gate 	releasef(did);
35367c478bd9Sstevel@tonic-gate 	return (dh);
35377c478bd9Sstevel@tonic-gate }
35387c478bd9Sstevel@tonic-gate 
35397c478bd9Sstevel@tonic-gate int
35407c478bd9Sstevel@tonic-gate door_ki_setparam(door_handle_t dh, int type, size_t val)
35417c478bd9Sstevel@tonic-gate {
35427c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
35437c478bd9Sstevel@tonic-gate 	vnode_t *vp;
35447c478bd9Sstevel@tonic-gate 
3545da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
35467c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
35477c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
35487c478bd9Sstevel@tonic-gate 		return (EINVAL);
35497c478bd9Sstevel@tonic-gate 	return (door_setparam_common(VTOD(vp), 1, type, val));
35507c478bd9Sstevel@tonic-gate }
35517c478bd9Sstevel@tonic-gate 
35527c478bd9Sstevel@tonic-gate int
35537c478bd9Sstevel@tonic-gate door_ki_getparam(door_handle_t dh, int type, size_t *out)
35547c478bd9Sstevel@tonic-gate {
35557c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
35567c478bd9Sstevel@tonic-gate 	vnode_t *vp;
35577c478bd9Sstevel@tonic-gate 
3558da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
35597c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
35607c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
35617c478bd9Sstevel@tonic-gate 		return (EINVAL);
35627c478bd9Sstevel@tonic-gate 	return (door_getparam_common(VTOD(vp), type, out));
35637c478bd9Sstevel@tonic-gate }
3564