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