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.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25*915894efSMatt Barden  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * System call I/F to doors (outside of vnodes I/F) and misc support
307c478bd9Sstevel@tonic-gate  * routines
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/door.h>
357c478bd9Sstevel@tonic-gate #include <sys/door_data.h>
367c478bd9Sstevel@tonic-gate #include <sys/proc.h>
377c478bd9Sstevel@tonic-gate #include <sys/thread.h>
38c12957e9Sraf #include <sys/prsystm.h>
39c12957e9Sraf #include <sys/procfs.h>
407c478bd9Sstevel@tonic-gate #include <sys/class.h>
417c478bd9Sstevel@tonic-gate #include <sys/cred.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
447c478bd9Sstevel@tonic-gate #include <sys/stack.h>
457c478bd9Sstevel@tonic-gate #include <sys/debug.h>
467c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
477c478bd9Sstevel@tonic-gate #include <sys/file.h>
487c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
497c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
507c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
51aa59c4cbSrsb #include <sys/vfs_opreg.h>
527c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
537c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
547c478bd9Sstevel@tonic-gate #include <sys/callb.h>
557c478bd9Sstevel@tonic-gate #include <sys/ucred.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include <sys/mman.h>
587c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
597c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
607c478bd9Sstevel@tonic-gate #include <vm/as.h>
617c478bd9Sstevel@tonic-gate #include <vm/hat.h>
627c478bd9Sstevel@tonic-gate #include <vm/page.h>
637c478bd9Sstevel@tonic-gate #include <vm/seg.h>
647c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
657c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
665ab67823SVivek Gavaskar #include <vm/seg_kpm.h>
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
697c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
707c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
717c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
74da6c28aaSamw  * The maximum amount of data (in bytes) that will be transferred using
757c478bd9Sstevel@tonic-gate  * an intermediate kernel buffer.  For sizes greater than this we map
767c478bd9Sstevel@tonic-gate  * in the destination pages and perform a 1-copy transfer.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate size_t	door_max_arg = 16 * 1024;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
81da6c28aaSamw  * Maximum amount of data that will be transferred in a reply to a
827c478bd9Sstevel@tonic-gate  * door_upcall.  Need to guard against a process returning huge amounts
837c478bd9Sstevel@tonic-gate  * of data and getting the kernel stuck in kmem_alloc.
847c478bd9Sstevel@tonic-gate  */
8561dfa509SRick McNeal size_t	door_max_upcall_reply = 4 * 1024 * 1024;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Maximum number of descriptors allowed to be passed in a single
897c478bd9Sstevel@tonic-gate  * door_call or door_return.  We need to allocate kernel memory
907c478bd9Sstevel@tonic-gate  * for all of them at once, so we can't let it scale without limit.
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate uint_t door_max_desc = 1024;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Definition of a door handle, used by other kernel subsystems when
967c478bd9Sstevel@tonic-gate  * calling door functions.  This is really a file structure but we
977c478bd9Sstevel@tonic-gate  * want to hide that fact.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate struct __door_handle {
1007c478bd9Sstevel@tonic-gate 	file_t dh_file;
1017c478bd9Sstevel@tonic-gate };
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #define	DHTOF(dh) ((file_t *)(dh))
1047c478bd9Sstevel@tonic-gate #define	FTODH(fp) ((door_handle_t)(fp))
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static int doorfs(long, long, long, long, long, long);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static struct sysent door_sysent = {
1097c478bd9Sstevel@tonic-gate 	6,
1107c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1117c478bd9Sstevel@tonic-gate 	(int (*)())doorfs,
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1157c478bd9Sstevel@tonic-gate 	&mod_syscallops, "doors", &door_sysent
1167c478bd9Sstevel@tonic-gate };
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int
1217c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
1227c478bd9Sstevel@tonic-gate     int32_t arg5, int32_t subcode);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static struct sysent door_sysent32 = {
1257c478bd9Sstevel@tonic-gate 	6,
1267c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1277c478bd9Sstevel@tonic-gate 	(int (*)())doorfs32,
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1317c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
1327c478bd9Sstevel@tonic-gate 	"32-bit door syscalls",
1337c478bd9Sstevel@tonic-gate 	&door_sysent32
1347c478bd9Sstevel@tonic-gate };
1357c478bd9Sstevel@tonic-gate #endif
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1387c478bd9Sstevel@tonic-gate 	MODREV_1,
1397c478bd9Sstevel@tonic-gate 	&modlsys,
1407c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1417c478bd9Sstevel@tonic-gate 	&modlsys32,
1427c478bd9Sstevel@tonic-gate #endif
1437c478bd9Sstevel@tonic-gate 	NULL
1447c478bd9Sstevel@tonic-gate };
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate dev_t	doordev;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate extern	struct vfs door_vfs;
1497c478bd9Sstevel@tonic-gate extern	struct vnodeops *door_vnodeops;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate int
_init(void)1527c478bd9Sstevel@tonic-gate _init(void)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t door_vfsops_template[] = {
1557c478bd9Sstevel@tonic-gate 		NULL, NULL
1567c478bd9Sstevel@tonic-gate 	};
1577c478bd9Sstevel@tonic-gate 	extern const fs_operation_def_t door_vnodeops_template[];
1587c478bd9Sstevel@tonic-gate 	vfsops_t *door_vfsops;
1597c478bd9Sstevel@tonic-gate 	major_t major;
1607c478bd9Sstevel@tonic-gate 	int error;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
1637c478bd9Sstevel@tonic-gate 	if ((major = getudev()) == (major_t)-1)
1647c478bd9Sstevel@tonic-gate 		return (ENXIO);
1657c478bd9Sstevel@tonic-gate 	doordev = makedevice(major, 0);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/* Create a dummy vfs */
1687c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(door_vfsops_template, &door_vfsops);
1697c478bd9Sstevel@tonic-gate 	if (error != 0) {
1707c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vfs ops");
1717c478bd9Sstevel@tonic-gate 		return (error);
1727c478bd9Sstevel@tonic-gate 	}
173da6c28aaSamw 	VFS_INIT(&door_vfs, door_vfsops, NULL);
1747c478bd9Sstevel@tonic-gate 	door_vfs.vfs_flag = VFS_RDONLY;
1757c478bd9Sstevel@tonic-gate 	door_vfs.vfs_dev = doordev;
1767c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
1797c478bd9Sstevel@tonic-gate 	if (error != 0) {
1807c478bd9Sstevel@tonic-gate 		vfs_freevfsops(door_vfsops);
1817c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vnode ops");
1827c478bd9Sstevel@tonic-gate 		return (error);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1887c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate /* system call functions */
1947c478bd9Sstevel@tonic-gate static int door_call(int, void *);
1957c478bd9Sstevel@tonic-gate static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
1967c478bd9Sstevel@tonic-gate static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
1977c478bd9Sstevel@tonic-gate     uint_t), void *data_cookie, uint_t);
1987c478bd9Sstevel@tonic-gate static int door_revoke(int);
1997c478bd9Sstevel@tonic-gate static int door_info(int, struct door_info *);
2007c478bd9Sstevel@tonic-gate static int door_ucred(struct ucred_s *);
2017c478bd9Sstevel@tonic-gate static int door_bind(int);
2027c478bd9Sstevel@tonic-gate static int door_unbind(void);
2037c478bd9Sstevel@tonic-gate static int door_unref(void);
2047c478bd9Sstevel@tonic-gate static int door_getparam(int, int, size_t *);
2057c478bd9Sstevel@tonic-gate static int door_setparam(int, int, size_t);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #define	DOOR_RETURN_OLD	4		/* historic value, for s10 */
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate static int
doorfs(long arg1,long arg2,long arg3,long arg4,long arg5,long subcode)2137c478bd9Sstevel@tonic-gate doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	switch (subcode) {
2167c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2177c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)arg2));
2187c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2197c478bd9Sstevel@tonic-gate 		door_return_desc_t *drdp = (door_return_desc_t *)arg3;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2227c478bd9Sstevel@tonic-gate 			door_return_desc_t drd;
2237c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2247c478bd9Sstevel@tonic-gate 				return (EFAULT);
2257c478bd9Sstevel@tonic-gate 			return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
2267c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)arg4, arg5));
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, NULL,
2297c478bd9Sstevel@tonic-gate 		    0, (caddr_t)arg4, arg5));
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2327c478bd9Sstevel@tonic-gate 		/*
2337c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2347c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2357c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2367c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2377c478bd9Sstevel@tonic-gate 		 */
2387c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
2397c478bd9Sstevel@tonic-gate 		    arg4, (caddr_t)arg5, 0));
2407c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
2417c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())arg1, (void *)arg2, arg3));
2427c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
2437c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
2447c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
2457c478bd9Sstevel@tonic-gate 		return (door_info(arg1, (struct door_info *)arg2));
2467c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
2477c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
2487c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
2497c478bd9Sstevel@tonic-gate 		return (door_unbind());
2507c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
2517c478bd9Sstevel@tonic-gate 		return (door_unref());
2527c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
2537c478bd9Sstevel@tonic-gate 		return (door_ucred((struct ucred_s *)arg1));
2547c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
2557c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2, (size_t *)arg3));
2567c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
2577c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, arg3));
2587c478bd9Sstevel@tonic-gate 	default:
2597c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls from 32-bit programs.
2667c478bd9Sstevel@tonic-gate  * Needed at the moment because of the casts - they undo some damage
2677c478bd9Sstevel@tonic-gate  * that truss causes (sign-extending the stack pointer) when truss'ing
2687c478bd9Sstevel@tonic-gate  * a 32-bit program using doors.
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate static int
doorfs32(int32_t arg1,int32_t arg2,int32_t arg3,int32_t arg4,int32_t arg5,int32_t subcode)2717c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
2727c478bd9Sstevel@tonic-gate     int32_t arg4, int32_t arg5, int32_t subcode)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	switch (subcode) {
2757c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2767c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
2777c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2787c478bd9Sstevel@tonic-gate 		door_return_desc32_t *drdp =
2797c478bd9Sstevel@tonic-gate 		    (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
2807c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2817c478bd9Sstevel@tonic-gate 			door_return_desc32_t drd;
2827c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2837c478bd9Sstevel@tonic-gate 				return (EFAULT);
2847c478bd9Sstevel@tonic-gate 			return (door_return(
2857c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
2867c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)drd.desc_ptr,
2877c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2887c478bd9Sstevel@tonic-gate 			    (size_t)(uintptr_t)(size32_t)arg5));
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
2917c478bd9Sstevel@tonic-gate 		    arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2927c478bd9Sstevel@tonic-gate 		    (size_t)(uintptr_t)(size32_t)arg5));
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2957c478bd9Sstevel@tonic-gate 		/*
2967c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2977c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2987c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2997c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
3007c478bd9Sstevel@tonic-gate 		 */
3017c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
3027c478bd9Sstevel@tonic-gate 		    (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
3037c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
3047c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
3057c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
3067c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)(caddr32_t)arg2, arg3));
3077c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
3087c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
3097c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
3107c478bd9Sstevel@tonic-gate 		return (door_info(arg1,
3117c478bd9Sstevel@tonic-gate 		    (struct door_info *)(uintptr_t)(caddr32_t)arg2));
3127c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
3137c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
3147c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
3157c478bd9Sstevel@tonic-gate 		return (door_unbind());
3167c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
3177c478bd9Sstevel@tonic-gate 		return (door_unref());
3187c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
3197c478bd9Sstevel@tonic-gate 		return (door_ucred(
3207c478bd9Sstevel@tonic-gate 		    (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
3217c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
3227c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2,
3237c478bd9Sstevel@tonic-gate 		    (size_t *)(uintptr_t)(caddr32_t)arg3));
3247c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
3257c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	default:
3287c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate #endif
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate void shuttle_resume(kthread_t *, kmutex_t *);
3347c478bd9Sstevel@tonic-gate void shuttle_swtch(kmutex_t *);
3357c478bd9Sstevel@tonic-gate void shuttle_sleep(kthread_t *);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * Support routines
3397c478bd9Sstevel@tonic-gate  */
3407c478bd9Sstevel@tonic-gate static int door_create_common(void (*)(), void *, uint_t, int, int *,
3417c478bd9Sstevel@tonic-gate     file_t **);
3427c478bd9Sstevel@tonic-gate static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3437c478bd9Sstevel@tonic-gate static int door_args(kthread_t *, int);
3447c478bd9Sstevel@tonic-gate static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3457c478bd9Sstevel@tonic-gate static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
346c4ace179Sdm static void	door_server_exit(proc_t *, kthread_t *);
3477c478bd9Sstevel@tonic-gate static void	door_release_server(door_node_t *, kthread_t *);
3487c478bd9Sstevel@tonic-gate static kthread_t	*door_get_server(door_node_t *);
3497c478bd9Sstevel@tonic-gate static door_node_t	*door_lookup(int, file_t **);
3507c478bd9Sstevel@tonic-gate static int	door_translate_in(void);
3517c478bd9Sstevel@tonic-gate static int	door_translate_out(void);
3527c478bd9Sstevel@tonic-gate static void	door_fd_rele(door_desc_t *, uint_t, int);
3537c478bd9Sstevel@tonic-gate static void	door_list_insert(door_node_t *);
3547c478bd9Sstevel@tonic-gate static void	door_info_common(door_node_t *, door_info_t *, file_t *);
3557c478bd9Sstevel@tonic-gate static int	door_release_fds(door_desc_t *, uint_t);
3567c478bd9Sstevel@tonic-gate static void	door_fd_close(door_desc_t *, uint_t);
3577c478bd9Sstevel@tonic-gate static void	door_fp_close(struct file **, uint_t);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate static door_data_t *
door_my_data(int create_if_missing)3607c478bd9Sstevel@tonic-gate door_my_data(int create_if_missing)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	door_data_t *ddp;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	ddp = curthread->t_door;
3657c478bd9Sstevel@tonic-gate 	if (create_if_missing && ddp == NULL)
3667c478bd9Sstevel@tonic-gate 		ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	return (ddp);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate static door_server_t *
door_my_server(int create_if_missing)3727c478bd9Sstevel@tonic-gate door_my_server(int create_if_missing)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate static door_client_t *
door_my_client(int create_if_missing)3807c478bd9Sstevel@tonic-gate door_my_client(int create_if_missing)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate  * System call to create a door
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate int
door_create(void (* pc_cookie)(),void * data_cookie,uint_t attributes)3917c478bd9Sstevel@tonic-gate door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	int fd;
3947c478bd9Sstevel@tonic-gate 	int err;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_CREATE_MASK) ||
3977c478bd9Sstevel@tonic-gate 	    ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3987c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI)))
3997c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
4027c478bd9Sstevel@tonic-gate 	    &fd, NULL)) != 0)
4037c478bd9Sstevel@tonic-gate 		return (set_errno(err));
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	f_setfd(fd, FD_CLOEXEC);
4067c478bd9Sstevel@tonic-gate 	return (fd);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * Common code for creating user and kernel doors.  If a door was
4117c478bd9Sstevel@tonic-gate  * created, stores a file structure pointer in the location pointed
4127c478bd9Sstevel@tonic-gate  * to by fpp (if fpp is non-NULL) and returns 0.  Also, if a non-NULL
4137c478bd9Sstevel@tonic-gate  * pointer to a file descriptor is passed in as fdp, allocates a file
4147c478bd9Sstevel@tonic-gate  * descriptor representing the door.  If a door could not be created,
4157c478bd9Sstevel@tonic-gate  * returns an error.
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate static int
door_create_common(void (* pc_cookie)(),void * data_cookie,uint_t attributes,int from_kernel,int * fdp,file_t ** fpp)4187c478bd9Sstevel@tonic-gate door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
4197c478bd9Sstevel@tonic-gate     int from_kernel, int *fdp, file_t **fpp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
4227c478bd9Sstevel@tonic-gate 	vnode_t		*vp;
4237c478bd9Sstevel@tonic-gate 	struct file	*fp;
4247c478bd9Sstevel@tonic-gate 	static door_id_t index = 0;
4257c478bd9Sstevel@tonic-gate 	proc_t		*p = (from_kernel)? &p0 : curproc;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	dp->door_vnode = vn_alloc(KM_SLEEP);
4307c478bd9Sstevel@tonic-gate 	dp->door_target = p;
4317c478bd9Sstevel@tonic-gate 	dp->door_data = data_cookie;
4327c478bd9Sstevel@tonic-gate 	dp->door_pc = pc_cookie;
4337c478bd9Sstevel@tonic-gate 	dp->door_flags = attributes;
4347c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4357c478bd9Sstevel@tonic-gate 	if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
4367c478bd9Sstevel@tonic-gate 		dp->door_data_max = UINT32_MAX;
4377c478bd9Sstevel@tonic-gate 	else
4387c478bd9Sstevel@tonic-gate #endif
4397c478bd9Sstevel@tonic-gate 		dp->door_data_max = SIZE_MAX;
4407c478bd9Sstevel@tonic-gate 	dp->door_data_min = 0UL;
4417c478bd9Sstevel@tonic-gate 	dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	vp = DTOV(dp);
4447c478bd9Sstevel@tonic-gate 	vn_setops(vp, door_vnodeops);
4457c478bd9Sstevel@tonic-gate 	vp->v_type = VDOOR;
4467c478bd9Sstevel@tonic-gate 	vp->v_vfsp = &door_vfs;
4477c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)dp;
4487c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
4497c478bd9Sstevel@tonic-gate 	dp->door_index = index++;
4507c478bd9Sstevel@tonic-gate 	/* add to per-process door list */
4517c478bd9Sstevel@tonic-gate 	door_list_insert(dp);
4527c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
4557c478bd9Sstevel@tonic-gate 		/*
4567c478bd9Sstevel@tonic-gate 		 * If the file table is full, remove the door from the
4577c478bd9Sstevel@tonic-gate 		 * per-process list, free the door, and return NULL.
4587c478bd9Sstevel@tonic-gate 		 */
4597c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
4607c478bd9Sstevel@tonic-gate 		door_list_delete(dp);
4617c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
4627c478bd9Sstevel@tonic-gate 		vn_free(vp);
4637c478bd9Sstevel@tonic-gate 		kmem_free(dp, sizeof (door_node_t));
4647c478bd9Sstevel@tonic-gate 		return (EMFILE);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 	vn_exists(vp);
4677c478bd9Sstevel@tonic-gate 	if (fdp != NULL)
4687c478bd9Sstevel@tonic-gate 		setf(*fdp, fp);
4697c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
4727c478bd9Sstevel@tonic-gate 		*fpp = fp;
4737c478bd9Sstevel@tonic-gate 	return (0);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate static int
door_check_limits(door_node_t * dp,door_arg_t * da,int upcall)4777c478bd9Sstevel@tonic-gate door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/* we allow unref upcalls through, despite any minimum */
4827c478bd9Sstevel@tonic-gate 	if (da->data_size < dp->door_data_min &&
4837c478bd9Sstevel@tonic-gate 	    !(upcall && da->data_ptr == DOOR_UNREF_DATA))
4847c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	if (da->data_size > dp->door_data_max)
4877c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
4907c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if (da->desc_num > dp->door_desc_max)
4937c478bd9Sstevel@tonic-gate 		return (ENFILE);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	return (0);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * Door invocation.
5007c478bd9Sstevel@tonic-gate  */
5017c478bd9Sstevel@tonic-gate int
door_call(int did,void * args)5027c478bd9Sstevel@tonic-gate door_call(int did, void *args)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate 	/* Locals */
5057c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
5067c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
5077c478bd9Sstevel@tonic-gate 	int		error = 0;
5087c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
5097c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
5107c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
5117c478bd9Sstevel@tonic-gate 	door_desc_t	*start = NULL;
5127c478bd9Sstevel@tonic-gate 	uint_t		ncopied = 0;
5137c478bd9Sstevel@tonic-gate 	size_t		dsize;
5147c478bd9Sstevel@tonic-gate 	/* destructor for data returned by a kernel server */
5157c478bd9Sstevel@tonic-gate 	void		(*destfn)() = NULL;
5167c478bd9Sstevel@tonic-gate 	void		*destarg;
5177c478bd9Sstevel@tonic-gate 	model_t		datamodel;
5187c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
519751c7f73Sjwadams 	int		needcleanup = 0;
520a574db85Sraf 	int		cancel_pending;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
5237c478bd9Sstevel@tonic-gate 	datamodel = lwp_getdatamodel(lwp);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	/*
5287c478bd9Sstevel@tonic-gate 	 * Get the arguments
5297c478bd9Sstevel@tonic-gate 	 */
5307c478bd9Sstevel@tonic-gate 	if (args) {
5317c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
5327c478bd9Sstevel@tonic-gate 			if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
5337c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5347c478bd9Sstevel@tonic-gate 		} else {
5357c478bd9Sstevel@tonic-gate 			door_arg32_t    da32;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 			if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
5387c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5397c478bd9Sstevel@tonic-gate 			ct->d_args.data_ptr =
5407c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.data_ptr;
5417c478bd9Sstevel@tonic-gate 			ct->d_args.data_size = da32.data_size;
5427c478bd9Sstevel@tonic-gate 			ct->d_args.desc_ptr =
5437c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)da32.desc_ptr;
5447c478bd9Sstevel@tonic-gate 			ct->d_args.desc_num = da32.desc_num;
5457c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf =
5467c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.rbuf;
5477c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = da32.rsize;
5487c478bd9Sstevel@tonic-gate 		}
5497c478bd9Sstevel@tonic-gate 	} else {
5507c478bd9Sstevel@tonic-gate 		/* No arguments, and no results allowed */
5517c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
5527c478bd9Sstevel@tonic-gate 		ct->d_args.data_size = 0;
5537c478bd9Sstevel@tonic-gate 		ct->d_args.desc_num = 0;
5547c478bd9Sstevel@tonic-gate 		ct->d_args.rsize = 0;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
5587c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
5597c478bd9Sstevel@tonic-gate 
560289175a0Sjwadams 	/*
561289175a0Sjwadams 	 * We don't want to hold the door FD over the entire operation;
562289175a0Sjwadams 	 * instead, we put a hold on the door vnode and release the FD
563289175a0Sjwadams 	 * immediately
564289175a0Sjwadams 	 */
565289175a0Sjwadams 	VN_HOLD(DTOV(dp));
566289175a0Sjwadams 	releasef(did);
567289175a0Sjwadams 
568c12957e9Sraf 	/*
569c12957e9Sraf 	 * This should be done in shuttle_resume(), just before going to
570c12957e9Sraf 	 * sleep, but we want to avoid overhead while holding door_knob.
571c12957e9Sraf 	 * prstop() is just a no-op if we don't really go to sleep.
572e28ad609SRoger A. Faulkner 	 * We test not-kernel-address-space for the sake of clustering code.
573c12957e9Sraf 	 */
574e28ad609SRoger A. Faulkner 	if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
575c12957e9Sraf 		prstop(PR_REQUESTED, 0);
576c12957e9Sraf 
5777c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
5787c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
5797c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5807c478bd9Sstevel@tonic-gate 		error = EBADF;
5817c478bd9Sstevel@tonic-gate 		goto out;
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	/*
5857c478bd9Sstevel@tonic-gate 	 * before we do anything, check that we are not overflowing the
5867c478bd9Sstevel@tonic-gate 	 * required limits.
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, &ct->d_args, 0);
5897c478bd9Sstevel@tonic-gate 	if (error != 0) {
5907c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5917c478bd9Sstevel@tonic-gate 		goto out;
5927c478bd9Sstevel@tonic-gate 	}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * Check for in-kernel door server.
5967c478bd9Sstevel@tonic-gate 	 */
5977c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
5987c478bd9Sstevel@tonic-gate 		caddr_t rbuf = ct->d_args.rbuf;
5997c478bd9Sstevel@tonic-gate 		size_t rsize = ct->d_args.rsize;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		dp->door_active++;
6027c478bd9Sstevel@tonic-gate 		ct->d_kernel = 1;
6037c478bd9Sstevel@tonic-gate 		ct->d_error = DOOR_WAIT;
6047c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6057c478bd9Sstevel@tonic-gate 		/* translate file descriptors to vnodes */
6067c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
6077c478bd9Sstevel@tonic-gate 			error = door_translate_in();
6087c478bd9Sstevel@tonic-gate 			if (error)
6097c478bd9Sstevel@tonic-gate 				goto out;
6107c478bd9Sstevel@tonic-gate 		}
6117c478bd9Sstevel@tonic-gate 		/*
6127c478bd9Sstevel@tonic-gate 		 * Call kernel door server.  Arguments are passed and
6137c478bd9Sstevel@tonic-gate 		 * returned as a door_arg pointer.  When called, data_ptr
6147c478bd9Sstevel@tonic-gate 		 * points to user data and desc_ptr points to a kernel list
6157c478bd9Sstevel@tonic-gate 		 * of door descriptors that have been converted to file
6167c478bd9Sstevel@tonic-gate 		 * structure pointers.  It's the server function's
6177c478bd9Sstevel@tonic-gate 		 * responsibility to copyin the data pointed to by data_ptr
6187c478bd9Sstevel@tonic-gate 		 * (this avoids extra copying in some cases).  On return,
6197c478bd9Sstevel@tonic-gate 		 * data_ptr points to a user buffer of data, and desc_ptr
6207c478bd9Sstevel@tonic-gate 		 * points to a kernel list of door descriptors representing
6217c478bd9Sstevel@tonic-gate 		 * files.  When a reference is passed to a kernel server,
6227c478bd9Sstevel@tonic-gate 		 * it is the server's responsibility to release the reference
6237c478bd9Sstevel@tonic-gate 		 * (by calling closef).  When the server includes a
6247c478bd9Sstevel@tonic-gate 		 * reference in its reply, it is released as part of the
6257c478bd9Sstevel@tonic-gate 		 * the call (the server must duplicate the reference if
6267c478bd9Sstevel@tonic-gate 		 * it wants to retain a copy).  The destfn, if set to
6277c478bd9Sstevel@tonic-gate 		 * non-NULL, is a destructor to be called when the returned
6287c478bd9Sstevel@tonic-gate 		 * kernel data (if any) is no longer needed (has all been
6297c478bd9Sstevel@tonic-gate 		 * translated and copied to user level).
6307c478bd9Sstevel@tonic-gate 		 */
6317c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &ct->d_args,
6327c478bd9Sstevel@tonic-gate 		    &destfn, &destarg, &error);
6337c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6347c478bd9Sstevel@tonic-gate 		/* not implemented yet */
6357c478bd9Sstevel@tonic-gate 		if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
6367c478bd9Sstevel@tonic-gate 			door_deliver_unref(dp);
6377c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6387c478bd9Sstevel@tonic-gate 		if (error)
6397c478bd9Sstevel@tonic-gate 			goto out;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		/* translate vnodes to files */
6427c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
6437c478bd9Sstevel@tonic-gate 			error = door_translate_out();
6447c478bd9Sstevel@tonic-gate 			if (error)
6457c478bd9Sstevel@tonic-gate 				goto out;
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 		ct->d_buf = ct->d_args.rbuf;
6487c478bd9Sstevel@tonic-gate 		ct->d_bufsize = ct->d_args.rsize;
6497c478bd9Sstevel@tonic-gate 		if (rsize < (ct->d_args.data_size +
6507c478bd9Sstevel@tonic-gate 		    (ct->d_args.desc_num * sizeof (door_desc_t)))) {
6517c478bd9Sstevel@tonic-gate 			/* handle overflow */
6527c478bd9Sstevel@tonic-gate 			error = door_overflow(curthread, ct->d_args.data_ptr,
6537c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size, ct->d_args.desc_ptr,
6547c478bd9Sstevel@tonic-gate 			    ct->d_args.desc_num);
6557c478bd9Sstevel@tonic-gate 			if (error)
6567c478bd9Sstevel@tonic-gate 				goto out;
6577c478bd9Sstevel@tonic-gate 			/* door_overflow sets d_args rbuf and rsize */
6587c478bd9Sstevel@tonic-gate 		} else {
6597c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = rbuf;
6607c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = rsize;
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 		goto results;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/*
6667c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
6677c478bd9Sstevel@tonic-gate 	 */
6687c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
6697c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
6707c478bd9Sstevel@tonic-gate 			error = EBADF;
6717c478bd9Sstevel@tonic-gate 		else
6727c478bd9Sstevel@tonic-gate 			error = EAGAIN;
6737c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6747c478bd9Sstevel@tonic-gate 		goto out;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
6787c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num || ct->d_args.data_size) {
6797c478bd9Sstevel@tonic-gate 		int is_private = (dp->door_flags & DOOR_PRIVATE);
6807c478bd9Sstevel@tonic-gate 		/*
6817c478bd9Sstevel@tonic-gate 		 * Move data from client to server
6827c478bd9Sstevel@tonic-gate 		 */
6837c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
6847c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6857c478bd9Sstevel@tonic-gate 		error = door_args(server_thread, is_private);
6867c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6877c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
6887c478bd9Sstevel@tonic-gate 		if (error) {
6897c478bd9Sstevel@tonic-gate 			/*
6907c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
6917c478bd9Sstevel@tonic-gate 			 */
6927c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
6937c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
6947c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
6957c478bd9Sstevel@tonic-gate 			goto out;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	dp->door_active++;
7007c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
701289175a0Sjwadams 	ct->d_args_done = 0;
7027c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
7037c478bd9Sstevel@tonic-gate 	st->d_active = dp;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
7087c478bd9Sstevel@tonic-gate shuttle_return:
7097c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
7107c478bd9Sstevel@tonic-gate 		/*
7117c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
7127c478bd9Sstevel@tonic-gate 		 */
7137c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
714a574db85Sraf 		cancel_pending = 0;
715a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
716a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
717a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
7187c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
7197c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
720a574db85Sraf 			if (cancel_pending)
721a574db85Sraf 				schedctl_cancel_eintr();
7227c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7237c478bd9Sstevel@tonic-gate 			error = EINTR;
7247c478bd9Sstevel@tonic-gate 			/*
7257c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
7267c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
7277c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
7287c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
7297c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
7307c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
7317c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
7327c478bd9Sstevel@tonic-gate 			 */
7337c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
7347c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
7357c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
7387c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
7417c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
7427c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
7457c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
7467c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
7497c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
7507c478bd9Sstevel@tonic-gate 				}
7517c478bd9Sstevel@tonic-gate 			}
7527c478bd9Sstevel@tonic-gate 		} else {
7537c478bd9Sstevel@tonic-gate 			/*
7547c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
7557c478bd9Sstevel@tonic-gate 			 *
7567c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
7577c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
7587c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
7597c478bd9Sstevel@tonic-gate 			 * is updated by the server.
7607c478bd9Sstevel@tonic-gate 			 */
7617c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7627c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
7637c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
7647c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
7657c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
7667c478bd9Sstevel@tonic-gate 				lwp->lwp_asleep = 0;
7677c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
7687c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
7697c478bd9Sstevel@tonic-gate 				/* Server exit */
7707c478bd9Sstevel@tonic-gate 				error = EINTR;
7717c478bd9Sstevel@tonic-gate 			} else {
7727c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
7737c478bd9Sstevel@tonic-gate 				error = ct->d_error;
7747c478bd9Sstevel@tonic-gate 			}
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 		/*
7777c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
7787c478bd9Sstevel@tonic-gate 		 * results for me.
7797c478bd9Sstevel@tonic-gate 		 */
7807c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
7817c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
7827c478bd9Sstevel@tonic-gate 
783289175a0Sjwadams 		/*
784289175a0Sjwadams 		 * If the server has not processed our message, free the
785289175a0Sjwadams 		 * descriptors.
786289175a0Sjwadams 		 */
787289175a0Sjwadams 		if (!ct->d_args_done) {
788751c7f73Sjwadams 			needcleanup = 1;
789289175a0Sjwadams 			ct->d_args_done = 1;
790289175a0Sjwadams 		}
791289175a0Sjwadams 
7927c478bd9Sstevel@tonic-gate 		/*
7937c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
7947c478bd9Sstevel@tonic-gate 		 */
7957c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
7967c478bd9Sstevel@tonic-gate 			gotresults = 1;
7977c478bd9Sstevel@tonic-gate 	}
798289175a0Sjwadams 	ASSERT(ct->d_args_done);
7997c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;		/* /proc */
8007c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;		/* /proc */
8017c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
8027c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
8037c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
8047c478bd9Sstevel@tonic-gate 
805751c7f73Sjwadams 	if (needcleanup)
806751c7f73Sjwadams 		door_fp_close(ct->d_fpp, ct->d_args.desc_num);
807751c7f73Sjwadams 
8087c478bd9Sstevel@tonic-gate results:
8097c478bd9Sstevel@tonic-gate 	/*
8107c478bd9Sstevel@tonic-gate 	 * Move the results to userland (if any)
8117c478bd9Sstevel@tonic-gate 	 */
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
8147c478bd9Sstevel@tonic-gate 		goto out;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (error) {
8177c478bd9Sstevel@tonic-gate 		/*
8187c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
8197c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
8207c478bd9Sstevel@tonic-gate 		 */
8217c478bd9Sstevel@tonic-gate 		if (gotresults) {
8227c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
8237c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
8247c478bd9Sstevel@tonic-gate 		}
8257c478bd9Sstevel@tonic-gate 		goto out;
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	/*
8297c478bd9Sstevel@tonic-gate 	 * Copy back data if we haven't caused an overflow (already
8307c478bd9Sstevel@tonic-gate 	 * handled) and we are using a 2 copy transfer, or we are
8317c478bd9Sstevel@tonic-gate 	 * returning data from a kernel server.
8327c478bd9Sstevel@tonic-gate 	 */
8337c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size) {
8347c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
8357c478bd9Sstevel@tonic-gate 		if (ct->d_kernel || (!ct->d_overflow &&
8367c478bd9Sstevel@tonic-gate 		    ct->d_args.data_size <= door_max_arg)) {
837289175a0Sjwadams 			if (copyout_nowatch(ct->d_buf, ct->d_args.rbuf,
8387c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size)) {
8397c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, ct->d_args.desc_num);
8407c478bd9Sstevel@tonic-gate 				error = EFAULT;
8417c478bd9Sstevel@tonic-gate 				goto out;
8427c478bd9Sstevel@tonic-gate 			}
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	/*
8477c478bd9Sstevel@tonic-gate 	 * stuff returned doors into our proc, copyout the descriptors
8487c478bd9Sstevel@tonic-gate 	 */
8497c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
8507c478bd9Sstevel@tonic-gate 		struct file	**fpp;
8517c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
8527c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 		dsize = n * sizeof (door_desc_t);
8557c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
8567c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 		while (n--) {
8597c478bd9Sstevel@tonic-gate 			if (door_insert(*fpp, didpp) == -1) {
8607c478bd9Sstevel@tonic-gate 				/* Close remaining files */
8617c478bd9Sstevel@tonic-gate 				door_fp_close(fpp, n + 1);
8627c478bd9Sstevel@tonic-gate 				error = EMFILE;
8637c478bd9Sstevel@tonic-gate 				goto out;
8647c478bd9Sstevel@tonic-gate 			}
8657c478bd9Sstevel@tonic-gate 			fpp++; didpp++; ncopied++;
8667c478bd9Sstevel@tonic-gate 		}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
8697c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
8707c478bd9Sstevel@tonic-gate 
871289175a0Sjwadams 		if (copyout_nowatch(start, ct->d_args.desc_ptr, dsize)) {
8727c478bd9Sstevel@tonic-gate 			error = EFAULT;
8737c478bd9Sstevel@tonic-gate 			goto out;
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/*
8787c478bd9Sstevel@tonic-gate 	 * Return the results
8797c478bd9Sstevel@tonic-gate 	 */
8807c478bd9Sstevel@tonic-gate 	if (datamodel == DATAMODEL_NATIVE) {
881289175a0Sjwadams 		if (copyout_nowatch(&ct->d_args, args,
882289175a0Sjwadams 		    sizeof (door_arg_t)) != 0)
8837c478bd9Sstevel@tonic-gate 			error = EFAULT;
8847c478bd9Sstevel@tonic-gate 	} else {
8857c478bd9Sstevel@tonic-gate 		door_arg32_t    da32;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 		da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr;
8887c478bd9Sstevel@tonic-gate 		da32.data_size = ct->d_args.data_size;
8897c478bd9Sstevel@tonic-gate 		da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr;
8907c478bd9Sstevel@tonic-gate 		da32.desc_num = ct->d_args.desc_num;
8917c478bd9Sstevel@tonic-gate 		da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf;
8927c478bd9Sstevel@tonic-gate 		da32.rsize = ct->d_args.rsize;
893289175a0Sjwadams 		if (copyout_nowatch(&da32, args, sizeof (door_arg32_t)) != 0) {
8947c478bd9Sstevel@tonic-gate 			error = EFAULT;
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate out:
8997c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/* clean up the overflow buffer if an error occurred */
9027c478bd9Sstevel@tonic-gate 	if (error != 0 && ct->d_overflow) {
9037c478bd9Sstevel@tonic-gate 		(void) as_unmap(curproc->p_as, ct->d_args.rbuf,
9047c478bd9Sstevel@tonic-gate 		    ct->d_args.rsize);
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 	ct->d_overflow = 0;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/* call destructor */
9097c478bd9Sstevel@tonic-gate 	if (destfn) {
9107c478bd9Sstevel@tonic-gate 		ASSERT(ct->d_kernel);
9117c478bd9Sstevel@tonic-gate 		(*destfn)(dp->door_data, destarg);
9127c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
9137c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	if (dp)
917289175a0Sjwadams 		VN_RELE(DTOV(dp));
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	if (ct->d_buf) {
9207c478bd9Sstevel@tonic-gate 		ASSERT(!ct->d_kernel);
9217c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_buf, ct->d_bufsize);
9227c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
9237c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
9247c478bd9Sstevel@tonic-gate 	}
9257c478bd9Sstevel@tonic-gate 	ct->d_kernel = 0;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/* clean up the descriptor copyout buffer */
9287c478bd9Sstevel@tonic-gate 	if (start != NULL) {
9297c478bd9Sstevel@tonic-gate 		if (error != 0)
9307c478bd9Sstevel@tonic-gate 			door_fd_close(start, ncopied);
9317c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
9357c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
9367c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
9377c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	if (error)
9417c478bd9Sstevel@tonic-gate 		return (set_errno(error));
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	return (0);
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate static int
door_setparam_common(door_node_t * dp,int from_kernel,int type,size_t val)9477c478bd9Sstevel@tonic-gate door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	int error = 0;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
9547c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9557c478bd9Sstevel@tonic-gate 		return (EBADF);
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/*
9597c478bd9Sstevel@tonic-gate 	 * door_ki_setparam() can only affect kernel doors.
9607c478bd9Sstevel@tonic-gate 	 * door_setparam() can only affect doors attached to the current
9617c478bd9Sstevel@tonic-gate 	 * process.
9627c478bd9Sstevel@tonic-gate 	 */
9637c478bd9Sstevel@tonic-gate 	if ((from_kernel && dp->door_target != &p0) ||
9647c478bd9Sstevel@tonic-gate 	    (!from_kernel && dp->door_target != curproc)) {
9657c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9667c478bd9Sstevel@tonic-gate 		return (EPERM);
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	switch (type) {
9707c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
9717c478bd9Sstevel@tonic-gate 		if (val > INT_MAX)
9727c478bd9Sstevel@tonic-gate 			error = ERANGE;
9737c478bd9Sstevel@tonic-gate 		else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0)
9747c478bd9Sstevel@tonic-gate 			error = ENOTSUP;
9757c478bd9Sstevel@tonic-gate 		else
9767c478bd9Sstevel@tonic-gate 			dp->door_desc_max = (uint_t)val;
9777c478bd9Sstevel@tonic-gate 		break;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
9807c478bd9Sstevel@tonic-gate 		if (val > dp->door_data_max)
9817c478bd9Sstevel@tonic-gate 			error = EINVAL;
9827c478bd9Sstevel@tonic-gate 		else
9837c478bd9Sstevel@tonic-gate 			dp->door_data_min = val;
9847c478bd9Sstevel@tonic-gate 		break;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
9877c478bd9Sstevel@tonic-gate 		if (val < dp->door_data_min)
9887c478bd9Sstevel@tonic-gate 			error = EINVAL;
9897c478bd9Sstevel@tonic-gate 		else
9907c478bd9Sstevel@tonic-gate 			dp->door_data_max = val;
9917c478bd9Sstevel@tonic-gate 		break;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	default:
9947c478bd9Sstevel@tonic-gate 		error = EINVAL;
9957c478bd9Sstevel@tonic-gate 		break;
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
9997c478bd9Sstevel@tonic-gate 	return (error);
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate static int
door_getparam_common(door_node_t * dp,int type,size_t * out)10037c478bd9Sstevel@tonic-gate door_getparam_common(door_node_t *dp, int type, size_t *out)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	int error = 0;
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
10087c478bd9Sstevel@tonic-gate 	switch (type) {
10097c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
10107c478bd9Sstevel@tonic-gate 		*out = (size_t)dp->door_desc_max;
10117c478bd9Sstevel@tonic-gate 		break;
10127c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
10137c478bd9Sstevel@tonic-gate 		*out = dp->door_data_min;
10147c478bd9Sstevel@tonic-gate 		break;
10157c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
10167c478bd9Sstevel@tonic-gate 		*out = dp->door_data_max;
10177c478bd9Sstevel@tonic-gate 		break;
10187c478bd9Sstevel@tonic-gate 	default:
10197c478bd9Sstevel@tonic-gate 		error = EINVAL;
10207c478bd9Sstevel@tonic-gate 		break;
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
10237c478bd9Sstevel@tonic-gate 	return (error);
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate int
door_setparam(int did,int type,size_t val)10277c478bd9Sstevel@tonic-gate door_setparam(int did, int type, size_t val)
10287c478bd9Sstevel@tonic-gate {
10297c478bd9Sstevel@tonic-gate 	door_node_t *dp;
10307c478bd9Sstevel@tonic-gate 	int error = 0;
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
10337c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	error = door_setparam_common(dp, 0, type, val);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	releasef(did);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	if (error)
10407c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	return (0);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate int
door_getparam(int did,int type,size_t * out)10467c478bd9Sstevel@tonic-gate door_getparam(int did, int type, size_t *out)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	door_node_t *dp;
10497c478bd9Sstevel@tonic-gate 	size_t val = 0;
10507c478bd9Sstevel@tonic-gate 	int error = 0;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
10537c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	error = door_getparam_common(dp, type, &val);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	releasef(did);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	if (error)
10607c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
10637c478bd9Sstevel@tonic-gate 		if (copyout(&val, out, sizeof (val)))
10647c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10657c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10667c478bd9Sstevel@tonic-gate 	} else {
10677c478bd9Sstevel@tonic-gate 		size32_t val32 = (size32_t)val;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 		if (val != val32)
10707c478bd9Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		if (copyout(&val32, out, sizeof (val32)))
10737c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10747c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	return (0);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate /*
10817c478bd9Sstevel@tonic-gate  * A copyout() which proceeds from high addresses to low addresses.  This way,
10827c478bd9Sstevel@tonic-gate  * stack guard pages are effective.
1083289175a0Sjwadams  *
1084289175a0Sjwadams  * Note that we use copyout_nowatch();  this is called while the client is
1085289175a0Sjwadams  * held.
10867c478bd9Sstevel@tonic-gate  */
10877c478bd9Sstevel@tonic-gate static int
door_stack_copyout(const void * kaddr,void * uaddr,size_t count)10887c478bd9Sstevel@tonic-gate door_stack_copyout(const void *kaddr, void *uaddr, size_t count)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	const char *kbase = (const char *)kaddr;
10917c478bd9Sstevel@tonic-gate 	uintptr_t ubase = (uintptr_t)uaddr;
10927c478bd9Sstevel@tonic-gate 	size_t pgsize = PAGESIZE;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	if (count <= pgsize)
1095289175a0Sjwadams 		return (copyout_nowatch(kaddr, uaddr, count));
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	while (count > 0) {
10987c478bd9Sstevel@tonic-gate 		uintptr_t start, end, offset, amount;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		end = ubase + count;
11017c478bd9Sstevel@tonic-gate 		start = P2ALIGN(end - 1, pgsize);
11027c478bd9Sstevel@tonic-gate 		if (P2ALIGN(ubase, pgsize) == start)
11037c478bd9Sstevel@tonic-gate 			start = ubase;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 		offset = start - ubase;
11067c478bd9Sstevel@tonic-gate 		amount = end - start;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		ASSERT(amount > 0 && amount <= count && amount <= pgsize);
1109