1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 3898 rsb * Common Development and Distribution License (the "License"). 6 3898 rsb * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 390 raf 22 0 stevel /* 23 5891 raf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* 28 0 stevel * System call I/F to doors (outside of vnodes I/F) and misc support 29 0 stevel * routines 30 0 stevel */ 31 0 stevel #include <sys/types.h> 32 0 stevel #include <sys/systm.h> 33 0 stevel #include <sys/door.h> 34 0 stevel #include <sys/door_data.h> 35 0 stevel #include <sys/proc.h> 36 0 stevel #include <sys/thread.h> 37 7112 raf #include <sys/prsystm.h> 38 7112 raf #include <sys/procfs.h> 39 0 stevel #include <sys/class.h> 40 0 stevel #include <sys/cred.h> 41 0 stevel #include <sys/kmem.h> 42 0 stevel #include <sys/cmn_err.h> 43 0 stevel #include <sys/stack.h> 44 0 stevel #include <sys/debug.h> 45 0 stevel #include <sys/cpuvar.h> 46 0 stevel #include <sys/file.h> 47 0 stevel #include <sys/fcntl.h> 48 0 stevel #include <sys/vnode.h> 49 0 stevel #include <sys/vfs.h> 50 3898 rsb #include <sys/vfs_opreg.h> 51 0 stevel #include <sys/sobject.h> 52 0 stevel #include <sys/schedctl.h> 53 0 stevel #include <sys/callb.h> 54 0 stevel #include <sys/ucred.h> 55 0 stevel 56 0 stevel #include <sys/mman.h> 57 0 stevel #include <sys/sysmacros.h> 58 0 stevel #include <sys/vmsystm.h> 59 0 stevel #include <vm/as.h> 60 0 stevel #include <vm/hat.h> 61 0 stevel #include <vm/page.h> 62 0 stevel #include <vm/seg.h> 63 0 stevel #include <vm/seg_vn.h> 64 0 stevel #include <vm/seg_vn.h> 65 0 stevel 66 0 stevel #include <sys/modctl.h> 67 0 stevel #include <sys/syscall.h> 68 0 stevel #include <sys/pathname.h> 69 0 stevel #include <sys/rctl.h> 70 0 stevel 71 0 stevel /* 72 5331 amw * The maximum amount of data (in bytes) that will be transferred using 73 0 stevel * an intermediate kernel buffer. For sizes greater than this we map 74 0 stevel * in the destination pages and perform a 1-copy transfer. 75 0 stevel */ 76 0 stevel size_t door_max_arg = 16 * 1024; 77 0 stevel 78 0 stevel /* 79 5331 amw * Maximum amount of data that will be transferred in a reply to a 80 0 stevel * door_upcall. Need to guard against a process returning huge amounts 81 0 stevel * of data and getting the kernel stuck in kmem_alloc. 82 0 stevel */ 83 0 stevel size_t door_max_upcall_reply = 1024 * 1024; 84 0 stevel 85 0 stevel /* 86 0 stevel * Maximum number of descriptors allowed to be passed in a single 87 0 stevel * door_call or door_return. We need to allocate kernel memory 88 0 stevel * for all of them at once, so we can't let it scale without limit. 89 0 stevel */ 90 0 stevel uint_t door_max_desc = 1024; 91 0 stevel 92 0 stevel /* 93 0 stevel * Definition of a door handle, used by other kernel subsystems when 94 0 stevel * calling door functions. This is really a file structure but we 95 0 stevel * want to hide that fact. 96 0 stevel */ 97 0 stevel struct __door_handle { 98 0 stevel file_t dh_file; 99 0 stevel }; 100 0 stevel 101 0 stevel #define DHTOF(dh) ((file_t *)(dh)) 102 0 stevel #define FTODH(fp) ((door_handle_t)(fp)) 103 0 stevel 104 0 stevel static int doorfs(long, long, long, long, long, long); 105 0 stevel 106 0 stevel static struct sysent door_sysent = { 107 0 stevel 6, 108 0 stevel SE_ARGC | SE_NOUNLOAD, 109 0 stevel (int (*)())doorfs, 110 0 stevel }; 111 0 stevel 112 0 stevel static struct modlsys modlsys = { 113 0 stevel &mod_syscallops, "doors", &door_sysent 114 0 stevel }; 115 0 stevel 116 0 stevel #ifdef _SYSCALL32_IMPL 117 0 stevel 118 0 stevel static int 119 0 stevel doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, 120 0 stevel int32_t arg5, int32_t subcode); 121 0 stevel 122 0 stevel static struct sysent door_sysent32 = { 123 0 stevel 6, 124 0 stevel SE_ARGC | SE_NOUNLOAD, 125 0 stevel (int (*)())doorfs32, 126 0 stevel }; 127 0 stevel 128 0 stevel static struct modlsys modlsys32 = { 129 0 stevel &mod_syscallops32, 130 0 stevel "32-bit door syscalls", 131 0 stevel &door_sysent32 132 0 stevel }; 133 0 stevel #endif 134 0 stevel 135 0 stevel static struct modlinkage modlinkage = { 136 0 stevel MODREV_1, 137 0 stevel &modlsys, 138 0 stevel #ifdef _SYSCALL32_IMPL 139 0 stevel &modlsys32, 140 0 stevel #endif 141 0 stevel NULL 142 0 stevel }; 143 0 stevel 144 0 stevel dev_t doordev; 145 0 stevel 146 0 stevel extern struct vfs door_vfs; 147 0 stevel extern struct vnodeops *door_vnodeops; 148 0 stevel 149 0 stevel int 150 0 stevel _init(void) 151 0 stevel { 152 0 stevel static const fs_operation_def_t door_vfsops_template[] = { 153 0 stevel NULL, NULL 154 0 stevel }; 155 0 stevel extern const fs_operation_def_t door_vnodeops_template[]; 156 0 stevel vfsops_t *door_vfsops; 157 0 stevel major_t major; 158 0 stevel int error; 159 0 stevel 160 0 stevel mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL); 161 0 stevel if ((major = getudev()) == (major_t)-1) 162 0 stevel return (ENXIO); 163 0 stevel doordev = makedevice(major, 0); 164 0 stevel 165 0 stevel /* Create a dummy vfs */ 166 0 stevel error = vfs_makefsops(door_vfsops_template, &door_vfsops); 167 0 stevel if (error != 0) { 168 0 stevel cmn_err(CE_WARN, "door init: bad vfs ops"); 169 0 stevel return (error); 170 0 stevel } 171 5331 amw VFS_INIT(&door_vfs, door_vfsops, NULL); 172 0 stevel door_vfs.vfs_flag = VFS_RDONLY; 173 0 stevel door_vfs.vfs_dev = doordev; 174 0 stevel vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0); 175 0 stevel 176 0 stevel error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops); 177 0 stevel if (error != 0) { 178 0 stevel vfs_freevfsops(door_vfsops); 179 0 stevel cmn_err(CE_WARN, "door init: bad vnode ops"); 180 0 stevel return (error); 181 0 stevel } 182 0 stevel return (mod_install(&modlinkage)); 183 0 stevel } 184 0 stevel 185 0 stevel int 186 0 stevel _info(struct modinfo *modinfop) 187 0 stevel { 188 0 stevel return (mod_info(&modlinkage, modinfop)); 189 0 stevel } 190 0 stevel 191 0 stevel /* system call functions */ 192 0 stevel static int door_call(int, void *); 193 0 stevel static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t); 194 0 stevel static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *, 195 0 stevel uint_t), void *data_cookie, uint_t); 196 0 stevel static int door_revoke(int); 197 0 stevel static int door_info(int, struct door_info *); 198 0 stevel static int door_ucred(struct ucred_s *); 199 0 stevel static int door_bind(int); 200 0 stevel static int door_unbind(void); 201 0 stevel static int door_unref(void); 202 0 stevel static int door_getparam(int, int, size_t *); 203 0 stevel static int door_setparam(int, int, size_t); 204 0 stevel 205 0 stevel #define DOOR_RETURN_OLD 4 /* historic value, for s10 */ 206 0 stevel 207 0 stevel /* 208 0 stevel * System call wrapper for all door related system calls 209 0 stevel */ 210 0 stevel static int 211 0 stevel doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode) 212 0 stevel { 213 0 stevel switch (subcode) { 214 0 stevel case DOOR_CALL: 215 0 stevel return (door_call(arg1, (void *)arg2)); 216 0 stevel case DOOR_RETURN: { 217 0 stevel door_return_desc_t *drdp = (door_return_desc_t *)arg3; 218 0 stevel 219 0 stevel if (drdp != NULL) { 220 0 stevel door_return_desc_t drd; 221 0 stevel if (copyin(drdp, &drd, sizeof (drd))) 222 0 stevel return (EFAULT); 223 0 stevel return (door_return((caddr_t)arg1, arg2, drd.desc_ptr, 224 0 stevel drd.desc_num, (caddr_t)arg4, arg5)); 225 0 stevel } 226 0 stevel return (door_return((caddr_t)arg1, arg2, NULL, 227 0 stevel 0, (caddr_t)arg4, arg5)); 228 0 stevel } 229 0 stevel case DOOR_RETURN_OLD: 230 0 stevel /* 231 0 stevel * In order to support the S10 runtime environment, we 232 0 stevel * still respond to the old syscall subcode for door_return. 233 0 stevel * We treat it as having no stack limits. This code should 234 0 stevel * be removed when such support is no longer needed. 235 0 stevel */ 236 0 stevel return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3, 237 0 stevel arg4, (caddr_t)arg5, 0)); 238 0 stevel case DOOR_CREATE: 239 0 stevel return (door_create((void (*)())arg1, (void *)arg2, arg3)); 240 0 stevel case DOOR_REVOKE: 241 0 stevel return (door_revoke(arg1)); 242 0 stevel case DOOR_INFO: 243 0 stevel return (door_info(arg1, (struct door_info *)arg2)); 244 0 stevel case DOOR_BIND: 245 0 stevel return (door_bind(arg1)); 246 0 stevel case DOOR_UNBIND: 247 0 stevel return (door_unbind()); 248 0 stevel case DOOR_UNREFSYS: 249 0 stevel return (door_unref()); 250 0 stevel case DOOR_UCRED: 251 0 stevel return (door_ucred((struct ucred_s *)arg1)); 252 0 stevel case DOOR_GETPARAM: 253 0 stevel return (door_getparam(arg1, arg2, (size_t *)arg3)); 254 0 stevel case DOOR_SETPARAM: 255 0 stevel return (door_setparam(arg1, arg2, arg3)); 256 0 stevel default: 257 0 stevel return (set_errno(EINVAL)); 258 0 stevel } 259 0 stevel } 260 0 stevel 261 0 stevel #ifdef _SYSCALL32_IMPL 262 0 stevel /* 263 0 stevel * System call wrapper for all door related system calls from 32-bit programs. 264 0 stevel * Needed at the moment because of the casts - they undo some damage 265 0 stevel * that truss causes (sign-extending the stack pointer) when truss'ing 266 0 stevel * a 32-bit program using doors. 267 0 stevel */ 268 0 stevel static int 269 0 stevel doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, 270 0 stevel int32_t arg4, int32_t arg5, int32_t subcode) 271 0 stevel { 272 0 stevel switch (subcode) { 273 0 stevel case DOOR_CALL: 274 0 stevel return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2)); 275 0 stevel case DOOR_RETURN: { 276 0 stevel door_return_desc32_t *drdp = 277 0 stevel (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3; 278 0 stevel if (drdp != NULL) { 279 0 stevel door_return_desc32_t drd; 280 0 stevel if (copyin(drdp, &drd, sizeof (drd))) 281 0 stevel return (EFAULT); 282 0 stevel return (door_return( 283 0 stevel (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2, 284 0 stevel (door_desc_t *)(uintptr_t)drd.desc_ptr, 285 0 stevel drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4, 286 0 stevel (size_t)(uintptr_t)(size32_t)arg5)); 287 0 stevel } 288 0 stevel return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, 289 0 stevel arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4, 290 0 stevel (size_t)(uintptr_t)(size32_t)arg5)); 291 0 stevel } 292 0 stevel case DOOR_RETURN_OLD: 293 0 stevel /* 294 0 stevel * In order to support the S10 runtime environment, we 295 0 stevel * still respond to the old syscall subcode for door_return. 296 0 stevel * We treat it as having no stack limits. This code should 297 0 stevel * be removed when such support is no longer needed. 298 0 stevel */ 299 0 stevel return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2, 300 0 stevel (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4, 301 0 stevel (caddr_t)(uintptr_t)(caddr32_t)arg5, 0)); 302 0 stevel case DOOR_CREATE: 303 0 stevel return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1, 304 0 stevel (void *)(uintptr_t)(caddr32_t)arg2, arg3)); 305 0 stevel case DOOR_REVOKE: 306 0 stevel return (door_revoke(arg1)); 307 0 stevel case DOOR_INFO: 308 0 stevel return (door_info(arg1, 309 0 stevel (struct door_info *)(uintptr_t)(caddr32_t)arg2)); 310 0 stevel case DOOR_BIND: 311 0 stevel return (door_bind(arg1)); 312 0 stevel case DOOR_UNBIND: 313 0 stevel return (door_unbind()); 314 0 stevel case DOOR_UNREFSYS: 315 0 stevel return (door_unref()); 316 0 stevel case DOOR_UCRED: 317 0 stevel return (door_ucred( 318 0 stevel (struct ucred_s *)(uintptr_t)(caddr32_t)arg1)); 319 0 stevel case DOOR_GETPARAM: 320 0 stevel return (door_getparam(arg1, arg2, 321 0 stevel (size_t *)(uintptr_t)(caddr32_t)arg3)); 322 0 stevel case DOOR_SETPARAM: 323 0 stevel return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3)); 324 0 stevel 325 0 stevel default: 326 0 stevel return (set_errno(EINVAL)); 327 0 stevel } 328 0 stevel } 329 0 stevel #endif 330 0 stevel 331 0 stevel void shuttle_resume(kthread_t *, kmutex_t *); 332 0 stevel void shuttle_swtch(kmutex_t *); 333 0 stevel void shuttle_sleep(kthread_t *); 334 0 stevel 335 0 stevel /* 336 0 stevel * Support routines 337 0 stevel */ 338 0 stevel static int door_create_common(void (*)(), void *, uint_t, int, int *, 339 0 stevel file_t **); 340 0 stevel static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t); 341 0 stevel static int door_args(kthread_t *, int); 342 0 stevel static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t); 343 0 stevel static int door_copy(struct as *, caddr_t, caddr_t, uint_t); 344 5540 dm120769 static void door_server_exit(proc_t *, kthread_t *); 345 0 stevel static void door_release_server(door_node_t *, kthread_t *); 346 0 stevel static kthread_t *door_get_server(door_node_t *); 347 0 stevel static door_node_t *door_lookup(int, file_t **); 348 0 stevel static int door_translate_in(void); 349 0 stevel static int door_translate_out(void); 350 0 stevel static void door_fd_rele(door_desc_t *, uint_t, int); 351 0 stevel static void door_list_insert(door_node_t *); 352 0 stevel static void door_info_common(door_node_t *, door_info_t *, file_t *); 353 0 stevel static int door_release_fds(door_desc_t *, uint_t); 354 0 stevel static void door_fd_close(door_desc_t *, uint_t); 355 0 stevel static void door_fp_close(struct file **, uint_t); 356 0 stevel 357 0 stevel static door_data_t * 358 0 stevel door_my_data(int create_if_missing) 359 0 stevel { 360 0 stevel door_data_t *ddp; 361 0 stevel 362 0 stevel ddp = curthread->t_door; 363 0 stevel if (create_if_missing && ddp == NULL) 364 0 stevel ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP); 365 0 stevel 366 0 stevel return (ddp); 367 0 stevel } 368 0 stevel 369 0 stevel static door_server_t * 370 0 stevel door_my_server(int create_if_missing) 371 0 stevel { 372 0 stevel door_data_t *ddp = door_my_data(create_if_missing); 373 0 stevel 374 0 stevel return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL); 375 0 stevel } 376 0 stevel 377 0 stevel static door_client_t * 378 0 stevel door_my_client(int create_if_missing) 379 0 stevel { 380 0 stevel door_data_t *ddp = door_my_data(create_if_missing); 381 0 stevel 382 0 stevel return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL); 383 0 stevel } 384 0 stevel 385 0 stevel /* 386 0 stevel * System call to create a door 387 0 stevel */ 388 0 stevel int 389 0 stevel door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes) 390 0 stevel { 391 0 stevel int fd; 392 0 stevel int err; 393 0 stevel 394 0 stevel if ((attributes & ~DOOR_CREATE_MASK) || 395 0 stevel ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) == 396 0 stevel (DOOR_UNREF | DOOR_UNREF_MULTI))) 397 0 stevel return (set_errno(EINVAL)); 398 0 stevel 399 0 stevel if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0, 400 0 stevel &fd, NULL)) != 0) 401 0 stevel return (set_errno(err)); 402 0 stevel 403 0 stevel f_setfd(fd, FD_CLOEXEC); 404 0 stevel return (fd); 405 0 stevel } 406 0 stevel 407 0 stevel /* 408 0 stevel * Common code for creating user and kernel doors. If a door was 409 0 stevel * created, stores a file structure pointer in the location pointed 410 0 stevel * to by fpp (if fpp is non-NULL) and returns 0. Also, if a non-NULL 411 0 stevel * pointer to a file descriptor is passed in as fdp, allocates a file 412 0 stevel * descriptor representing the door. If a door could not be created, 413 0 stevel * returns an error. 414 0 stevel */ 415 0 stevel static int 416 0 stevel door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes, 417 0 stevel int from_kernel, int *fdp, file_t **fpp) 418 0 stevel { 419 0 stevel door_node_t *dp; 420 0 stevel vnode_t *vp; 421 0 stevel struct file *fp; 422 0 stevel static door_id_t index = 0; 423 0 stevel proc_t *p = (from_kernel)? &p0 : curproc; 424 0 stevel 425 0 stevel dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP); 426 0 stevel 427 0 stevel dp->door_vnode = vn_alloc(KM_SLEEP); 428 0 stevel dp->door_target = p; 429 0 stevel dp->door_data = data_cookie; 430 0 stevel dp->door_pc = pc_cookie; 431 0 stevel dp->door_flags = attributes; 432 0 stevel #ifdef _SYSCALL32_IMPL 433 0 stevel if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE) 434 0 stevel dp->door_data_max = UINT32_MAX; 435 0 stevel else 436 0 stevel #endif 437 0 stevel dp->door_data_max = SIZE_MAX; 438 0 stevel dp->door_data_min = 0UL; 439 0 stevel dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX; 440 0 stevel 441 0 stevel vp = DTOV(dp); 442 0 stevel vn_setops(vp, door_vnodeops); 443 0 stevel vp->v_type = VDOOR; 444 0 stevel vp->v_vfsp = &door_vfs; 445 0 stevel vp->v_data = (caddr_t)dp; 446 0 stevel mutex_enter(&door_knob); 447 0 stevel dp->door_index = index++; 448 0 stevel /* add to per-process door list */ 449 0 stevel door_list_insert(dp); 450 0 stevel mutex_exit(&door_knob); 451 0 stevel 452 0 stevel if (falloc(vp, FREAD | FWRITE, &fp, fdp)) { 453 0 stevel /* 454 0 stevel * If the file table is full, remove the door from the 455 0 stevel * per-process list, free the door, and return NULL. 456 0 stevel */ 457 0 stevel mutex_enter(&door_knob); 458 0 stevel door_list_delete(dp); 459 0 stevel mutex_exit(&door_knob); 460 0 stevel vn_free(vp); 461 0 stevel kmem_free(dp, sizeof (door_node_t)); 462 0 stevel return (EMFILE); 463 0 stevel } 464 0 stevel vn_exists(vp); 465 0 stevel if (fdp != NULL) 466 0 stevel setf(*fdp, fp); 467 0 stevel mutex_exit(&fp->f_tlock); 468 0 stevel 469 0 stevel if (fpp != NULL) 470 0 stevel *fpp = fp; 471 0 stevel return (0); 472 0 stevel } 473 0 stevel 474 0 stevel static int 475 0 stevel door_check_limits(door_node_t *dp, door_arg_t *da, int upcall) 476 0 stevel { 477 0 stevel ASSERT(MUTEX_HELD(&door_knob)); 478 0 stevel 479 0 stevel /* we allow unref upcalls through, despite any minimum */ 480 0 stevel if (da->data_size < dp->door_data_min && 481 0 stevel !(upcall && da->data_ptr == DOOR_UNREF_DATA)) 482 0 stevel return (ENOBUFS); 483 0 stevel 484 0 stevel if (da->data_size > dp->door_data_max) 485 0 stevel return (ENOBUFS); 486 0 stevel 487 0 stevel if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC)) 488 0 stevel return (ENOTSUP); 489 0 stevel 490 0 stevel if (da->desc_num > dp->door_desc_max) 491 0 stevel return (ENFILE); 492 0 stevel 493 0 stevel return (0); 494 0 stevel } 495 0 stevel 496 0 stevel /* 497 0 stevel * Door invocation. 498 0 stevel */ 499 0 stevel int 500 0 stevel door_call(int did, void *args) 501 0 stevel { 502 0 stevel /* Locals */ 503 0 stevel door_node_t *dp; 504 0 stevel kthread_t *server_thread; 505 0 stevel int error = 0; 506 0 stevel klwp_t *lwp; 507 0 stevel door_client_t *ct; /* curthread door_data */ 508 0 stevel door_server_t *st; /* server thread door_data */ 509 0 stevel door_desc_t *start = NULL; 510 0 stevel uint_t ncopied = 0; 511 0 stevel size_t dsize; 512 0 stevel /* destructor for data returned by a kernel server */ 513 0 stevel void (*destfn)() = NULL; 514 0 stevel void *destarg; 515 0 stevel model_t datamodel; 516 0 stevel int gotresults = 0; 517 6818 jwadams int needcleanup = 0; 518 5891 raf int cancel_pending; 519 0 stevel 520 0 stevel lwp = ttolwp(curthread); 521 0 stevel datamodel = lwp_getdatamodel(lwp); 522 0 stevel 523 0 stevel ct = door_my_client(1); 524 0 stevel 525 0 stevel /* 526 0 stevel * Get the arguments 527 0 stevel */ 528 0 stevel if (args) { 529 0 stevel if (datamodel == DATAMODEL_NATIVE) { 530 0 stevel if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0) 531 0 stevel return (set_errno(EFAULT)); 532 0 stevel } else { 533 0 stevel door_arg32_t da32; 534 0 stevel 535 0 stevel if (copyin(args, &da32, sizeof (door_arg32_t)) != 0) 536 0 stevel return (set_errno(EFAULT)); 537 0 stevel ct->d_args.data_ptr = 538 0 stevel (char *)(uintptr_t)da32.data_ptr; 539 0 stevel ct->d_args.data_size = da32.data_size; 540 0 stevel ct->d_args.desc_ptr = 541 0 stevel (door_desc_t *)(uintptr_t)da32.desc_ptr; 542 0 stevel ct->d_args.desc_num = da32.desc_num; 543 0 stevel ct->d_args.rbuf = 544 0 stevel (char *)(uintptr_t)da32.rbuf; 545 0 stevel ct->d_args.rsize = da32.rsize; 546 0 stevel } 547 0 stevel } else { 548 0 stevel /* No arguments, and no results allowed */ 549 0 stevel ct->d_noresults = 1; 550 0 stevel ct->d_args.data_size = 0; 551 0 stevel ct->d_args.desc_num = 0; 552 0 stevel ct->d_args.rsize = 0; 553 0 stevel } 554 0 stevel 555 0 stevel if ((dp = door_lookup(did, NULL)) == NULL) 556 0 stevel return (set_errno(EBADF)); 557 0 stevel 558 6655 jwadams /* 559 6655 jwadams * We don't want to hold the door FD over the entire operation; 560 6655 jwadams * instead, we put a hold on the door vnode and release the FD 561 6655 jwadams * immediately 562 6655 jwadams */ 563 6655 jwadams VN_HOLD(DTOV(dp)); 564 6655 jwadams releasef(did); 565 7112 raf 566 7112 raf /* 567 7112 raf * This should be done in shuttle_resume(), just before going to 568 7112 raf * sleep, but we want to avoid overhead while holding door_knob. 569 7112 raf * prstop() is just a no-op if we don't really go to sleep. 570 7338 Roger * We test not-kernel-address-space for the sake of clustering code. 571 7112 raf */ 572 7338 Roger if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas) 573 7112 raf prstop(PR_REQUESTED, 0); 574 6655 jwadams 575 0 stevel mutex_enter(&door_knob); 576 0 stevel if (DOOR_INVALID(dp)) { 577 0 stevel mutex_exit(&door_knob); 578 0 stevel error = EBADF; 579 0 stevel goto out; 580 0 stevel } 581 0 stevel 582 0 stevel /* 583 0 stevel * before we do anything, check that we are not overflowing the 584 0 stevel * required limits. 585 0 stevel */ 586 0 stevel error = door_check_limits(dp, &ct->d_args, 0); 587 0 stevel if (error != 0) { 588 0 stevel mutex_exit(&door_knob); 589 0 stevel goto out; 590 0 stevel } 591 0 stevel 592 0 stevel /* 593 0 stevel * Check for in-kernel door server. 594 0 stevel */ 595 0 stevel if (dp->door_target == &p0) { 596 0 stevel caddr_t rbuf = ct->d_args.rbuf; 597 0 stevel size_t rsize = ct->d_args.rsize; 598 0 stevel 599 0 stevel dp->door_active++; 600 0 stevel ct->d_kernel = 1; 601 0 stevel ct->d_error = DOOR_WAIT; 602 0 stevel mutex_exit(&door_knob); 603 0 stevel /* translate file descriptors to vnodes */ 604 0 stevel if (ct->d_args.desc_num) { 605 0 stevel error = door_translate_in(); 606 0 stevel if (error) 607 0 stevel goto out; 608 0 stevel } 609 0 stevel /* 610 0 stevel * Call kernel door server. Arguments are passed and 611 0 stevel * returned as a door_arg pointer. When called, data_ptr 612 0 stevel * points to user data and desc_ptr points to a kernel list 613 0 stevel * of door descriptors that have been converted to file 614 0 stevel * structure pointers. It's the server function's 615 0 stevel * responsibility to copyin the data pointed to by data_ptr 616 0 stevel * (this avoids extra copying in some cases). On return, 617 0 stevel * data_ptr points to a user buffer of data, and desc_ptr 618 0 stevel * points to a kernel list of door descriptors representing 619 0 stevel * files. When a reference is passed to a kernel server, 620 0 stevel * it is the server's responsibility to release the reference 621 0 stevel * (by calling closef). When the server includes a 622 0 stevel * reference in its reply, it is released as part of the 623 0 stevel * the call (the server must duplicate the reference if 624 0 stevel * it wants to retain a copy). The destfn, if set to 625 0 stevel * non-NULL, is a destructor to be called when the returned 626 0 stevel * kernel data (if any) is no longer needed (has all been 627 0 stevel * translated and copied to user level). 628 0 stevel */ 629 0 stevel (*(dp->door_pc))(dp->door_data, &ct->d_args, 630 0 stevel &destfn, &destarg, &error); 631 0 stevel mutex_enter(&door_knob); 632 0 stevel /* not implemented yet */ 633 0 stevel if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY)) 634 0 stevel door_deliver_unref(dp); 635 0 stevel mutex_exit(&door_knob); 636 0 stevel if (error) 637 0 stevel goto out; 638 0 stevel 639 0 stevel /* translate vnodes to files */ 640 0 stevel if (ct->d_args.desc_num) { 641 0 stevel error = door_translate_out(); 642 0 stevel if (error) 643 0 stevel goto out; 644 0 stevel } 645 0 stevel ct->d_buf = ct->d_args.rbuf; 646 0 stevel ct->d_bufsize = ct->d_args.rsize; 647 0 stevel if (rsize < (ct->d_args.data_size + 648 0 stevel (ct->d_args.desc_num * sizeof (door_desc_t)))) { 649 0 stevel /* handle overflow */ 650 0 stevel error = door_overflow(curthread, ct->d_args.data_ptr, 651 0 stevel ct->d_args.data_size, ct->d_args.desc_ptr, 652 0 stevel ct->d_args.desc_num); 653 0 stevel if (error) 654 0 stevel goto out; 655 0 stevel /* door_overflow sets d_args rbuf and rsize */ 656 0 stevel } else { 657 0 stevel ct->d_args.rbuf = rbuf; 658 0 stevel ct->d_args.rsize = rsize; 659 0 stevel } 660 0 stevel goto results; 661 0 stevel } 662 0 stevel 663 0 stevel /* 664 0 stevel * Get a server thread from the target domain 665 0 stevel */ 666 0 stevel if ((server_thread = door_get_server(dp)) == NULL) { 667 0 stevel if (DOOR_INVALID(dp)) 668 0 stevel error = EBADF; 669 0 stevel else 670 0 stevel error = EAGAIN; 671 0 stevel mutex_exit(&door_knob); 672 0 stevel goto out; 673 0 stevel } 674 0 stevel 675 0 stevel st = DOOR_SERVER(server_thread->t_door); 676 0 stevel if (ct->d_args.desc_num || ct->d_args.data_size) { 677 0 stevel int is_private = (dp->door_flags & DOOR_PRIVATE); 678 0 stevel /* 679 0 stevel * Move data from client to server 680 0 stevel */ 681 0 stevel DOOR_T_HOLD(st); 682 0 stevel mutex_exit(&door_knob); 683 0 stevel error = door_args(server_thread, is_private); 684 0 stevel mutex_enter(&door_knob); 685 0 stevel DOOR_T_RELEASE(st); 686 0 stevel if (error) { 687 0 stevel /* 688 0 stevel * We're not going to resume this thread after all 689 0 stevel */ 690 0 stevel door_release_server(dp, server_thread); 691 0 stevel shuttle_sleep(server_thread); 692 0 stevel mutex_exit(&door_knob); 693 0 stevel goto out; 694 0 stevel } 695 0 stevel } 696 0 stevel 697 0 stevel dp->door_active++; 698 0 stevel ct->d_error = DOOR_WAIT; 699 6655 jwadams ct->d_args_done = 0; 700 0 stevel st->d_caller = curthread; 701 0 stevel st->d_active = dp; 702 0 stevel 703 0 stevel shuttle_resume(server_thread, &door_knob); 704 0 stevel 705 0 stevel mutex_enter(&door_knob); 706 0 stevel shuttle_return: 707 0 stevel if ((error = ct->d_error) < 0) { /* DOOR_WAIT or DOOR_EXIT */ 708 0 stevel /* 709 0 stevel * Premature wakeup. Find out why (stop, forkall, sig, exit ...) 710 0 stevel */ 711 0 stevel mutex_exit(&door_knob); /* May block in ISSIG */ 712 5891 raf cancel_pending = 0; 713 5891 raf if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort || 714 5891 raf MUSTRETURN(curproc, curthread) || 715 5891 raf (cancel_pending = schedctl_cancel_pending()) != 0) { 716 0 stevel /* Signal, forkall, ... */ 717 0 stevel lwp->lwp_sysabort = 0; 718 5891 raf if (cancel_pending) 719 5891 raf schedctl_cancel_eintr(); 720 0 stevel mutex_enter(&door_knob); 721 0 stevel error = EINTR; 722 0 stevel /* 723 0 stevel * If the server has finished processing our call, 724 0 stevel * or exited (calling door_slam()), then d_error 725 0 stevel * will have changed. If the server hasn't finished 726 0 stevel * yet, d_error will still be DOOR_WAIT, and we 727 0 stevel * let it know we are not interested in any 728 0 stevel * results by sending a SIGCANCEL, unless the door 729 0 stevel * is marked with DOOR_NO_CANCEL. 730 0 stevel */ 731 0 stevel if (ct->d_error == DOOR_WAIT && 732 0 stevel st->d_caller == curthread) { 733 0 stevel proc_t *p = ttoproc(server_thread); 734 0 stevel 735 0 stevel st->d_active = NULL; 736 0 stevel st->d_caller = NULL; 737 0 stevel 738 0 stevel if (!(dp->door_flags & DOOR_NO_CANCEL)) { 739 0 stevel DOOR_T_HOLD(st); 740 0 stevel mutex_exit(&door_knob); 741 0 stevel 742 0 stevel mutex_enter(&p->p_lock); 743 0 stevel sigtoproc(p, server_thread, SIGCANCEL); 744 0 stevel mutex_exit(&p->p_lock); 745 0 stevel 746 0 stevel mutex_enter(&door_knob); 747 0 stevel DOOR_T_RELEASE(st); 748 0 stevel } 749 0 stevel } 750 0 stevel } else { 751 0 stevel /* 752 0 stevel * Return from stop(), server exit... 753 0 stevel * 754 0 stevel * Note that the server could have done a 755 0 stevel * door_return while the client was in stop state 756 0 stevel * (ISSIG), in which case the error condition 757 0 stevel * is updated by the server. 758 0 stevel */ 759 0 stevel mutex_enter(&door_knob); 760 0 stevel if (ct->d_error == DOOR_WAIT) { 761 0 stevel /* Still waiting for a reply */ 762 0 stevel shuttle_swtch(&door_knob); 763 0 stevel mutex_enter(&door_knob); 764 0 stevel lwp->lwp_asleep = 0; 765 0 stevel goto shuttle_return; 766 0 stevel } else if (ct->d_error == DOOR_EXIT) { 767 0 stevel /* Server exit */ 768 0 stevel error = EINTR; 769 0 stevel } else { 770 0 stevel /* Server did a door_return during ISSIG */ 771 0 stevel error = ct->d_error; 772 0 stevel } 773 0 stevel } 774 0 stevel /* 775 0 stevel * Can't exit if the server is currently copying 776 0 stevel * results for me. 777 0 stevel */ 778 0 stevel while (DOOR_T_HELD(ct)) 779 0 stevel cv_wait(&ct->d_cv, &door_knob); 780 0 stevel 781 0 stevel /* 782 6655 jwadams * If the server has not processed our message, free the 783 6655 jwadams * descriptors. 784 6655 jwadams */ 785 6655 jwadams if (!ct->d_args_done) { 786 6818 jwadams needcleanup = 1; 787 6655 jwadams ct->d_args_done = 1; 788 6655 jwadams } 789 6655 jwadams 790 6655 jwadams /* 791 0 stevel * Find out if results were successfully copied. 792 0 stevel */ 793 0 stevel if (ct->d_error == 0) 794 0 stevel gotresults = 1; 795 0 stevel } 796 6655 jwadams ASSERT(ct->d_args_done); 797 0 stevel lwp->lwp_asleep = 0; /* /proc */ 798 0 stevel lwp->lwp_sysabort = 0; /* /proc */ 799 0 stevel if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY)) 800 0 stevel door_deliver_unref(dp); 801 0 stevel mutex_exit(&door_knob); 802 6818 jwadams 803 6818 jwadams if (needcleanup) 804 6818 jwadams door_fp_close(ct->d_fpp, ct->d_args.desc_num); 805 0 stevel 806 0 stevel results: 807 0 stevel /* 808 0 stevel * Move the results to userland (if any) 809 0 stevel */ 810 0 stevel 811 0 stevel if (ct->d_noresults) 812 0 stevel goto out; 813 0 stevel 814 0 stevel if (error) { 815 0 stevel /* 816 0 stevel * If server returned results successfully, then we've 817 0 stevel * been interrupted and may need to clean up. 818 0 stevel */ 819 0 stevel if (gotresults) { 820 0 stevel ASSERT(error == EINTR); 821 0 stevel door_fp_close(ct->d_fpp, ct->d_args.desc_num); 822 0 stevel } 823 0 stevel goto out; 824 0 stevel } 825 0 stevel 826 0 stevel /* 827 0 stevel * Copy back data if we haven't caused an overflow (already 828 0 stevel * handled) and we are using a 2 copy transfer, or we are 829 0 stevel * returning data from a kernel server. 830 0 stevel */ 831 0 stevel if (ct->d_args.data_size) { 832 0 stevel ct->d_args.data_ptr = ct->d_args.rbuf; 833 0 stevel if (ct->d_kernel || (!ct->d_overflow && 834 0 stevel ct->d_args.data_size <= door_max_arg)) { 835 6655 jwadams if (copyout_nowatch(ct->d_buf, ct->d_args.rbuf, 836 0 stevel ct->d_args.data_size)) { 837 0 stevel door_fp_close(ct->d_fpp, ct->d_args.desc_num); 838 0 stevel error = EFAULT; 839 0 stevel goto out; 840 0 stevel } 841 0 stevel } 842 0 stevel } 843 0 stevel 844 0 stevel /* 845 0 stevel * stuff returned doors into our proc, copyout the descriptors 846 0 stevel */ 847 0 stevel if (ct->d_args.desc_num) { 848 0 stevel struct file **fpp; 849 0 stevel door_desc_t *didpp; 850 0 stevel uint_t n = ct->d_args.desc_num; 851 0 stevel 852 0 stevel dsize = n * sizeof (door_desc_t); 853 0 stevel start = didpp = kmem_alloc(dsize, KM_SLEEP); 854 0 stevel fpp = ct->d_fpp; 855 0 stevel 856 0 stevel while (n--) { 857 0 stevel if (door_insert(*fpp, didpp) == -1) { 858 0 stevel /* Close remaining files */ 859 0 stevel door_fp_close(fpp, n + 1); 860 0 stevel error = EMFILE; 861 0 stevel goto out; 862 0 stevel } 863 0 stevel fpp++; didpp++; ncopied++; 864 0 stevel } 865 0 stevel 866 0 stevel ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf + 867 0 stevel roundup(ct->d_args.data_size, sizeof (door_desc_t))); 868 0 stevel 869 6655 jwadams if (copyout_nowatch(start, ct->d_args.desc_ptr, dsize)) { 870 0 stevel error = EFAULT; 871 0 stevel goto out; 872 0 stevel } 873 0 stevel } 874 0 stevel 875 0 stevel /* 876 0 stevel * Return the results 877 0 stevel */ 878 0 stevel if (datamodel == DATAMODEL_NATIVE) { 879 6655 jwadams if (copyout_nowatch(&ct->d_args, args, 880 6655 jwadams sizeof (door_arg_t)) != 0) 881 0 stevel error = EFAULT; 882 0 stevel } else { 883 0 stevel door_arg32_t da32; 884 0 stevel 885 0 stevel da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr; 886 0 stevel da32.data_size = ct->d_args.data_size; 887 0 stevel da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr; 888 0 stevel da32.desc_num = ct->d_args.desc_num; 889 0 stevel da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf; 890 0 stevel da32.rsize = ct->d_args.rsize; 891 6655 jwadams if (copyout_nowatch(&da32, args, sizeof (door_arg32_t)) != 0) { 892 0 stevel error = EFAULT; 893 0 stevel } 894 0 stevel } 895 0 stevel 896 0 stevel out: 897 0 stevel ct->d_noresults = 0; 898 0 stevel 899 0 stevel /* clean up the overflow buffer if an error occurred */ 900 0 stevel if (error != 0 && ct->d_overflow) { 901 0 stevel (void) as_unmap(curproc->p_as, ct->d_args.rbuf, 902 0 stevel ct->d_args.rsize); 903 0 stevel } 904 0 stevel ct->d_overflow = 0; 905 0 stevel 906 0 stevel /* call destructor */ 907 0 stevel if (destfn) { 908 0 stevel ASSERT(ct->d_kernel); 909 0 stevel (*destfn)(dp->door_data, destarg); 910 0 stevel ct->d_buf = NULL; 911 0 stevel ct->d_bufsize = 0; 912 0 stevel } 913 0 stevel 914 0 stevel if (dp) 915 6655 jwadams VN_RELE(DTOV(dp)); 916 0 stevel 917 0 stevel if (ct->d_buf) { 918 0 stevel ASSERT(!ct->d_kernel); 919 0 stevel kmem_free(ct->d_buf, ct->d_bufsize); 920 0 stevel ct->d_buf = NULL; 921 0 stevel ct->d_bufsize = 0; 922 0 stevel } 923 0 stevel ct->d_kernel = 0; 924 0 stevel 925 0 stevel /* clean up the descriptor copyout buffer */ 926 0 stevel if (start != NULL) { 927 0 stevel if (error != 0) 928 0 stevel door_fd_close(start, ncopied); 929 0 stevel kmem_free(start, dsize); 930 0 stevel } 931 0 stevel 932 0 stevel if (ct->d_fpp) { 933 0 stevel kmem_free(ct->d_fpp, ct->d_fpp_size); 934 0 stevel ct->d_fpp = NULL; 935 0 stevel ct->d_fpp_size = 0; 936 0 stevel } 937 0 stevel 938 0 stevel if (error) 939 0 stevel return (set_errno(error)); 940 0 stevel 941 0 stevel return (0); 942 0 stevel } 943 0 stevel 944 0 stevel static int 945 0 stevel door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val) 946 0 stevel { 947 0 stevel int error = 0; 948 0 stevel 949 0 stevel mutex_enter(&door_knob); 950 0 stevel 951 0 stevel if (DOOR_INVALID(dp)) { 952 0 stevel mutex_exit(&door_knob); 953 0 stevel return (EBADF); 954 0 stevel } 955 0 stevel 956 0 stevel /* 957 0 stevel * door_ki_setparam() can only affect kernel doors. 958 0 stevel * door_setparam() can only affect doors attached to the current 959 0 stevel * process. 960 0 stevel */ 961 0 stevel if ((from_kernel && dp->door_target != &p0) || 962 0 stevel (!from_kernel && dp->door_target != curproc)) { 963 0 stevel mutex_exit(&door_knob); 964 0 stevel return (EPERM); 965 0 stevel } 966 0 stevel 967 0 stevel switch (type) { 968 0 stevel case DOOR_PARAM_DESC_MAX: 969 0 stevel if (val > INT_MAX) 970 0 stevel error = ERANGE; 971 0 stevel else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0) 972 0 stevel error = ENOTSUP; 973 0 stevel else 974 0 stevel dp->door_desc_max = (uint_t)val; 975 0 stevel break; 976 0 stevel 977 0 stevel case DOOR_PARAM_DATA_MIN: 978 0 stevel if (val > dp->door_data_max) 979 0 stevel error = EINVAL; 980 0 stevel else 981 0 stevel dp->door_data_min = val; 982 0 stevel break; 983 0 stevel 984 0 stevel case DOOR_PARAM_DATA_MAX: 985 0 stevel if (val < dp->door_data_min) 986 0 stevel error = EINVAL; 987 0 stevel else 988 0 stevel dp->door_data_max = val; 989 0 stevel break; 990 0 stevel 991 0 stevel default: 992 0 stevel error = EINVAL; 993 0 stevel break; 994 0 stevel } 995 0 stevel 996 0 stevel mutex_exit(&door_knob); 997 0 stevel return (error); 998 0 stevel } 999 0 stevel 1000 0 stevel static int 1001 0 stevel door_getparam_common(door_node_t *dp, int type, size_t *out) 1002 0 stevel { 1003 0 stevel int error = 0; 1004 0 stevel 1005 0 stevel mutex_enter(&door_knob); 1006 0 stevel switch (type) { 1007 0 stevel case DOOR_PARAM_DESC_MAX: 1008 0 stevel *out = (size_t)dp->door_desc_max; 1009 0 stevel break; 1010 0 stevel case DOOR_PARAM_DATA_MIN: 1011 0 stevel *out = dp->door_data_min; 1012 0 stevel break; 1013 0 stevel case DOOR_PARAM_DATA_MAX: 1014 0 stevel *out = dp->door_data_max; 1015 0 stevel break; 1016 0 stevel default: 1017 0 stevel error = EINVAL; 1018 0 stevel break; 1019 0 stevel } 1020 0 stevel mutex_exit(&door_knob); 1021 0 stevel return (error); 1022 0 stevel } 1023 0 stevel 1024 0 stevel int 1025 0 stevel door_setparam(int did, int type, size_t val) 1026 0 stevel { 1027 0 stevel door_node_t *dp; 1028 0 stevel int error = 0; 1029 0 stevel 1030 0 stevel if ((dp = door_lookup(did, NULL)) == NULL) 1031 0 stevel return (set_errno(EBADF)); 1032 0 stevel 1033 0 stevel error = door_setparam_common(dp, 0, type, val); 1034 0 stevel 1035 0 stevel releasef(did); 1036 0 stevel 1037 0 stevel if (error) 1038 0 stevel return (set_errno(error)); 1039 0 stevel 1040 0 stevel return (0); 1041 0 stevel } 1042 0 stevel 1043 0 stevel int 1044 0 stevel door_getparam(int did, int type, size_t *out) 1045 0 stevel { 1046 0 stevel door_node_t *dp; 1047 0 stevel size_t val = 0; 1048 0 stevel int error = 0; 1049 0 stevel 1050 0 stevel if ((dp = door_lookup(did, NULL)) == NULL) 1051 0 stevel return (set_errno(EBADF)); 1052 0 stevel 1053 0 stevel error = door_getparam_common(dp, type, &val); 1054 0 stevel 1055 0 stevel releasef(did); 1056 0 stevel 1057 0 stevel if (error) 1058 0 stevel return (set_errno(error)); 1059 0 stevel 1060 0 stevel if (get_udatamodel() == DATAMODEL_NATIVE) { 1061 0 stevel if (copyout(&val, out, sizeof (val))) 1062 0 stevel return (set_errno(EFAULT)); 1063 0 stevel #ifdef _SYSCALL32_IMPL 1064 0 stevel } else { 1065 0 stevel size32_t val32 = (size32_t)val; 1066 0 stevel 1067 0 stevel if (val != val32) 1068 0 stevel return (set_errno(EOVERFLOW)); 1069 0 stevel 1070 0 stevel if (copyout(&val32, out, sizeof (val32))) 1071 0 stevel return (set_errno(EFAULT)); 1072 0 stevel #endif /* _SYSCALL32_IMPL */ 1073 0 stevel } 1074 0 stevel 1075 0 stevel return (0); 1076 0 stevel } 1077 0 stevel 1078 0 stevel /* 1079 0 stevel * A copyout() which proceeds from high addresses to low addresses. This way, 1080 0 stevel * stack guard pages are effective. 1081 6655 jwadams * 1082 6655 jwadams * Note that we use copyout_nowatch(); this is called while the client is 1083 6655 jwadams * held. 1084 0 stevel */ 1085 0 stevel static int 1086 0 stevel door_stack_copyout(const void *kaddr, void *uaddr, size_t count) 1087 0 stevel { 1088 0 stevel const char *kbase = (const char *)kaddr; 1089 0 stevel uintptr_t ubase = (uintptr_t)uaddr; 1090 0 stevel size_t pgsize = PAGESIZE; 1091 0 stevel 1092 0 stevel if (count <= pgsize) 1093 6655 jwadams return (copyout_nowatch(kaddr, uaddr, count)); 1094 0 stevel 1095 0 stevel while (count > 0) { 1096 0 stevel uintptr_t start, end, offset, amount; 1097 0 stevel 1098 0 stevel end = ubase + count; 1099 0 stevel start = P2ALIGN(end - 1, pgsize); 1100 0 stevel if (P2ALIGN(ubase, pgsize) == start) 1101 0 stevel start = ubase; 1102 0 stevel 1103 0 stevel offset = start - ubase; 1104 0 stevel amount = end - start; 1105 0 stevel 1106 0 stevel ASSERT(amount > 0 && amount <= count && amount <= pgsize); 1107 0 stevel 1108 6655 jwadams if (copyout_nowatch(kbase + offset, (void *)start, amount)) 1109 0 stevel return (1); 1110 0 stevel count -= amount; 1111 0 stevel } 1112 0 stevel return (0); 1113 0 stevel } 1114 0 stevel 1115 0 stevel /* 1116 0 stevel * Writes the stack layout for door_return() into the door_server_t of the 1117 0 stevel * server thread. 1118 0 stevel */ 1119 0 stevel static int 1120 0 stevel door_layout(kthread_t *tp, size_t data_size, uint_t ndesc, int info_needed) 1121 0 stevel { 1122 0 stevel door_server_t *st = DOOR_SERVER(tp->t_door); 1123 0 stevel door_layout_t *out = &st->d_layout; 1124 0 stevel uintptr_t base_sp = (uintptr_t)st->d_sp; 1125 0 stevel size_t ssize = st->d_ssize; 1126 0 stevel size_t descsz; 1127 0 stevel uintptr_t descp, datap, infop, resultsp, finalsp; 1128 0 stevel size_t align = STACK_ALIGN; 1129 0 stevel size_t results_sz = sizeof (struct door_results); 1130 0 stevel model_t datamodel = lwp_getdatamodel(ttolwp(tp)); 1131 0 stevel 1132 0 stevel ASSERT(!st->d_layout_done); 1133 0 stevel 1134 0 stevel #ifndef _STACK_GROWS_DOWNWARD 1135 0 stevel #error stack does not grow downward, door_layout() must change 1136 0 stevel #endif 1137 0 stevel 1138 0 stevel #ifdef _SYSCALL32_IMPL 1139 0 stevel if (datamodel != DATAMODEL_NATIVE) { 1140 0 stevel align = STACK_ALIGN32; 1141 0 stevel results_sz = sizeof (struct door_results32); 1142 0 stevel } 1143 0 stevel #endif 1144 0 stevel 1145 0 stevel descsz = ndesc * sizeof (door_desc_t); 1146 0 stevel 1147 0 stevel /* 1148 0 stevel * To speed up the overflow checking, we do an initial check 1149 0 stevel * that the passed in data size won't cause us to wrap past 1150 0 stevel * base_sp. Since door_max_desc limits descsz, we can 1151 0 stevel * safely use it here. 65535 is an arbitrary 'bigger than 1152 0 stevel * we need, small enough to not cause trouble' constant; 1153 0 stevel * the only constraint is that it must be > than: 1154 0 stevel * 1155 0 stevel * 5 * STACK_ALIGN + 1156 0 stevel * sizeof (door_info_t) + 1157 0 stevel * sizeof (door_results_t) + 1158 0 stevel * (max adjustment from door_final_sp()) 1159 0 stevel * 1160 0 stevel * After we compute the layout, we can safely do a "did we wrap 1161 0 stevel * around" check, followed by a check against the recorded 1162 0 stevel * stack size. 1163 0 stevel */ 1164 0 stevel if (data_size >= SIZE_MAX - (size_t)65535UL - descsz) 1165 0 stevel return (E2BIG); /* overflow */ 1166 0 stevel 1167 0 stevel descp = P2ALIGN(base_sp - descsz, align); 1168 0 stevel datap = P2ALIGN(descp - data_size, align); 1169 0 stevel 1170 0 stevel if (info_needed) 1171 0 stevel infop = P2ALIGN(datap - sizeof (door_info_t), align); 1172 0 stevel else 1173 0 stevel infop = datap; 1174 0 stevel 1175 0 stevel resultsp = P2ALIGN(infop - results_sz, align); 1176 0 stevel finalsp = door_final_sp(resultsp, align, datamodel); 1177 0 stevel 1178 0 stevel if (finalsp > base_sp) 1179 0 stevel return (E2BIG); /* overflow */ 1180 0 stevel 1181 0 stevel if (ssize != 0 && (base_sp - finalsp) > ssize) 1182 0 stevel return (E2BIG); /* doesn't fit in stack */ 1183 0 stevel 1184 0 stevel out->dl_descp = (ndesc != 0)? (caddr_t)descp : 0; 1185 0 stevel out->dl_datap = (data_size != 0)? (caddr_t)datap : 0; 1186 0 stevel out->dl_infop = info_needed? (caddr_t)infop : 0; 1187 0 stevel out->dl_resultsp = (caddr_t)resultsp; 1188 0 stevel out->dl_sp = (caddr_t)finalsp; 1189 0 stevel 1190 0 stevel st->d_layout_done = 1; 1191 0 stevel return (0); 1192 0 stevel } 1193 0 stevel 1194 0 stevel static int 1195 0 stevel door_server_dispatch(door_client_t *ct, door_node_t *dp) 1196 0 stevel { 1197 0 stevel door_server_t *st = DOOR_SERVER(curthread->t_door); 1198 0 stevel door_layout_t *layout = &st->d_layout; 1199 0 stevel int error = 0; 1200 0 stevel 1201 0 stevel int is_private = (dp->door_flags & DOOR_PRIVATE); 1202 0 stevel 1203 0 stevel door_pool_t *pool = (is_private)? &dp->door_servers : 1204 0 stevel &curproc->p_server_threads; 1205 0 stevel 1206 0 stevel int empty_pool = (pool->dp_threads == NULL); 1207 0 stevel 1208 0 stevel caddr_t infop = NULL; 1209 0 stevel char *datap = NULL; 1210 0 stevel size_t datasize = 0; 1211 0 stevel size_t descsize; 1212 0 stevel 1213 0 stevel file_t **fpp = ct->d_fpp; 1214 0 stevel door_desc_t *start = NULL; 1215 0 stevel uint_t ndesc = 0; 1216 0 stevel uint_t ncopied = 0; 1217 0 stevel 1218 0 stevel if (ct != NULL) { 1219 0 stevel datap = ct->d_args.data_ptr; 1220 0 stevel datasize = ct->d_args.data_size; 1221 0 stevel ndesc = ct->d_args.desc_num; 1222 0 stevel } 1223 0 stevel 1224 0 stevel descsize = ndesc * sizeof (door_desc_t); 1225 0 stevel 1226 0 stevel /* 1227 0 stevel * Reset datap to NULL if we aren't passing any data. Be careful 1228 0 stevel * to let unref notifications through, though. 1229 0 stevel */ 1230 0 stevel if (datap == DOOR_UNREF_DATA) { 1231 6997 jwadams if (ct->d_upcall != NULL) 1232 0 stevel datasize = 0; 1233 0 stevel else 1234 0 stevel datap = NULL; 1235 0 stevel } else if (datasize == 0) { 1236 0 stevel datap = NULL; 1237 0 stevel } 1238 0 stevel 1239 0 stevel /* 1240 0 stevel * Get the stack layout, if it hasn't already been done. 1241 0 stevel */ 1242 0 stevel if (!st->d_layout_done) { 1243 0 stevel error = door_layout(curthread, datasize, ndesc, 1244 0 stevel (is_private && empty_pool)); 1245 0 stevel if (error != 0) 1246 0 stevel goto fail; 1247 0 stevel } 1248 0 stevel 1249 0 stevel /* 1250 0 stevel * fill out the stack, starting from the top. Layout was already 1251 0 stevel * filled in by door_args() or door_translate_out(). 1252 0 stevel */ 1253 0 stevel if (layout->dl_descp != NULL) { 1254 0 stevel ASSERT(ndesc != 0); 1255 0 stevel start = kmem_alloc(descsize, KM_SLEEP); 1256 0 stevel 1257 0 stevel while (ndesc > 0) { 1258 0 stevel if (door_insert(*fpp, &start[ncopied]) == -1) { 1259 0 stevel error = EMFILE; 1260 0 stevel goto fail; 1261 0 stevel } 1262 0 stevel ndesc--; 1263 0 stevel ncopied++; 1264 0 stevel fpp++; 1265 0 stevel } 1266 0 stevel if (door_stack_copyout(start, layout->dl_descp, descsize)) { 1267 0 stevel error = E2BIG; 1268 0 stevel goto fail; 1269 0 stevel } 1270 0 stevel } 1271 0 stevel fpp = NULL; /* finished processing */ 1272 0 stevel 1273 0 stevel if (layout->dl_datap != NULL) { 1274 0 stevel ASSERT(datasize != 0); 1275 0 stevel datap = layout->dl_datap; 1276 6997 jwadams if (ct->d_upcall != NULL || datasize <= door_max_arg) { 1277 0 stevel if (door_stack_copyout(ct->d_buf, datap, datasize)) { 1278 0 stevel error = E2BIG; 1279 0 stevel goto fail; 1280 0 stevel } 1281 0 stevel } 1282 0 stevel } 1283 0 stevel 1284 0 stevel if (is_private && empty_pool) { 1285 0 stevel door_info_t di; 1286 0 stevel 1287 0 stevel infop = layout->dl_infop; 1288 0 stevel ASSERT(infop != NULL); 1289 0 stevel 1290 0 stevel di.di_target = curproc->p_pid; 1291 0 stevel di.di_proc = (door_ptr_t)(uintptr_t)dp->door_pc; 1292 0 stevel di.di_data = (door_ptr_t)(uintptr_t)dp->door_data; 1293 0 stevel di.di_uniquifier = dp->door_index; 1294 0 stevel di.di_attributes = (dp->door_flags & DOOR_ATTR_MASK) | 1295 0 stevel DOOR_LOCAL; 1296 0 stevel 1297 6655 jwadams if (door_stack_copyout(&di, infop, sizeof (di))) { 1298 0 stevel error = E2BIG; 1299 0 stevel goto fail; 1300 0 stevel } 1301 0 stevel } 1302 0 stevel 1303 0 stevel if (get_udatamodel() == DATAMODEL_NATIVE) { 1304 0 stevel struct door_results dr; 1305 0 stevel 1306 0 stevel dr.cookie = dp->door_data; 1307 0 stevel dr.data_ptr = datap; 1308 0 stevel dr.data_size = datasize; 1309 0 stevel dr.desc_ptr = (door_desc_t *)layout->dl_descp; 1310 0 stevel dr.desc_num = ncopied; 1311 0 stevel dr.pc = dp->door_pc; 1312 0 stevel dr.nservers = !empty_pool; 1313 0 stevel dr.door_info = (door_info_t *)infop; 1314 0 stevel 1315 6655 jwadams if (door_stack_copyout(&dr, layout->dl_resultsp, sizeof (dr))) { 1316 0 stevel error = E2BIG; 1317 0 stevel goto fail; 1318 0 stevel } 1319 0 stevel #ifdef _SYSCALL32_IMPL 1320 0 stevel } else { 1321 0 stevel struct door_results32 dr32; 1322 0 stevel 1323 0 stevel dr32.cookie = (caddr32_t)(uintptr_t)dp->door_data; 1324 0 stevel dr32.data_ptr = (caddr32_t)(uintptr_t)datap; 1325 0 stevel dr32.data_size = (size32_t)datasize; 1326 0 stevel dr32.desc_ptr = (caddr32_t)(uintptr_t)layout->dl_descp; 1327 0 stevel dr32.desc_num = ncopied; 1328 0 stevel dr32.pc = (caddr32_t)(uintptr_t)dp->door_pc; 1329 0 stevel dr32.nservers = !empty_pool; 1330 0 stevel dr32.door_info = (caddr32_t)(uintptr_t)infop; 1331 0 stevel 1332 6655 jwadams if (door_stack_copyout(&dr32, layout->dl_resultsp, 1333 6655 jwadams sizeof (dr32))) { 1334 0 stevel error = E2BIG; 1335 0 stevel goto fail; 1336 0 stevel } 1337 0 stevel #endif 1338 0 stevel } 1339 0 stevel 1340 0 stevel error = door_finish_dispatch(layout->dl_sp); 1341 0 stevel fail: 1342 0 stevel if (start != NULL) { 1343 0 stevel if (error != 0) 1344 0 stevel door_fd_close(start, ncopied); 1345 0 stevel kmem_free(start, descsize); 1346 0 stevel } 1347 0 stevel if (fpp != NULL) 1348 0 stevel door_fp_close(fpp, ndesc); 1349 0 stevel 1350 0 stevel return (error); 1351 0 stevel } 1352 0 stevel 1353 0 stevel /* 1354 0 stevel * Return the results (if any) to the caller (if any) and wait for the 1355 0 stevel * next invocation on a door. 1356 0 stevel */ 1357 0 stevel int 1358 0 stevel door_return(caddr_t data_ptr, size_t data_size, 1359 0 stevel door_desc_t *desc_ptr, uint_t desc_num, caddr_t sp, size_t ssize) 1360 0 stevel { 1361 0 stevel kthread_t *caller; 1362 0 stevel klwp_t *lwp; 1363 0 stevel int error = 0; 1364 0 stevel door_node_t *dp; 1365 0 stevel door_server_t *st; /* curthread door_data */ 1366 0 stevel door_client_t *ct; /* caller door_data */ 1367 5891 raf int cancel_pending; 1368 0 stevel 1369 0 stevel st = door_my_server(1); 1370 0 stevel 1371 0 stevel /* 1372 0 stevel * If thread was bound to a door that no longer exists, return 1373 0 stevel * an error. This can happen if a thread is bound to a door 1374 0 stevel * before the process calls forkall(); in the child, the door 1375 0 stevel * doesn't exist and door_fork() sets the d_invbound flag. 1376 0 stevel */ 1377 0 stevel if (st->d_invbound) 1378 0 stevel return (set_errno(EINVAL)); 1379 0 stevel 1380 0 stevel st->d_sp = sp; /* Save base of stack. */ 1381 0 stevel st->d_ssize = ssize; /* and its size */ 1382 0 stevel 1383 0 stevel /* 1384 7112 raf * This should be done in shuttle_resume(), just before going to 1385 7112 raf * sleep, but we want to avoid overhead while holding door_knob. 1386 7112 raf * prstop() is just a no-op if we don't really go to sleep. 1387 7338 Roger * We test not-kernel-address-space for the sake of clustering code. 1388 0 stevel */ 1389 7112 raf lwp = ttolwp(curthread); 1390 7338 Roger if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas) 1391 7112 raf prstop(PR_REQUESTED, 0); 1392 0 stevel 1393 0 stevel /* Make sure the caller hasn't gone away */ 1394 0 stevel mutex_enter(&door_knob); 1395 0 stevel if ((caller = st->d_caller) == NULL || caller->t_door == NULL) { 1396 0 stevel if (desc_num != 0) { 1397 0 stevel /* close any DOOR_RELEASE descriptors */ 1398 0 stevel mutex_exit(&door_knob); 1399 0 stevel error = door_release_fds(desc_ptr, desc_num); 1400 0 stevel if (error) 1401 0 stevel return (set_errno(error)); 1402 0 stevel mutex_enter(&door_knob); 1403 0 stevel } 1404 0 stevel goto out; 1405 0 stevel } 1406 0 stevel ct = DOOR_CLIENT(caller->t_door); 1407 0 stevel 1408 0 stevel ct->d_args.data_size = data_size; 1409 0 stevel ct->d_args.desc_num = desc_num; 1410 0 stevel /* 1411 0 stevel * Transfer results, if any, to the client 1412 0 stevel */ 1413 0 stevel if (data_size != 0 || desc_num != 0) { 1414 0 stevel /* 1415 0 stevel * Prevent the client from exiting until we have finished 1416 0 stevel * moving results. 1417 0 stevel */ 1418 0 stevel DOOR_T_HOLD(ct); 1419 0 stevel mutex_exit(&door_knob); 1420 0 stevel error = door_results(caller, data_ptr, data_size, 1421 0 stevel desc_ptr, desc_num); 1422 0 stevel mutex_enter(&door_knob); 1423 0 stevel DOOR_T_RELEASE(ct); 1424 0 stevel /* 1425 0 stevel * Pass EOVERFLOW errors back to the client 1426 0 stevel */ 1427 0 stevel if (error && error != EOVERFLOW) { 1428 0 stevel mutex_exit(&door_knob); 1429 0 stevel return (set_errno(error)); 1430 0 stevel } 1431 0 stevel } 1432 0 stevel out: 1433 0 stevel /* Put ourselves on the available server thread list */ 1434 0 stevel door_release_server(st->d_pool, curthread); 1435 0 stevel 1436 0 stevel /* 1437 0 stevel * Make sure the caller is still waiting to be resumed 1438 0 stevel */ 1439 0 stevel if (caller) { 1440 0 stevel disp_lock_t *tlp; 1441 0 stevel 1442 0 stevel thread_lock(caller); 1443 0 stevel ct->d_error = error; /* Return any errors */ 1444 0 stevel if (caller->t_state == TS_SLEEP && 1445 0 stevel SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) { 1446 0 stevel cpu_t *cp = CPU; 1447 0 stevel 1448 0 stevel tlp = caller->t_lockp; 1449 0 stevel /* 1450 0 stevel * Setting t_disp_queue prevents erroneous preemptions 1451 0 stevel * if this thread is still in execution on another 1452 0 stevel * processor 1453 0 stevel */ 1454 0 stevel caller->t_disp_queue = cp->cpu_disp; 1455 0 stevel CL_ACTIVE(caller); 1456 0 stevel /* 1457 0 stevel * We are calling thread_onproc() instead of 1458 0 stevel * THREAD_ONPROC() because compiler can reorder 1459 0 stevel * the two stores of t_state and t_lockp in 1460 0 stevel * THREAD_ONPROC(). 1461 0 stevel */ 1462 0 stevel thread_onproc(caller, cp); 1463 0 stevel disp_lock_exit_high(tlp); 1464 0 stevel shuttle_resume(caller, &door_knob); 1465 0 stevel } else { 1466 0 stevel /* May have been setrun or in stop state */ 1467 0 stevel thread_unlock(caller); 1468 0 stevel shuttle_swtch(&door_knob); 1469 0 stevel } 1470 0 stevel } else { 1471 0 stevel shuttle_swtch(&door_knob); 1472 0 stevel } 1473 0 stevel 1474 0 stevel /* 1475 0 stevel * We've sprung to life. Determine if we are part of a door 1476 0 stevel * invocation, or just interrupted 1477 0 stevel */ 1478 0 stevel mutex_enter(&door_knob); 1479 0 stevel if ((dp = st->d_active) != NULL) { 1480 0 stevel /* 1481 0 stevel * Normal door invocation. Return any error condition 1482 0 stevel * encountered while trying to pass args to the server 1483 0 stevel * thread. 1484 0 stevel */ 1485 0 stevel lwp->lwp_asleep = 0; 1486 0 stevel /* 1487 0 stevel * Prevent the caller from leaving us while we 1488 0 stevel * are copying out the arguments from it's buffer. 1489 0 stevel */ 1490 0 stevel ASSERT(st->d_caller != NULL); 1491 0 stevel ct = DOOR_CLIENT(st->d_caller->t_door); 1492 0 stevel 1493 0 stevel DOOR_T_HOLD(ct); 1494 0 stevel mutex_exit(&door_knob); 1495 0 stevel error = door_server_dispatch(ct, dp); 1496 0 stevel mutex_enter(&door_knob); 1497 0 stevel DOOR_T_RELEASE(ct); 1498 6655 jwadams 1499 6655 jwadams /* let the client know we have processed his message */ 1500 6655 jwadams ct->d_args_done = 1; 1501 0 stevel 1502 0 stevel if (error) { 1503 0 stevel caller = st->d_caller; 1504 0 stevel if (caller) 1505 0 stevel ct = DOOR_CLIENT(caller->t_door); 1506 0 stevel else 1507 0 stevel ct = NULL; 1508 0 stevel goto out; 1509 0 stevel } 1510 0 stevel mutex_exit(&door_knob); 1511 0 stevel return (0); 1512 0 stevel } else { 1513 0 stevel /* 1514 0 stevel * We are not involved in a door_invocation. 1515 0 stevel * Check for /proc related activity... 1516 0 stevel */ 1517 0 stevel st->d_caller = NULL; 1518 5540 dm120769 door_server_exit(curproc, curthread); 1519 0 stevel mutex_exit(&door_knob); 1520 5891 raf cancel_pending = 0; 1521 5891 raf if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort || 1522 5891 raf MUSTRETURN(curproc, curthread) || 1523 5891 raf (cancel_pending = schedctl_cancel_pending()) != 0) { 1524 5891 raf if (cancel_pending) 1525 5891 raf schedctl_cancel_eintr(); 1526 0 stevel lwp->lwp_asleep = 0; 1527 0 stevel lwp->lwp_sysabort = 0; 1528 0 stevel return (set_errno(EINTR)); 1529 0 stevel } 1530 0 stevel /* Go back and wait for another request */ 1531 0 stevel lwp->lwp_asleep = 0; 1532 0 stevel mutex_enter(&door_knob); 1533 0 stevel caller = NULL; 1534 0 stevel goto out; 1535 0 stevel } 1536 0 stevel } 1537 0 stevel 1538 0 stevel /* 1539 0 stevel * Revoke any future invocations on this door 1540 0 stevel */ 1541 0 stevel int 1542 0 stevel door_revoke(int did) 1543 0 stevel { 1544 0 stevel door_node_t *d; 1545 0 stevel int error; 1546 0 stevel 1547 0 stevel if ((d = door_lookup(did, NULL)) == NULL) 1548 0 stevel return (set_errno(EBADF)); 1549 0 stevel 1550 0 stevel mutex_enter(&door_knob); 1551 0 stevel if (d->door_target != curproc) { 1552 0 stevel mutex_exit(&door_knob); 1553 0 stevel releasef(did); 1554 0 stevel return (set_errno(EPERM)); 1555 0 stevel } 1556 0 stevel d->door_flags |= DOOR_REVOKED; 1557 0 stevel if (d->door_flags & DOOR_PRIVATE) 1558 0 stevel cv_broadcast(&d->door_servers.dp_cv); 1559 0 stevel else 1560 0 stevel cv_broadcast(&curproc->p_server_threads.dp_cv); 1561 0 stevel mutex_exit(&door_knob); 1562 0 stevel releasef(did); 1563 0 stevel /* Invalidate the descriptor */ 1564 0 stevel if ((error = closeandsetf(did, NULL)) != 0) 1565 0 stevel return (set_errno(error)); 1566 0 stevel return (0); 1567 0 stevel } 1568 0 stevel 1569 0 stevel int 1570 0 stevel door_info(int did, struct door_info *d_info) 1571 0 stevel { 1572 0 stevel door_node_t *dp; 1573 0 stevel door_info_t di; 1574 0 stevel door_server_t *st; 1575 0 stevel file_t *fp = NULL; 1576 0 stevel 1577 0 stevel if (did == DOOR_QUERY) { 1578 0 stevel /* Get information on door current thread is bound to */ 1579 0 stevel if ((st = door_my_server(0)) == NULL || 1580 0 stevel (dp = st->d_pool) == NULL) 1581 0 stevel /* Thread isn't bound to a door */ 1582 0 stevel return (set_errno(EBADF)); 1583 0 stevel } else if ((dp = door_lookup(did, &fp)) == NULL) { 1584 0 stevel /* Not a door */ 1585 0 stevel return (set_errno(EBADF)); 1586 0 stevel } 1587 0 stevel 1588 0 stevel door_info_common(dp, &di, fp); 1589 0 stevel 1590 0 stevel if (did != DOOR_QUERY) 1591 0 stevel releasef(did); 1592 0 stevel 1593 0 stevel if (copyout(&di, d_info, sizeof (struct door_info))) 1594 0 stevel return (set_errno(EFAULT)); 1595 0 stevel return (0); 1596 0 stevel } 1597 0 stevel 1598 0 stevel /* 1599 0 stevel * Common code for getting information about a door either via the 1600 0 stevel * door_info system call or the door_ki_info kernel call. 1601 0 stevel */ 1602 0 stevel void 1603 0 stevel door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp) 1604 0 stevel { 1605 0 stevel int unref_count; 1606 0 stevel 1607 0 stevel bzero(dip, sizeof (door_info_t)); 1608 0 stevel 1609 0 stevel mutex_enter(&door_knob); 1610 0 stevel if (dp->door_target == NULL) 1611 0 stevel dip->di_target = -1; 1612 0 stevel else 1613 0 stevel dip->di_target = dp->door_target->p_pid; 1614 0 stevel 1615 0 stevel dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK; 1616 0 stevel if (dp->door_target == curproc) 1617 0 stevel dip->di_attributes |= DOOR_LOCAL; 1618 0 stevel dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc; 1619 0 stevel dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data; 1620 0 stevel dip->di_uniquifier = dp->door_index; 1621 0 stevel /* 1622 0 stevel * If this door is in the middle of having an unreferenced 1623 0 stevel * notification delivered, don't count the VN_HOLD by 1624 0 stevel * door_deliver_unref in determining if it is unreferenced. 1625 0 stevel * This handles the case where door_info is called from the 1626 0 stevel * thread delivering the unref notification. 1627 0 stevel */ 1628 0 stevel if (dp->door_flags & DOOR_UNREF_ACTIVE) 1629 0 stevel unref_count = 2; 1630 0 stevel else 1631 0 stevel unref_count = 1; 1632 0 stevel mutex_exit(&door_knob); 1633 0 stevel 1634 0 stevel if (fp == NULL) { 1635 0 stevel /* 1636 0 stevel * If this thread is bound to the door, then we can just 1637 0 stevel * check the vnode; a ref count of 1 (or 2 if this is 1638 0 stevel * handling an unref notification) means that the hold 1639 0 stevel * from the door_bind is the only reference to the door 1640 0 stevel * (no file descriptor refers to it). 1641 0 stevel */ 1642 0 stevel if (DTOV(dp)->v_count == unref_count) 1643 0 stevel dip->di_attributes |= DOOR_IS_UNREF; 1644 0 stevel } else { 1645 0 stevel /* 1646 0 stevel * If we're working from a file descriptor or door handle 1647 0 stevel * we need to look at the file structure count. We don't 1648 0 stevel * need to hold the vnode lock since this is just a snapshot. 1649 0 stevel */ 1650 0 stevel mutex_enter(&fp->f_tlock); 1651 0 stevel if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count) 1652 0 stevel dip->di_attributes |= DOOR_IS_UNREF; 1653 0 stevel mutex_exit(&fp->f_tlock); 1654 0 stevel } 1655 0 stevel } 1656 0 stevel 1657 0 stevel /* 1658 0 stevel * Return credentials of the door caller (if any) for this invocation 1659 0 stevel */ 1660 0 stevel int 1661 0 stevel door_ucred(struct ucred_s *uch) 1662 0 stevel { 1663 0 stevel kthread_t *caller; 1664 0 stevel door_server_t *st; 1665 0 stevel door_client_t *ct; 1666 6997 jwadams door_upcall_t *dup; 1667 0 stevel struct proc *p; 1668 0 stevel struct ucred_s *res; 1669 0 stevel int err; 1670 0 stevel 1671 0 stevel mutex_enter(&door_knob); 1672 0 stevel if ((st = door_my_server(0)) == NULL || 1673 0 stevel (caller = st->d_caller) == NULL) { 1674 0 stevel mutex_exit(&door_knob); 1675 0 stevel return (set_errno(EINVAL)); 1676 0 stevel } 1677 0 stevel 1678 0 stevel ASSERT(caller->t_door != NULL); 1679 0 stevel ct = DOOR_CLIENT(caller->t_door); 1680 0 stevel 1681 0 stevel /* Prevent caller from exiting while we examine the cred */ 1682 0 stevel DOOR_T_HOLD(ct); 1683 0 stevel mutex_exit(&door_knob); 1684 0 stevel 1685 0 stevel p = ttoproc(caller); 1686 0 stevel 1687 6263 seb /* 1688 6263 seb * If the credentials are not specified by the client, get the one 1689 6263 seb * associated with the calling process. 1690 6263 seb */ 1691 6997 jwadams if ((dup = ct->d_upcall) != NULL) 1692 6997 jwadams res = cred2ucred(dup->du_cred, p0.p_pid, NULL, CRED()); 1693 6997 jwadams else 1694 6997 jwadams res = cred2ucred(caller->t_cred, p->p_pid, NULL, CRED()); 1695 0 stevel 1696 0 stevel mutex_enter(&door_knob); 1697 0 stevel DOOR_T_RELEASE(ct); 1698 0 stevel mutex_exit(&door_knob); 1699 0 stevel 1700 0 stevel err = copyout(res, uch, res->uc_size); 1701 0 stevel 1702 0 stevel kmem_free(res, res->uc_size); 1703 0 stevel 1704 0 stevel if (err != 0) 1705 0 stevel return (set_errno(EFAULT)); 1706 0 stevel 1707 0 stevel return (0); 1708 0 stevel } 1709 0 stevel 1710 0 stevel /* 1711 0 stevel * Bind the current lwp to the server thread pool associated with 'did' 1712 0 stevel */ 1713 0 stevel int 1714 0 stevel door_bind(int did) 1715 0 stevel { 1716 0 stevel door_node_t *dp; 1717 0 stevel door_server_t *st; 1718 0 stevel 1719 0 stevel if ((dp = door_lookup(did, NULL)) == NULL) { 1720 0 stevel /* Not a door */ 1721 0 stevel return (set_errno(EBADF)); 1722 0 stevel } 1723 0 stevel 1724 0 stevel /* 1725 0 stevel * Can't bind to a non-private door, and can't bind to a door 1726 0 stevel * served by another process. 1727 0 stevel */ 1728 0 stevel if ((dp->door_flags & DOOR_PRIVATE) == 0 || 1729 0 stevel dp->door_target != curproc) { 1730 0 stevel releasef(did); 1731 0 stevel return (set_errno(EINVAL)); 1732 0 stevel } 1733 0 stevel 1734 0 stevel st = door_my_server(1); 1735 0 stevel if (st->d_pool) 1736 0 stevel door_unbind_thread(st->d_pool); 1737 0 stevel st->d_pool = dp; 1738 0 stevel st->d_invbound = 0; 1739 0 stevel door_bind_thread(dp); 1740 0 stevel releasef(did); 1741 0 stevel 1742 0 stevel return (0); 1743 0 stevel } 1744 0 stevel 1745 0 stevel /* 1746 0 stevel * Unbind the current lwp from it's server thread pool 1747 0 stevel */ 1748 0 stevel int 1749 0 stevel door_unbind(void) 1750 0 stevel { 1751 0 stevel door_server_t *st; 1752 0 stevel 1753 0 stevel if ((st = door_my_server(0)) == NULL) 1754 0 stevel return (set_errno(EBADF)); 1755 0 stevel 1756 0 stevel if (st->d_invbound) { 1757 0 stevel ASSERT(st->d_pool == NULL); 1758 0 stevel st->d_invbound = 0; 1759 0 stevel return (0); 1760 0 stevel } 1761 0 stevel if (st->d_pool == NULL) 1762 0 stevel return (set_errno(EBADF)); 1763 0 stevel door_unbind_thread(st->d_pool); 1764 0 stevel st->d_pool = NULL; 1765 0 stevel return (0); 1766 0 stevel } 1767 0 stevel 1768 0 stevel /* 1769 0 stevel * Create a descriptor for the associated file and fill in the 1770 0 stevel * attributes associated with it. 1771 0 stevel * 1772 0 stevel * Return 0 for success, -1 otherwise; 1773 0 stevel */ 1774 0 stevel int 1775 0 stevel door_insert(struct file *fp, door_desc_t *dp) 1776 0 stevel { 1777 0 stevel struct vnode *vp; 1778 0 stevel int fd; 1779 0 stevel door_attr_t attributes = DOOR_DESCRIPTOR; 1780 0 stevel 1781 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 1782 0 stevel if ((fd = ufalloc(0)) == -1) 1783 0 stevel return (-1); 1784 0 stevel setf(fd, fp); 1785 0 stevel dp->d_data.d_desc.d_descriptor = fd; 1786 0 stevel 1787 0 stevel /* Fill in the attributes */ 1788 5331 amw if (VOP_REALVP(fp->f_vnode, &vp, NULL)) 1789 0 stevel vp = fp->f_vnode; 1790 0 stevel if (vp && vp->v_type == VDOOR) { 1791 0 stevel if (VTOD(vp)->door_target == curproc) 1792 0 stevel attributes |= DOOR_LOCAL; 1793 0 stevel attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK; 1794 0 stevel dp->d_data.d_desc.d_id = VTOD(vp)->door_index; 1795 0 stevel } 1796 0 stevel dp->d_attributes = attributes; 1797 0 stevel return (0); 1798 0 stevel } 1799 0 stevel 1800 0 stevel /* 1801 0 stevel * Return an available thread for this server. A NULL return value indicates 1802 0 stevel * that either: 1803 0 stevel * The door has been revoked, or 1804 0 stevel * a signal was received. 1805 0 stevel * The two conditions can be differentiated using DOOR_INVALID(dp). 1806 0 stevel */ 1807 0 stevel static kthread_t * 1808 0 stevel door_get_server(door_node_t *dp) 1809 0 stevel { 1810 0 stevel kthread_t **ktp; 1811 0 stevel kthread_t *server_t; 1812 0 stevel door_pool_t *pool; 1813 0 stevel door_server_t *st; 1814 0 stevel int signalled; 1815 0 stevel 1816 0 stevel disp_lock_t *tlp; 1817 0 stevel cpu_t *cp; 1818 0 stevel 1819 0 stevel ASSERT(MUTEX_HELD(&door_knob)); 1820 0 stevel 1821 0 stevel if (dp->door_flags & DOOR_PRIVATE) 1822 0 stevel pool = &dp->door_servers; 1823 0 stevel else 1824 0 stevel pool = &dp->door_target->p_server_threads; 1825 0 stevel 1826 0 stevel for (;;) { 1827 0 stevel /* 1828 0 stevel * We search the thread pool, looking for a server thread 1829 0 stevel * ready to take an invocation (i.e. one which is still 1830 0 stevel * sleeping on a shuttle object). If none are available, 1831 0 stevel * we sleep on the pool's CV, and will be signaled when a 1832 0 stevel * thread is added to the pool. 1833 0 stevel * 1834 0 stevel * This relies on the fact that once a thread in the thread 1835 0 stevel * pool wakes up, it *must* remove and add itself to the pool 1836 0 stevel * before it can receive door calls. 1837 0 stevel */ 1838 0 stevel if (DOOR_INVALID(dp)) 1839 0 stevel return (NULL); /* Target has become invalid */ 1840 0 stevel 1841 0 stevel for (ktp = &pool->dp_threads; 1842 0 stevel (server_t = *ktp) != NULL; 1843 0 stevel ktp = &st->d_servers) { 1844 0 stevel st = DOOR_SERVER(server_t->t_door); 1845 0 stevel 1846 0 stevel thread_lock(server_t); 1847 0 stevel if (server_t->t_state == TS_SLEEP && 1848 0 stevel SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE) 1849 0 stevel break; 1850 0 stevel thread_unlock(server_t); 1851 0 stevel } 1852 0 stevel if (server_t != NULL) 1853 0 stevel break; /* we've got a live one! */ 1854 0 stevel 1855 0 stevel if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob, 1856 0 stevel &signalled)) { 1857 0 stevel /* 1858 5331 amw * If we were signaled and the door is still 1859 0 stevel * valid, pass the signal on to another waiter. 1860 0 stevel */ 1861 0 stevel if (signalled && !DOOR_INVALID(dp)) 1862 0 stevel cv_signal(&pool->dp_cv); 1863 0 stevel return (NULL); /* Got a signal */ 1864 0 stevel } 1865 0 stevel } 1866 0 stevel 1867 0 stevel /* 1868 0 stevel * We've got a thread_lock()ed thread which is still on the 1869 0 stevel * shuttle. Take it off the list of available server threads 1870 0 stevel * and mark it as ONPROC. We are committed to resuming this 1871 0 stevel * thread now. 1872 0 stevel */ 1873 0 stevel tlp = server_t->t_lockp; 1874 0 stevel cp = CPU; 1875 0 stevel 1876 0 stevel *ktp = st->d_servers; 1877 0 stevel st->d_servers = NULL; 1878 0 stevel /* 1879 0 stevel * Setting t_disp_queue prevents erroneous preemptions 1880 0 stevel * if this thread is still in execution on another processor 1881 0 stevel */ 1882 0 stevel server_t->t_disp_queue = cp->cpu_disp; 1883 0 stevel CL_ACTIVE(server_t); 1884 0 stevel /* 1885 0 stevel * We are calling thread_onproc() instead of 1886 0 stevel * THREAD_ONPROC() because compiler can reorder 1887 0 stevel * the two stores of t_state and t_lockp in 1888 0 stevel * THREAD_ONPROC(). 1889 0 stevel */ 1890 0 stevel thread_onproc(server_t, cp); 1891 0 stevel disp_lock_exit(tlp); 1892 0 stevel return (server_t); 1893 0 stevel } 1894 0 stevel 1895 0 stevel /* 1896 0 stevel * Put a server thread back in the pool. 1897 0 stevel */ 1898 0 stevel static void 1899 0 stevel door_release_server(door_node_t *dp, kthread_t *t) 1900 0 stevel { 1901 0 stevel door_server_t *st = DOOR_SERVER(t->t_door); 1902 0 stevel door_pool_t *pool; 1903 0 stevel 1904 0 stevel ASSERT(MUTEX_HELD(&door_knob)); 1905 0 stevel st->d_active = NULL; 1906 0 stevel st->d_caller = NULL; 1907 0 stevel st->d_layout_done = 0; 1908 0 stevel if (dp && (dp->door_flags & DOOR_PRIVATE)) { 1909 0 stevel ASSERT(dp->door_target == NULL || 1910 0 stevel dp->door_target == ttoproc(t)); 1911 0 stevel pool = &dp->door_servers; 1912 0 stevel } else { 1913 0 stevel pool = &ttoproc(t)->p_server_threads; 1914 0 stevel } 1915 0 stevel 1916 0 stevel st->d_servers = pool->dp_threads; 1917 0 stevel pool->dp_threads = t; 1918 0 stevel 1919 0 stevel /* If someone is waiting for a server thread, wake him up */ 1920 0 stevel cv_signal(&pool->dp_cv); 1921 0 stevel } 1922 0 stevel 1923 0 stevel /* 1924 0 stevel * Remove a server thread from the pool if present. 1925 0 stevel */ 1926 5540 dm120769 static void 1927 0 stevel door_server_exit(proc_t *p, kthread_t *t) 1928 0 stevel { 1929 0 stevel door_pool_t *pool; 1930 0 stevel kthread_t **next; 1931 0 stevel door_server_t *st = DOOR_SERVER(t->t_door); 1932 0 stevel 1933 0 stevel ASSERT(MUTEX_HELD(&door_knob)); 1934 0 stevel if (st->d_pool != NULL) { 1935 0 stevel ASSERT(st->d_pool->door_flags & DOOR_PRIVATE); 1936 0 stevel pool = &st->d_pool->door_servers; 1937 0 stevel } else { 1938 0 stevel pool = &p->p_server_threads; 1939 0 stevel } 1940 0 stevel 1941 0 stevel next = &pool->dp_threads; 1942 0 stevel while (*next != NULL) { 1943 0 stevel if (*next == t) { 1944 0 stevel *next = DOOR_SERVER(t->t_door)->d_servers; 1945 5540 dm120769 return; 1946 0 stevel } 1947 0 stevel next = &(DOOR_SERVER((*next)->t_door)->d_servers); 1948 0 stevel } 1949 0 stevel } 1950 0 stevel 1951 0 stevel /* 1952 0 stevel * Lookup the door descriptor. Caller must call releasef when finished 1953 0 stevel * with associated door. 1954 0 stevel */ 1955 0 stevel static door_node_t * 1956 0 stevel door_lookup(int did, file_t **fpp) 1957 0 stevel { 1958 0 stevel vnode_t *vp; 1959 0 stevel file_t *fp; 1960 0 stevel 1961 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 1962 0 stevel if ((fp = getf(did)) == NULL) 1963 0 stevel return (NULL); 1964 0 stevel /* 1965 0 stevel * Use the underlying vnode (we may be namefs mounted) 1966 0 stevel */ 1967 5331 amw if (VOP_REALVP(fp->f_vnode, &vp, NULL)) 1968 0 stevel vp = fp->f_vnode; 1969 0 stevel 1970 0 stevel if (vp == NULL || vp->v_type != VDOOR) { 1971 0 stevel releasef(did); 1972 0 stevel return (NULL); 1973 0 stevel } 1974 0 stevel 1975 0 stevel if (fpp) 1976 0 stevel *fpp = fp; 1977 0 stevel 1978 0 stevel return (VTOD(vp)); 1979 0 stevel } 1980 0 stevel 1981 0 stevel /* 1982 0 stevel * The current thread is exiting, so clean up any pending 1983 0 stevel * invocation details 1984 0 stevel */ 1985 0 stevel void 1986 0 stevel door_slam(void) 1987 0 stevel { 1988 0 stevel door_node_t *dp; 1989 0 stevel door_data_t *dt; 1990 0 stevel door_client_t *ct; 1991 0 stevel door_server_t *st; 1992 0 stevel 1993 0 stevel /* 1994 0 stevel * If we are an active door server, notify our 1995 0 stevel * client that we are exiting and revoke our door. 1996 0 stevel */ 1997 0 stevel if ((dt = door_my_data(0)) == NULL) 1998 0 stevel return; 1999 0 stevel ct = DOOR_CLIENT(dt); 2000 0 stevel st = DOOR_SERVER(dt); 2001 0 stevel 2002 0 stevel mutex_enter(&door_knob); 2003 0 stevel for (;;) { 2004 0 stevel if (DOOR_T_HELD(ct)) 2005 0 stevel cv_wait(&ct->d_cv, &door_knob); 2006 0 stevel else if (DOOR_T_HELD(st)) 2007 0 stevel cv_wait(&st->d_cv, &door_knob); 2008 0 stevel else 2009 0 stevel break; /* neither flag is set */ 2010 0 stevel } 2011 0 stevel curthread->t_door = NULL; 2012 0 stevel if ((dp = st->d_active) != NULL) { 2013 0 stevel kthread_t *t = st->d_caller; 2014 0 stevel proc_t *p = curproc; 2015 0 stevel 2016 0 stevel /* Revoke our door if the process is exiting */ 2017 390 raf if (dp->door_target == p && (p->p_flag & SEXITING)) { 2018 0 stevel door_list_delete(dp); 2019 0 stevel dp->door_target = NULL; 2020 0 stevel dp->door_flags |= DOOR_REVOKED; 2021 0 stevel if (dp->door_flags & DOOR_PRIVATE) 2022 0 stevel cv_broadcast(&dp->door_servers.dp_cv); 2023 0 stevel else 2024 0 stevel cv_broadcast(&p->p_server_threads.dp_cv); 2025 0 stevel } 2026 0 stevel 2027 0 stevel if (t != NULL) { 2028 0 stevel /* 2029 0 stevel * Let the caller know we are gone 2030 0 stevel */ 2031 0 stevel DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT; 2032 0 stevel thread_lock(t); 2033 0 stevel if (t->t_state == TS_SLEEP && 2034 0 stevel SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE) 2035 0 stevel setrun_locked(t); 2036 0 stevel thread_unlock(t); 2037 0 stevel } 2038 0 stevel } 2039 0 stevel mutex_exit(&door_knob); 2040 0 stevel if (st->d_pool) 2041 0 stevel door_unbind_thread(st->d_pool); /* Implicit door_unbind */ 2042 0 stevel kmem_free(dt, sizeof (door_data_t)); 2043 0 stevel } 2044 0 stevel 2045 0 stevel /* 2046 0 stevel * Set DOOR_REVOKED for all doors of the current process. This is called 2047 0 stevel * on exit before all lwp's are being terminated so that door calls will 2048 0 stevel * return with an error. 2049 0 stevel */ 2050 0 stevel void 2051 0 stevel door_revoke_all() 2052 0 stevel { 2053 0 stevel door_node_t *dp; 2054 0 stevel proc_t *p = ttoproc(curthread); 2055 0 stevel 2056 0 stevel mutex_enter(&door_knob); 2057 0 stevel for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) { 2058 0 stevel ASSERT(dp->door_target == p); 2059 0 stevel dp->door_flags |= DOOR_REVOKED; 2060 0 stevel if (dp->door_flags & DOOR_PRIVATE) 2061 0 stevel cv_broadcast(&dp->door_servers.dp_cv); 2062 0 stevel } 2063 0 stevel cv_broadcast(&p->p_server_threads.dp_cv); 2064 0 stevel mutex_exit(&door_knob); 2065 0 stevel } 2066 0 stevel 2067 0 stevel /* 2068 0 stevel * The process is exiting, and all doors it created need to be revoked. 2069 0 stevel */ 2070 0 stevel void 2071 0 stevel door_exit(void) 2072 0 stevel { 2073 0 stevel door_node_t *dp; 2074 0 stevel proc_t *p = ttoproc(curthread); 2075 0 stevel 2076 0 stevel ASSERT(p->p_lwpcnt == 1); 2077 0 stevel /* 2078 0 stevel * Walk the list of active doors created by this process and 2079 0 stevel * revoke them all. 2080 0 stevel */ 2081 0 stevel mutex_enter(&door_knob); 2082 0 stevel for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) { 2083 0 stevel dp->door_target = NULL; 2084 0 stevel dp->door_flags |= DOOR_REVOKED; 2085 0 stevel if (dp->door_flags & DOOR_PRIVATE) 2086 0 stevel cv_broadcast(&dp->door_servers.dp_cv); 2087 0 stevel } 2088 0 stevel cv_broadcast(&p->p_server_threads.dp_cv); 2089 0 stevel /* Clear the list */ 2090 0 stevel p->p_door_list = NULL; 2091 0 stevel 2092 0 stevel /* Clean up the unref list */ 2093 0 stevel while ((dp = p->p_unref_list) != NULL) { 2094 0 stevel p->p_unref_list = dp->door_ulist; 2095 0 stevel dp->door_ulist = NULL; 2096 0 stevel mutex_exit(&door_knob); 2097 0 stevel VN_RELE(DTOV(dp)); 2098 0 stevel mutex_enter(&door_knob); 2099 0 stevel } 2100 0 stevel mutex_exit(&door_knob); 2101 0 stevel } 2102 0 stevel 2103 0 stevel 2104 0 stevel /* 2105 0 stevel * The process is executing forkall(), and we need to flag threads that 2106 0 stevel * are bound to a door in the child. This will make the child threads 2107 0 stevel * return an error to door_return unless they call door_unbind first. 2108 0 stevel */ 2109 0 stevel void 2110 0 stevel door_fork(kthread_t *parent, kthread_t *child) 2111 0 stevel { 2112 0 stevel door_data_t *pt = parent->t_door; 2113 0 stevel door_server_t *st = DOOR_SERVER(pt); 2114 0 stevel door_data_t *dt; 2115 0 stevel 2116 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2117 0 stevel if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) { 2118 0 stevel /* parent thread is bound to a door */ 2119 0 stevel dt = child->t_door = 2120 0 stevel kmem_zalloc(sizeof (door_data_t), KM_SLEEP); 2121 0 stevel DOOR_SERVER(dt)->d_invbound = 1; 2122 0 stevel } 2123 0 stevel } 2124 0 stevel 2125 0 stevel /* 2126 0 stevel * Deliver queued unrefs to appropriate door server. 2127 0 stevel */ 2128 0 stevel static int 2129 0 stevel door_unref(void) 2130 0 stevel { 2131 0 stevel door_node_t *dp; 2132 0 stevel static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 }; 2133 0 stevel proc_t *p = ttoproc(curthread); 2134 0 stevel 2135 0 stevel /* make sure there's only one unref thread per process */ 2136 0 stevel mutex_enter(&door_knob); 2137 0 stevel if (p->p_unref_thread) { 2138 0 stevel mutex_exit(&door_knob); 2139 0 stevel return (set_errno(EALREADY)); 2140 0 stevel } 2141 0 stevel p->p_unref_thread = 1; 2142 0 stevel mutex_exit(&door_knob); 2143 0 stevel 2144 0 stevel (void) door_my_data(1); /* create info, if necessary */ 2145 0 stevel 2146 0 stevel for (;;) { 2147 0 stevel mutex_enter(&door_knob); 2148 0 stevel 2149 0 stevel /* Grab a queued request */ 2150 0 stevel while ((dp = p->p_unref_list) == NULL) { 2151 0 stevel if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) { 2152 0 stevel /* 2153 0 stevel * Interrupted. 2154 0 stevel * Return so we can finish forkall() or exit(). 2155 0 stevel */ 2156 0 stevel p->p_unref_thread = 0; 2157 0 stevel mutex_exit(&door_knob); 2158 0 stevel return (set_errno(EINTR)); 2159 0 stevel } 2160 0 stevel } 2161 0 stevel p->p_unref_list = dp->door_ulist; 2162 0 stevel dp->door_ulist = NULL; 2163 0 stevel dp->door_flags |= DOOR_UNREF_ACTIVE; 2164 0 stevel mutex_exit(&door_knob); 2165 0 stevel 2166 6997 jwadams (void) door_upcall(DTOV(dp), &unref_args, NULL, SIZE_MAX, 0); 2167 6997 jwadams 2168 6997 jwadams if (unref_args.rbuf != 0) { 2169 6997 jwadams kmem_free(unref_args.rbuf, unref_args.rsize); 2170 6997 jwadams unref_args.rbuf = NULL; 2171 6997 jwadams unref_args.rsize = 0; 2172 6997 jwadams } 2173 0 stevel 2174 0 stevel mutex_enter(&door_knob); 2175 0 stevel ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE); 2176 0 stevel dp->door_flags &= ~DOOR_UNREF_ACTIVE; 2177 0 stevel mutex_exit(&door_knob); 2178 0 stevel VN_RELE(DTOV(dp)); 2179 0 stevel } 2180 0 stevel } 2181 0 stevel 2182 0 stevel 2183 0 stevel /* 2184 0 stevel * Deliver queued unrefs to kernel door server. 2185 0 stevel */ 2186 0 stevel /* ARGSUSED */ 2187 0 stevel static void 2188 0 stevel door_unref_kernel(caddr_t arg) 2189 0 stevel { 2190 0 stevel door_node_t *dp; 2191 0 stevel static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 }; 2192 0 stevel proc_t *p = ttoproc(curthread); 2193 0 stevel callb_cpr_t cprinfo; 2194 0 stevel 2195 0 stevel /* should only be one of these */ 2196 0 stevel mutex_enter(&door_knob); 2197 0 stevel if (p->p_unref_thread) { 2198 0 stevel mutex_exit(&door_knob); 2199 0 stevel return; 2200 0 stevel } 2201 0 stevel p->p_unref_thread = 1; 2202 0 stevel mutex_exit(&door_knob); 2203 0 stevel 2204 0 stevel (void) door_my_data(1); /* make sure we have a door_data_t */ 2205 0 stevel 2206 0 stevel CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref"); 2207 0 stevel for (;;) { 2208 0 stevel mutex_enter(&door_knob); 2209 0 stevel /* Grab a queued request */ 2210 0 stevel while ((dp = p->p_unref_list) == NULL) { 2211 0 stevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 2212 0 stevel cv_wait(&p->p_unref_cv, &door_knob); 2213 0 stevel CALLB_CPR_SAFE_END(&cprinfo, &door_knob); 2214 0 stevel } 2215 0 stevel p->p_unref_list = dp->door_ulist; 2216 0 stevel dp->door_ulist = NULL; 2217 0 stevel dp->door_flags |= DOOR_UNREF_ACTIVE; 2218 0 stevel mutex_exit(&door_knob); 2219 0 stevel 2220 0 stevel (*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL); 2221 0 stevel 2222 0 stevel mutex_enter(&door_knob); 2223 0 stevel ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE); 2224 0 stevel dp->door_flags &= ~DOOR_UNREF_ACTIVE; 2225 0 stevel mutex_exit(&door_knob); 2226 0 stevel VN_RELE(DTOV(dp)); 2227 0 stevel } 2228 0 stevel } 2229 0 stevel 2230 0 stevel 2231 0 stevel /* 2232 0 stevel * Queue an unref invocation for processing for the current process 2233 0 stevel * The door may or may not be revoked at this point. 2234 0 stevel */ 2235 0 stevel void 2236 0 stevel door_deliver_unref(door_node_t *d) 2237 0 stevel { 2238 0 stevel struct proc *server = d->door_target; 2239 0 stevel 2240 0 stevel ASSERT(MUTEX_HELD(&door_knob)); 2241 0 stevel ASSERT(d->door_active == 0); 2242 0 stevel 2243 0 stevel if (server == NULL) 2244 0 stevel return; 2245 0 stevel /* 2246 0 stevel * Create a lwp to deliver unref calls if one isn't already running. 2247 0 stevel * 2248 0 stevel * A separate thread is used to deliver unrefs since the current 2249 0 stevel * thread may be holding resources (e.g. locks) in user land that 2250 0 stevel * may be needed by the unref processing. This would cause a 2251 0 stevel * deadlock. 2252 0 stevel */ 2253 0 stevel if (d->door_flags & DOOR_UNREF_MULTI) { 2254 0 stevel /* multiple unrefs */ 2255 0 stevel d->door_flags &= ~DOOR_DELAY; 2256 0 stevel } else { 2257 0 stevel /* Only 1 unref per door */ 2258 0 stevel d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY); 2259 0 stevel } 2260 0 stevel mutex_exit(&door_knob); 2261 0 stevel 2262 0 stevel /* 2263 0 stevel * Need to bump the vnode count before putting the door on the 2264 0 stevel * list so it doesn't get prematurely released by door_unref. 2265 0 stevel */ 2266 0 stevel VN_HOLD(DTOV(d)); 2267 0 stevel 2268 0 stevel mutex_enter(&door_knob); 2269 0 stevel /* is this door already on the unref list? */ 2270 0 stevel if (d->door_flags & DOOR_UNREF_MULTI) { 2271 0 stevel door_node_t *dp; 2272 0 stevel for (dp = server->p_unref_list; dp != NULL; 2273 0 stevel dp = dp->door_ulist) { 2274 0 stevel if (d == dp) { 2275 0 stevel /* already there, don't need to add another */ 2276 0 stevel mutex_exit(&door_knob); 2277 0 stevel VN_RELE(DTOV(d)); 2278 0 stevel mutex_enter(&door_knob); 2279 0 stevel return; 2280 0 stevel } 2281 0 stevel } 2282 0 stevel } 2283 0 stevel ASSERT(d->door_ulist == NULL); 2284 0 stevel d->door_ulist = server->p_unref_list; 2285 0 stevel server->p_unref_list = d; 2286 0 stevel cv_broadcast(&server->p_unref_cv); 2287 0 stevel } 2288 0 stevel 2289 0 stevel /* 2290 0 stevel * The callers buffer isn't big enough for all of the data/fd's. Allocate 2291 0 stevel * space in the callers address space for the results and copy the data 2292 0 stevel * there. 2293 0 stevel * 2294 0 stevel * For EOVERFLOW, we must clean up the server's door descriptors. 2295 0 stevel */ 2296 0 stevel static int 2297 0 stevel door_overflow( 2298 0 stevel kthread_t *caller, 2299 0 stevel caddr_t data_ptr, /* data location */ 2300 0 stevel size_t data_size, /* data size */ 2301 0 stevel door_desc_t *desc_ptr, /* descriptor location */ 2302 0 stevel uint_t desc_num) /* descriptor size */ 2303 0 stevel { 2304 0 stevel proc_t *callerp = ttoproc(caller); 2305 0 stevel struct as *as = callerp->p_as; 2306 0 stevel door_client_t *ct = DOOR_CLIENT(caller->t_door); 2307 0 stevel caddr_t addr; /* Resulting address in target */ 2308 0 stevel size_t rlen; /* Rounded len */ 2309 0 stevel size_t len; 2310 0 stevel uint_t i; 2311 0 stevel size_t ds = desc_num * sizeof (door_desc_t); 2312 0 stevel 2313 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2314 0 stevel ASSERT(DOOR_T_HELD(ct) || ct->d_kernel); 2315 0 stevel 2316 0 stevel /* Do initial overflow check */ 2317 0 stevel if (!ufcanalloc(callerp, desc_num)) 2318 0 stevel return (EMFILE); 2319 0 stevel 2320 0 stevel /* 2321 0 stevel * Allocate space for this stuff in the callers address space 2322 0 stevel */ 2323 0 stevel rlen = roundup(data_size + ds, PAGESIZE); 2324 0 stevel as_rangelock(as); 2325 0 stevel map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0); 2326 0 stevel if (addr == NULL || 2327 0 stevel as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) { 2328 0 stevel /* No virtual memory available, or anon mapping failed */ 2329 0 stevel as_rangeunlock(as); 2330 0 stevel if (!ct->d_kernel && desc_num > 0) { 2331 0 stevel int error = door_release_fds(desc_ptr, desc_num); 2332 0 stevel if (error) 2333 0 stevel return (error); 2334 0 stevel } 2335 0 stevel return (EOVERFLOW); 2336 0 stevel } 2337 0 stevel as_rangeunlock(as); 2338 0 stevel 2339 0 stevel if (ct->d_kernel) 2340 0 stevel goto out; 2341 0 stevel 2342 0 stevel if (data_size != 0) { 2343 0 stevel caddr_t src = data_ptr; 2344 0 stevel caddr_t saddr = addr; 2345 0 stevel 2346 0 stevel /* Copy any data */ 2347 0 stevel len = data_size; 2348 0 stevel while (len != 0) { 2349 0 stevel int amount; 2350 0 stevel int error; 2351 0 stevel 2352 0 stevel amount = len > PAGESIZE ? PAGESIZE : len; 2353 0 stevel if ((error = door_copy(as, src, saddr, amount)) != 0) { 2354 0 stevel (void) as_unmap(as, addr, rlen); 2355 0 stevel return (error); 2356 0 stevel } 2357 0 stevel saddr += amount; 2358 0 stevel src += amount; 2359 0 stevel len -= amount; 2360 0 stevel } 2361 0 stevel } 2362 0 stevel /* Copy any fd's */ 2363 0 stevel if (desc_num != 0) { 2364 0 stevel door_desc_t *didpp, *start; 2365 0 stevel struct file **fpp; 2366 0 stevel int fpp_size; 2367 0 stevel 2368 0 stevel start = didpp = kmem_alloc(ds, KM_SLEEP); 2369 6655 jwadams if (copyin_nowatch(desc_ptr, didpp, ds)) { 2370 0 stevel kmem_free(start, ds); 2371 0 stevel (void) as_unmap(as, addr, rlen); 2372 0 stevel return (EFAULT); 2373 0 stevel } 2374 0 stevel 2375 0 stevel fpp_size = desc_num * sizeof (struct file *); 2376 0 stevel if (fpp_size > ct->d_fpp_size) { 2377 0 stevel /* make more space */ 2378 0 stevel if (ct->d_fpp_size) 2379 0 stevel kmem_free(ct->d_fpp, ct->d_fpp_size); 2380 0 stevel ct->d_fpp_size = fpp_size; 2381 0 stevel ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP); 2382 0 stevel } 2383 0 stevel fpp = ct->d_fpp; 2384 0 stevel 2385 0 stevel for (i = 0; i < desc_num; i++) { 2386 0 stevel struct file *fp; 2387 0 stevel int fd = didpp->d_data.d_desc.d_descriptor; 2388 0 stevel 2389 0 stevel if (!(didpp->d_attributes & DOOR_DESCRIPTOR) || 2390 0 stevel (fp = getf(fd)) == NULL) { 2391 0 stevel /* close translated references */ 2392 0 stevel door_fp_close(ct->d_fpp, fpp - ct->d_fpp); 2393 0 stevel /* close untranslated references */ 2394 0 stevel door_fd_rele(didpp, desc_num - i, 0); 2395 0 stevel kmem_free(start, ds); 2396 0 stevel (void) as_unmap(as, addr, rlen); 2397 0 stevel return (EINVAL); 2398 0 stevel } 2399 0 stevel mutex_enter(&fp->f_tlock); 2400 0 stevel fp->f_count++; 2401 0 stevel mutex_exit(&fp->f_tlock); 2402 0 stevel 2403 0 stevel *fpp = fp; 2404 0 stevel releasef(fd); 2405 0 stevel 2406 0 stevel if (didpp->d_attributes & DOOR_RELEASE) { 2407 0 stevel /* release passed reference */ 2408 0 stevel (void) closeandsetf(fd, NULL); 2409 0 stevel } 2410 0 stevel 2411 0 stevel fpp++; didpp++; 2412 0 stevel } 2413 0 stevel kmem_free(start, ds); 2414 0 stevel } 2415 0 stevel 2416 0 stevel out: 2417 0 stevel ct->d_overflow = 1; 2418 0 stevel ct->d_args.rbuf = addr; 2419 0 stevel ct->d_args.rsize = rlen; 2420 0 stevel return (0); 2421 0 stevel } 2422 0 stevel 2423 0 stevel /* 2424 0 stevel * Transfer arguments from the client to the server. 2425 0 stevel */ 2426 0 stevel static int 2427 0 stevel door_args(kthread_t *server, int is_private) 2428 0 stevel { 2429 0 stevel door_server_t *st = DOOR_SERVER(server->t_door); 2430 0 stevel door_client_t *ct = DOOR_CLIENT(curthread->t_door); 2431 0 stevel uint_t ndid; 2432 0 stevel size_t dsize; 2433 0 stevel int error; 2434 0 stevel 2435 0 stevel ASSERT(DOOR_T_HELD(st)); 2436 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2437 0 stevel 2438 0 stevel ndid = ct->d_args.desc_num; 2439 0 stevel if (ndid > door_max_desc) 2440 0 stevel return (E2BIG); 2441 0 stevel 2442 0 stevel /* 2443 0 stevel * Get the stack layout, and fail now if it won't fit. 2444 0 stevel */ 2445 0 stevel error = door_layout(server, ct->d_args.data_size, ndid, is_private); 2446 0 stevel if (error != 0) 2447 0 stevel return (error); 2448 0 stevel 2449 0 stevel dsize = ndid * sizeof (door_desc_t); 2450 0 stevel if (ct->d_args.data_size != 0) { 2451 0 stevel if (ct->d_args.data_size <= door_max_arg) { 2452 0 stevel /* 2453 0 stevel * Use a 2 copy method for small amounts of data 2454 0 stevel * 2455 0 stevel * Allocate a little more than we need for the 2456 0 stevel * args, in the hope that the results will fit 2457 0 stevel * without having to reallocate a buffer 2458 0 stevel */ 2459 0 stevel ASSERT(ct->d_buf == NULL); 2460 0 stevel ct->d_bufsize = roundup(ct->d_args.data_size, 2461 0 stevel DOOR_ROUND); 2462 0 stevel ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP); 2463 6655 jwadams if (copyin_nowatch(ct->d_args.data_ptr, 2464 0 stevel ct->d_buf, ct->d_args.data_size) != 0) { 2465 0 stevel kmem_free(ct->d_buf, ct->d_bufsize); 2466 0 stevel ct->d_buf = NULL; 2467 0 stevel ct->d_bufsize = 0; 2468 0 stevel return (EFAULT); 2469 0 stevel } 2470 0 stevel } else { 2471 0 stevel struct as *as; 2472 0 stevel caddr_t src; 2473 0 stevel caddr_t dest; 2474 0 stevel size_t len = ct->d_args.data_size; 2475 0 stevel uintptr_t base; 2476 0 stevel 2477 0 stevel /* 2478 0 stevel * Use a 1 copy method 2479 0 stevel */ 2480 0 stevel as = ttoproc(server)->p_as; 2481 0 stevel src = ct->d_args.data_ptr; 2482 0 stevel 2483 0 stevel dest = st->d_layout.dl_datap; 2484 0 stevel base = (uintptr_t)dest; 2485 0 stevel 2486 0 stevel /* 2487 0 stevel * Copy data directly into server. We proceed 2488 0 stevel * downward from the top of the stack, to mimic 2489 0 stevel * normal stack usage. This allows the guard page 2490 0 stevel * to stop us before we corrupt anything. 2491 0 stevel */ 2492 0 stevel while (len != 0) { 2493 0 stevel uintptr_t start; 2494 0 stevel uintptr_t end; 2495 0 stevel uintptr_t offset; 2496 0 stevel size_t amount; 2497 0 stevel 2498 0 stevel /* 2499 0 stevel * Locate the next part to copy. 2500 0 stevel */ 2501 0 stevel end = base + len; 2502 0 stevel start = P2ALIGN(end - 1, PAGESIZE); 2503 0 stevel 2504 0 stevel /* 2505 0 stevel * if we are on the final (first) page, fix 2506 0 stevel * up the start position. 2507 0 stevel */ 2508 0 stevel if (P2ALIGN(base, PAGESIZE) == start) 2509 0 stevel start = base; 2510 0 stevel 2511 0 stevel offset = start - base; /* the copy offset */ 2512 0 stevel amount = end - start; /* # bytes to copy */ 2513 0 stevel 2514 0 stevel ASSERT(amount > 0 && amount <= len && 2515 0 stevel amount <= PAGESIZE); 2516 0 stevel 2517 0 stevel error = door_copy(as, src + offset, 2518 0 stevel dest + offset, amount); 2519 0 stevel if (error != 0) 2520 0 stevel return (error); 2521 0 stevel len -= amount; 2522 0 stevel } 2523 0 stevel } 2524 0 stevel } 2525 0 stevel /* 2526 0 stevel * Copyin the door args and translate them into files 2527 0 stevel */ 2528 0 stevel if (ndid != 0) { 2529 0 stevel door_desc_t *didpp; 2530 0 stevel door_desc_t *start; 2531 0 stevel struct file **fpp; 2532 0 stevel 2533 0 stevel start = didpp = kmem_alloc(dsize, KM_SLEEP); 2534 0 stevel 2535 6655 jwadams if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) { 2536 0 stevel kmem_free(start, dsize); 2537 0 stevel return (EFAULT); 2538 0 stevel } 2539 0 stevel ct->d_fpp_size = ndid * sizeof (struct file *); 2540 0 stevel ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP); 2541 0 stevel fpp = ct->d_fpp; 2542 0 stevel while (ndid--) { 2543 0 stevel struct file *fp; 2544 0 stevel int fd = didpp->d_data.d_desc.d_descriptor; 2545 0 stevel 2546 0 stevel /* We only understand file descriptors as passed objs */ 2547 0 stevel if (!(didpp->d_attributes & DOOR_DESCRIPTOR) || 2548 0 stevel (fp = getf(fd)) == NULL) { 2549 0 stevel /* close translated references */ 2550 0 stevel door_fp_close(ct->d_fpp, fpp - ct->d_fpp); 2551 0 stevel /* close untranslated references */ 2552 0 stevel door_fd_rele(didpp, ndid + 1, 0); 2553 0 stevel kmem_free(start, dsize); 2554 0 stevel kmem_free(ct->d_fpp, ct->d_fpp_size); 2555 0 stevel ct->d_fpp = NULL; 2556 0 stevel ct->d_fpp_size = 0; 2557 0 stevel return (EINVAL); 2558 0 stevel } 2559 0 stevel /* Hold the fp */ 2560 0 stevel mutex_enter(&fp->f_tlock); 2561 0 stevel fp->f_count++; 2562 0 stevel mutex_exit(&fp->f_tlock); 2563 0 stevel 2564 0 stevel *fpp = fp; 2565 0 stevel releasef(fd); 2566 0 stevel 2567 0 stevel if (didpp->d_attributes & DOOR_RELEASE) { 2568 0 stevel /* release passed reference */ 2569 0 stevel (void) closeandsetf(fd, NULL); 2570 0 stevel } 2571 0 stevel 2572 0 stevel fpp++; didpp++; 2573 0 stevel } 2574 0 stevel kmem_free(start, dsize); 2575 0 stevel } 2576 0 stevel return (0); 2577 0 stevel } 2578 0 stevel 2579 0 stevel /* 2580 0 stevel * Transfer arguments from a user client to a kernel server. This copies in 2581 0 stevel * descriptors and translates them into door handles. It doesn't touch the 2582 0 stevel * other data, letting the kernel server deal with that (to avoid needing 2583 0 stevel * to copy the data twice). 2584 0 stevel */ 2585 0 stevel static int 2586 0 stevel door_translate_in(void) 2587 0 stevel { 2588 0 stevel door_client_t *ct = DOOR_CLIENT(curthread->t_door); 2589 0 stevel uint_t ndid; 2590 0 stevel 2591 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2592 0 stevel ndid = ct->d_args.desc_num; 2593 0 stevel if (ndid > door_max_desc) 2594 0 stevel return (E2BIG); 2595 0 stevel /* 2596 0 stevel * Copyin the door args and translate them into door handles. 2597 0 stevel */ 2598 0 stevel if (ndid != 0) { 2599 0 stevel door_desc_t *didpp; 2600 0 stevel door_desc_t *start; 2601 0 stevel size_t dsize = ndid * sizeof (door_desc_t); 2602 0 stevel struct file *fp; 2603 0 stevel 2604 0 stevel start = didpp = kmem_alloc(dsize, KM_SLEEP); 2605 0 stevel 2606 6655 jwadams if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) { 2607 0 stevel kmem_free(start, dsize); 2608 0 stevel return (EFAULT); 2609 0 stevel } 2610 0 stevel while (ndid--) { 2611 0 stevel vnode_t *vp; 2612 0 stevel int fd = didpp->d_data.d_desc.d_descriptor; 2613 0 stevel 2614 0 stevel /* 2615 0 stevel * We only understand file descriptors as passed objs 2616 0 stevel */ 2617 0 stevel if ((didpp->d_attributes & DOOR_DESCRIPTOR) && 2618 0 stevel (fp = getf(fd)) != NULL) { 2619 0 stevel didpp->d_data.d_handle = FTODH(fp); 2620 0 stevel /* Hold the door */ 2621 0 stevel door_ki_hold(didpp->d_data.d_handle); 2622 0 stevel 2623 0 stevel releasef(fd); 2624 0 stevel 2625 0 stevel if (didpp->d_attributes & DOOR_RELEASE) { 2626 0 stevel /* release passed reference */ 2627 0 stevel (void) closeandsetf(fd, NULL); 2628 0 stevel } 2629 0 stevel 2630 5331 amw if (VOP_REALVP(fp->f_vnode, &vp, NULL)) 2631 0 stevel vp = fp->f_vnode; 2632 0 stevel 2633 0 stevel /* Set attributes */ 2634 0 stevel didpp->d_attributes = DOOR_HANDLE | 2635 0 stevel (VTOD(vp)->door_flags & DOOR_ATTR_MASK); 2636 0 stevel } else { 2637 0 stevel /* close translated references */ 2638 0 stevel door_fd_close(start, didpp - start); 2639 0 stevel /* close untranslated references */ 2640 0 stevel door_fd_rele(didpp, ndid + 1, 0); 2641 0 stevel kmem_free(start, dsize); 2642 0 stevel return (EINVAL); 2643 0 stevel } 2644 0 stevel didpp++; 2645 0 stevel } 2646 0 stevel ct->d_args.desc_ptr = start; 2647 0 stevel } 2648 0 stevel return (0); 2649 0 stevel } 2650 0 stevel 2651 0 stevel /* 2652 0 stevel * Translate door arguments from kernel to user. This copies the passed 2653 0 stevel * door handles. It doesn't touch other data. It is used by door_upcall, 2654 0 stevel * and for data returned by a door_call to a kernel server. 2655 0 stevel */ 2656 0 stevel static int 2657 0 stevel door_translate_out(void) 2658 0 stevel { 2659 0 stevel door_client_t *ct = DOOR_CLIENT(curthread->t_door); 2660 0 stevel uint_t ndid; 2661 0 stevel 2662 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2663 0 stevel ndid = ct->d_args.desc_num; 2664 0 stevel if (ndid > door_max_desc) { 2665 0 stevel door_fd_rele(ct->d_args.desc_ptr, ndid, 1); 2666 0 stevel return (E2BIG); 2667 0 stevel } 2668 0 stevel /* 2669 0 stevel * Translate the door args into files 2670 0 stevel */ 2671 0 stevel if (ndid != 0) { 2672 0 stevel door_desc_t *didpp = ct->d_args.desc_ptr; 2673 0 stevel struct file **fpp; 2674 0 stevel 2675 0 stevel ct->d_fpp_size = ndid * sizeof (struct file *); 2676 0 stevel fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP); 2677 0 stevel while (ndid--) { 2678 0 stevel struct file *fp = NULL; 2679 0 stevel int fd = -1; 2680 0 stevel 2681 0 stevel /* 2682 0 stevel * We understand file descriptors and door 2683 0 stevel * handles as passed objs. 2684 0 stevel */ 2685 0 stevel if (didpp->d_attributes & DOOR_DESCRIPTOR) { 2686 0 stevel fd = didpp->d_data.d_desc.d_descriptor; 2687 0 stevel fp = getf(fd); 2688 0 stevel } else if (didpp->d_attributes & DOOR_HANDLE) 2689 0 stevel fp = DHTOF(didpp->d_data.d_handle); 2690 0 stevel if (fp != NULL) { 2691 0 stevel /* Hold the fp */ 2692 0 stevel mutex_enter(&fp->f_tlock); 2693 0 stevel fp->f_count++; 2694 0 stevel mutex_exit(&fp->f_tlock); 2695 0 stevel 2696 0 stevel *fpp = fp; 2697 0 stevel if (didpp->d_attributes & DOOR_DESCRIPTOR) 2698 0 stevel releasef(fd); 2699 0 stevel if (didpp->d_attributes & DOOR_RELEASE) { 2700 0 stevel /* release passed reference */ 2701 0 stevel if (fd >= 0) 2702 0 stevel (void) closeandsetf(fd, NULL); 2703 0 stevel else 2704 0 stevel (void) closef(fp); 2705 0 stevel } 2706 0 stevel } else { 2707 0 stevel /* close translated references */ 2708 0 stevel door_fp_close(ct->d_fpp, fpp - ct->d_fpp); 2709 0 stevel /* close untranslated references */ 2710 0 stevel door_fd_rele(didpp, ndid + 1, 1); 2711 0 stevel kmem_free(ct->d_fpp, ct->d_fpp_size); 2712 0 stevel ct->d_fpp = NULL; 2713 0 stevel ct->d_fpp_size = 0; 2714 0 stevel return (EINVAL); 2715 0 stevel } 2716 0 stevel fpp++; didpp++; 2717 0 stevel } 2718 0 stevel } 2719 0 stevel return (0); 2720 0 stevel } 2721 0 stevel 2722 0 stevel /* 2723 0 stevel * Move the results from the server to the client 2724 0 stevel */ 2725 0 stevel static int 2726 0 stevel door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size, 2727 0 stevel door_desc_t *desc_ptr, uint_t desc_num) 2728 0 stevel { 2729 0 stevel door_client_t *ct = DOOR_CLIENT(caller->t_door); 2730 6997 jwadams door_upcall_t *dup = ct->d_upcall; 2731 0 stevel size_t dsize; 2732 0 stevel size_t rlen; 2733 0 stevel size_t result_size; 2734 0 stevel 2735 0 stevel ASSERT(DOOR_T_HELD(ct)); 2736 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2737 0 stevel 2738 0 stevel if (ct->d_noresults) 2739 0 stevel return (E2BIG); /* No results expected */ 2740 0 stevel 2741 0 stevel if (desc_num > door_max_desc) 2742 0 stevel return (E2BIG); /* Too many descriptors */ 2743 0 stevel 2744 0 stevel dsize = desc_num * sizeof (door_desc_t); 2745 0 stevel /* 2746 0 stevel * Check if the results are bigger than the clients buffer 2747 0 stevel */ 2748 0 stevel if (dsize) 2749 0 stevel rlen = roundup(data_size, sizeof (door_desc_t)); 2750 0 stevel else 2751 0 stevel rlen = data_size; 2752 0 stevel if ((result_size = rlen + dsize) == 0) 2753 0 stevel return (0); 2754 0 stevel 2755 6997 jwadams if (dup != NULL) { 2756 6997 jwadams if (desc_num > dup->du_max_descs) 2757 6997 jwadams return (EMFILE); 2758 6997 jwadams 2759 6997 jwadams if (data_size > dup->du_max_data) 2760 6997 jwadams return (E2BIG); 2761 6997 jwadams 2762 0 stevel /* 2763 0 stevel * Handle upcalls 2764 0 stevel */ 2765 0 stevel if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) { 2766 0 stevel /* 2767 0 stevel * If there's no return buffer or the buffer is too 2768 0 stevel * small, allocate a new one. The old buffer (if it 2769 0 stevel * exists) will be freed by the upcall client. 2770 0 stevel */ 2771 0 stevel if (result_size > door_max_upcall_reply) 2772 0 stevel return (E2BIG); 2773 0 stevel ct->d_args.rsize = result_size; 2774 0 stevel ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP); 2775 0 stevel } 2776 0 stevel ct->d_args.data_ptr = ct->d_args.rbuf; 2777 0 stevel if (data_size != 0 && 2778 6655 jwadams copyin_nowatch(data_ptr, ct->d_args.data_ptr, 2779 6655 jwadams data_size) != 0) 2780 0 stevel return (EFAULT); 2781 0 stevel } else if (result_size > ct->d_args.rsize) { 2782 0 stevel return (door_overflow(caller, data_ptr, data_size, 2783 0 stevel desc_ptr, desc_num)); 2784 0 stevel } else if (data_size != 0) { 2785 0 stevel if (data_size <= door_max_arg) { 2786 0 stevel /* 2787 0 stevel * Use a 2 copy method for small amounts of data 2788 0 stevel */ 2789 0 stevel if (ct->d_buf == NULL) { 2790 0 stevel ct->d_bufsize = data_size; 2791 0 stevel ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP); 2792 0 stevel } else if (ct->d_bufsize < data_size) { 2793 0 stevel kmem_free(ct->d_buf, ct->d_bufsize); 2794 0 stevel ct->d_bufsize = data_size; 2795 0 stevel ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP); 2796 0 stevel } 2797 6655 jwadams if (copyin_nowatch(data_ptr, ct->d_buf, data_size) != 0) 2798 0 stevel return (EFAULT); 2799 0 stevel } else { 2800 0 stevel struct as *as = ttoproc(caller)->p_as; 2801 0 stevel caddr_t dest = ct->d_args.rbuf; 2802 0 stevel caddr_t src = data_ptr; 2803 0 stevel size_t len = data_size; 2804 0 stevel 2805 0 stevel /* Copy data directly into client */ 2806 0 stevel while (len != 0) { 2807 0 stevel uint_t amount; 2808 0 stevel uint_t max; 2809 0 stevel uint_t off; 2810 0 stevel int error; 2811 0 stevel 2812 0 stevel off = (uintptr_t)dest & PAGEOFFSET; 2813 0 stevel if (off) 2814 0 stevel max = PAGESIZE - off; 2815 0 stevel else 2816 0 stevel max = PAGESIZE; 2817 0 stevel amount = len > max ? max : len; 2818 0 stevel error = door_copy(as, src, dest, amount); 2819 0 stevel if (error != 0) 2820 0 stevel return (error); 2821 0 stevel dest += amount; 2822 0 stevel src += amount; 2823 0 stevel len -= amount; 2824 0 stevel } 2825 0 stevel } 2826 0 stevel } 2827 0 stevel 2828 0 stevel /* 2829 0 stevel * Copyin the returned door ids and translate them into door_node_t 2830 0 stevel */ 2831 0 stevel if (desc_num != 0) { 2832 0 stevel door_desc_t *start; 2833 0 stevel door_desc_t *didpp; 2834 0 stevel struct file **fpp; 2835 0 stevel size_t fpp_size; 2836 0 stevel uint_t i; 2837 0 stevel 2838 0 stevel /* First, check if we would overflow client */ 2839 0 stevel if (!ufcanalloc(ttoproc(caller), desc_num)) 2840 0 stevel return (EMFILE); 2841 0 stevel 2842 0 stevel start = didpp = kmem_alloc(dsize, KM_SLEEP); 2843 6655 jwadams if (copyin_nowatch(desc_ptr, didpp, dsize)) { 2844 0 stevel kmem_free(start, dsize); 2845 0 stevel return (EFAULT); 2846 0 stevel } 2847 0 stevel fpp_size = desc_num * sizeof (struct file *); 2848 0 stevel if (fpp_size > ct->d_fpp_size) { 2849 0 stevel /* make more space */ 2850 0 stevel if (ct->d_fpp_size) 2851 0 stevel kmem_free(ct->d_fpp, ct->d_fpp_size); 2852 0 stevel ct->d_fpp_size = fpp_size; 2853 0 stevel ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP); 2854 0 stevel } 2855 0 stevel fpp = ct->d_fpp; 2856 0 stevel 2857 0 stevel for (i = 0; i < desc_num; i++) { 2858 0 stevel struct file *fp; 2859 0 stevel int fd = didpp->d_data.d_desc.d_descriptor; 2860 0 stevel 2861 0 stevel /* Only understand file descriptor results */ 2862 0 stevel if (!(didpp->d_attributes & DOOR_DESCRIPTOR) || 2863 0 stevel (fp = getf(fd)) == NULL) { 2864 0 stevel /* close translated references */ 2865 0 stevel door_fp_close(ct->d_fpp, fpp - ct->d_fpp); 2866 0 stevel /* close untranslated references */ 2867 0 stevel door_fd_rele(didpp, desc_num - i, 0); 2868 0 stevel kmem_free(start, dsize); 2869 0 stevel return (EINVAL); 2870 0 stevel } 2871 0 stevel 2872 0 stevel mutex_enter(&fp->f_tlock); 2873 0 stevel fp->f_count++; 2874 0 stevel mutex_exit(&fp->f_tlock); 2875 0 stevel 2876 0 stevel *fpp = fp; 2877 0 stevel releasef(fd); 2878 0 stevel 2879 0 stevel if (didpp->d_attributes & DOOR_RELEASE) { 2880 0 stevel /* release passed reference */ 2881 0 stevel (void) closeandsetf(fd, NULL); 2882 0 stevel } 2883 0 stevel 2884 0 stevel fpp++; didpp++; 2885 0 stevel } 2886 0 stevel kmem_free(start, dsize); 2887 0 stevel } 2888 0 stevel return (0); 2889 0 stevel } 2890 0 stevel 2891 0 stevel /* 2892 0 stevel * Close all the descriptors. 2893 0 stevel */ 2894 0 stevel static void 2895 0 stevel door_fd_close(door_desc_t *d, uint_t n) 2896 0 stevel { 2897 0 stevel uint_t i; 2898 0 stevel 2899 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2900 0 stevel for (i = 0; i < n; i++) { 2901 0 stevel if (d->d_attributes & DOOR_DESCRIPTOR) { 2902 0 stevel (void) closeandsetf( 2903 0 stevel d->d_data.d_desc.d_descriptor, NULL); 2904 0 stevel } else if (d->d_attributes & DOOR_HANDLE) { 2905 0 stevel door_ki_rele(d->d_data.d_handle); 2906 0 stevel } 2907 0 stevel d++; 2908 0 stevel } 2909 0 stevel } 2910 0 stevel 2911 0 stevel /* 2912 0 stevel * Close descriptors that have the DOOR_RELEASE attribute set. 2913 0 stevel */ 2914 0 stevel void 2915 0 stevel door_fd_rele(door_desc_t *d, uint_t n, int from_kernel) 2916 0 stevel { 2917 0 stevel uint_t i; 2918 0 stevel 2919 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2920 0 stevel for (i = 0; i < n; i++) { 2921 0 stevel if (d->d_attributes & DOOR_RELEASE) { 2922 0 stevel if (d->d_attributes & DOOR_DESCRIPTOR) { 2923 0 stevel (void) closeandsetf( 2924 0 stevel d->d_data.d_desc.d_descriptor, NULL); 2925 0 stevel } else if (from_kernel && 2926 0 stevel (d->d_attributes & DOOR_HANDLE)) { 2927 0 stevel door_ki_rele(d->d_data.d_handle); 2928 0 stevel } 2929 0 stevel } 2930 0 stevel d++; 2931 0 stevel } 2932 0 stevel } 2933 0 stevel 2934 0 stevel /* 2935 0 stevel * Copy descriptors into the kernel so we can release any marked 2936 0 stevel * DOOR_RELEASE. 2937 0 stevel */ 2938 0 stevel int 2939 0 stevel door_release_fds(door_desc_t *desc_ptr, uint_t ndesc) 2940 0 stevel { 2941 0 stevel size_t dsize; 2942 0 stevel door_desc_t *didpp; 2943 0 stevel uint_t desc_num; 2944 0 stevel 2945 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2946 0 stevel ASSERT(ndesc != 0); 2947 0 stevel 2948 0 stevel desc_num = MIN(ndesc, door_max_desc); 2949 0 stevel 2950 0 stevel dsize = desc_num * sizeof (door_desc_t); 2951 0 stevel didpp = kmem_alloc(dsize, KM_SLEEP); 2952 0 stevel 2953 0 stevel while (ndesc > 0) { 2954 0 stevel uint_t count = MIN(ndesc, desc_num); 2955 0 stevel 2956 6655 jwadams if (copyin_nowatch(desc_ptr, didpp, 2957 6655 jwadams count * sizeof (door_desc_t))) { 2958 0 stevel kmem_free(didpp, dsize); 2959 0 stevel return (EFAULT); 2960 0 stevel } 2961 0 stevel door_fd_rele(didpp, count, 0); 2962 0 stevel 2963 0 stevel ndesc -= count; 2964 0 stevel desc_ptr += count; 2965 0 stevel } 2966 0 stevel kmem_free(didpp, dsize); 2967 0 stevel return (0); 2968 0 stevel } 2969 0 stevel 2970 0 stevel /* 2971 0 stevel * Decrement ref count on all the files passed 2972 0 stevel */ 2973 0 stevel static void 2974 0 stevel door_fp_close(struct file **fp, uint_t n) 2975 0 stevel { 2976 0 stevel uint_t i; 2977 0 stevel 2978 0 stevel ASSERT(MUTEX_NOT_HELD(&door_knob)); 2979 0 stevel 2980 0 stevel for (i = 0; i < n; i++) 2981 0 stevel (void) closef(fp[i]); 2982 0 stevel } 2983 0 stevel 2984 0 stevel /* 2985 0 stevel * Copy data from 'src' in current address space to 'dest' in 'as' for 'len' 2986 0 stevel * bytes. 2987 0 stevel * 2988 0 stevel * Performs this using 1 mapin and 1 copy operation. 2989 0 stevel * 2990 0 stevel * We really should do more than 1 page at a time to improve 2991 0 stevel * performance, but for now this is treated as an anomalous condition. 2992 0 stevel */ 2993 0 stevel static int 2994 0 stevel door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len) 2995 0 stevel { 2996 0 stevel caddr_t kaddr; 2997 0 stevel caddr_t rdest; 2998 0 stevel uint_t off; 2999 0 stevel page_t **pplist; 3000 0 stevel page_t *pp = NULL; 3001 0 stevel int error = 0; 3002 0 stevel 3003 0 stevel ASSERT(len <= PAGESIZE); 3004 0 stevel off = (uintptr_t)dest & PAGEOFFSET; /* offset within the page */ 3005 0 stevel rdest = (caddr_t)((uintptr_t)dest & 3006 0 stevel (uintptr_t)PAGEMASK); /* Page boundary */ 3007 0 stevel ASSERT(off + len <= PAGESIZE); 3008 0 stevel 3009 0 stevel /* 3010 0 stevel * Lock down destination page. 3011 0 stevel */ 3012 0 stevel if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE)) 3013 0 stevel return (E2BIG); 3014 0 stevel /* 3015 0 stevel * Check if we have a shadow page list from as_pagelock. If not, 3016 0 stevel * we took the slow path and have to find our page struct the hard 3017 0 stevel * way. 3018 0 stevel */ 3019 0 stevel if (pplist == NULL) { 3020 0 stevel pfn_t pfnum; 3021 0 stevel 3022 0 stevel /* MMU mapping is already locked down */ 3023 0 stevel AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 3024 0 stevel pfnum = hat_getpfnum(as->a_hat, rdest); 3025 0 stevel AS_LOCK_EXIT(as, &as->a_lock); 3026 0 stevel 3027 0 stevel /* 3028 0 stevel * TODO: The pfn step should not be necessary - need 3029 0 stevel * a hat_getpp() function. 3030 0 stevel */ 3031 0 stevel if (pf_is_memory(pfnum)) { 3032 0 stevel pp = page_numtopp_nolock(pfnum); 3033 0 stevel ASSERT(pp == NULL || PAGE_LOCKED(pp)); 3034 0 stevel } else 3035 0 stevel pp = NULL; 3036 0 stevel if (pp == NULL) { 3037 0 stevel as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE); 3038 0 stevel return (E2BIG); 3039 0 stevel } 3040 0 stevel } else { 3041 0 stevel pp = *pplist; 3042 0 stevel } 3043 0 stevel /* 3044 0 stevel * Map destination page into kernel address 3045 0 stevel */ 3046 0 stevel kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE, (caddr_t)-1); 3047 0 stevel 3048 0 stevel /* 3049 0 stevel * Copy from src to dest 3050 0 stevel */ 3051 6655 jwadams if (copyin_nowatch(src, kaddr + off, len) != 0) 3052 0 stevel error = EFAULT; 3053 0 stevel /* 3054 0 stevel * Unmap destination page from kernel 3055 0 stevel */ 3056 0 stevel ppmapout(kaddr); 3057 0