1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/var.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/inline.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/siginfo.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/trap.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/machtrap.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/aio_impl.h> 56*7c478bd9Sstevel@tonic-gate #include <c2/audit.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/tnf.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/machpcb.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/copyops.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/timer.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/priv.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/msacct.h> 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate int syscalltrace = 0; 67*7c478bd9Sstevel@tonic-gate #ifdef SYSCALLTRACE 68*7c478bd9Sstevel@tonic-gate static kmutex_t systrace_lock; /* syscall tracing lock */ 69*7c478bd9Sstevel@tonic-gate #endif /* SYSCALLTRACE */ 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate static krwlock_t *lock_syscall(struct sysent *, uint_t); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 74*7c478bd9Sstevel@tonic-gate static struct sysent * 75*7c478bd9Sstevel@tonic-gate lwp_getsysent(klwp_t *lwp) 76*7c478bd9Sstevel@tonic-gate { 77*7c478bd9Sstevel@tonic-gate if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) 78*7c478bd9Sstevel@tonic-gate return (sysent); 79*7c478bd9Sstevel@tonic-gate return (sysent32); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate #define LWP_GETSYSENT(lwp) (lwp_getsysent(lwp)) 82*7c478bd9Sstevel@tonic-gate #else 83*7c478bd9Sstevel@tonic-gate #define LWP_GETSYSENT(lwp) (sysent) 84*7c478bd9Sstevel@tonic-gate #endif 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * Arrange for the real time profiling signal to be dispatched. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate void 90*7c478bd9Sstevel@tonic-gate realsigprof(int sysnum, int error) 91*7c478bd9Sstevel@tonic-gate { 92*7c478bd9Sstevel@tonic-gate proc_t *p; 93*7c478bd9Sstevel@tonic-gate klwp_t *lwp; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate if (curthread->t_rprof->rp_anystate == 0) 96*7c478bd9Sstevel@tonic-gate return; 97*7c478bd9Sstevel@tonic-gate p = ttoproc(curthread); 98*7c478bd9Sstevel@tonic-gate lwp = ttolwp(curthread); 99*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 100*7c478bd9Sstevel@tonic-gate if (sigismember(&p->p_ignore, SIGPROF) || 101*7c478bd9Sstevel@tonic-gate signal_is_blocked(curthread, SIGPROF)) { 102*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 103*7c478bd9Sstevel@tonic-gate return; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_signo = SIGPROF; 106*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_code = PROF_SIG; 107*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_errno = error; 108*7c478bd9Sstevel@tonic-gate hrt2ts(gethrtime(), &lwp->lwp_siginfo.si_tstamp); 109*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_syscall = sysnum; 110*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_nsysarg = (sysnum > 0 && sysnum < NSYSCALL) ? 111*7c478bd9Sstevel@tonic-gate LWP_GETSYSENT(lwp)[sysnum].sy_narg : 0; 112*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_fault = lwp->lwp_lastfault; 113*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_faddr = lwp->lwp_lastfaddr; 114*7c478bd9Sstevel@tonic-gate lwp->lwp_lastfault = 0; 115*7c478bd9Sstevel@tonic-gate lwp->lwp_lastfaddr = NULL; 116*7c478bd9Sstevel@tonic-gate sigtoproc(p, curthread, SIGPROF); 117*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 118*7c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_cursig == 0); 119*7c478bd9Sstevel@tonic-gate if (issig(FORREAL)) { 120*7c478bd9Sstevel@tonic-gate psig(); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 123*7c478bd9Sstevel@tonic-gate lwp->lwp_siginfo.si_signo = 0; 124*7c478bd9Sstevel@tonic-gate bzero(curthread->t_rprof, sizeof (*curthread->t_rprof)); 125*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* 129*7c478bd9Sstevel@tonic-gate * Called to restore the lwp's register window just before 130*7c478bd9Sstevel@tonic-gate * returning to user level (only if the registers have been 131*7c478bd9Sstevel@tonic-gate * fetched or modified through /proc). 132*7c478bd9Sstevel@tonic-gate */ 133*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 134*7c478bd9Sstevel@tonic-gate void 135*7c478bd9Sstevel@tonic-gate xregrestore(klwp_t *lwp, int shared) 136*7c478bd9Sstevel@tonic-gate { 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * If locals+ins were modified by /proc copy them out. 139*7c478bd9Sstevel@tonic-gate * Also copy to the shared window, if necessary. 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat == XREGMODIFIED) { 142*7c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 143*7c478bd9Sstevel@tonic-gate caddr_t sp = (caddr_t)lwptoregs(lwp)->r_sp; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate size_t rwinsize; 146*7c478bd9Sstevel@tonic-gate caddr_t rwp; 147*7c478bd9Sstevel@tonic-gate int is64; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate if (lwp_getdatamodel(lwp) == DATAMODEL_LP64) { 150*7c478bd9Sstevel@tonic-gate rwinsize = sizeof (struct rwindow); 151*7c478bd9Sstevel@tonic-gate rwp = sp + STACK_BIAS; 152*7c478bd9Sstevel@tonic-gate is64 = 1; 153*7c478bd9Sstevel@tonic-gate } else { 154*7c478bd9Sstevel@tonic-gate rwinsize = sizeof (struct rwindow32); 155*7c478bd9Sstevel@tonic-gate sp = (caddr_t)(caddr32_t)sp; 156*7c478bd9Sstevel@tonic-gate rwp = sp; 157*7c478bd9Sstevel@tonic-gate is64 = 0; 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate if (is64) 161*7c478bd9Sstevel@tonic-gate (void) copyout_nowatch(&lwp->lwp_pcb.pcb_xregs, 162*7c478bd9Sstevel@tonic-gate rwp, rwinsize); 163*7c478bd9Sstevel@tonic-gate else { 164*7c478bd9Sstevel@tonic-gate struct rwindow32 rwindow32; 165*7c478bd9Sstevel@tonic-gate int watched; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate watched = watch_disable_addr(rwp, rwinsize, S_WRITE); 168*7c478bd9Sstevel@tonic-gate rwindow_nto32(&lwp->lwp_pcb.pcb_xregs, &rwindow32); 169*7c478bd9Sstevel@tonic-gate (void) copyout(&rwindow32, rwp, rwinsize); 170*7c478bd9Sstevel@tonic-gate if (watched) 171*7c478bd9Sstevel@tonic-gate watch_enable_addr(rwp, rwinsize, S_WRITE); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* also copy to the user return window */ 175*7c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = sp; 176*7c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 177*7c478bd9Sstevel@tonic-gate bcopy(&lwp->lwp_pcb.pcb_xregs, &mpcb->mpcb_rwin[0], 178*7c478bd9Sstevel@tonic-gate sizeof (lwp->lwp_pcb.pcb_xregs)); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_xregstat = XREGNONE; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * Get the arguments to the current system call. 186*7c478bd9Sstevel@tonic-gate * lwp->lwp_ap normally points to the out regs in the reg structure. 187*7c478bd9Sstevel@tonic-gate * If the user is going to change the out registers and might want to 188*7c478bd9Sstevel@tonic-gate * get the args (for /proc tracing), it must copy the args elsewhere 189*7c478bd9Sstevel@tonic-gate * via save_syscall_args(). 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate uint_t 192*7c478bd9Sstevel@tonic-gate get_syscall_args(klwp_t *lwp, long *argp, int *nargsp) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate kthread_t *t = lwptot(lwp); 195*7c478bd9Sstevel@tonic-gate uint_t code = t->t_sysnum; 196*7c478bd9Sstevel@tonic-gate long mask; 197*7c478bd9Sstevel@tonic-gate long *ap; 198*7c478bd9Sstevel@tonic-gate int nargs; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32) 201*7c478bd9Sstevel@tonic-gate mask = (uint32_t)0xffffffffU; 202*7c478bd9Sstevel@tonic-gate else 203*7c478bd9Sstevel@tonic-gate mask = 0xffffffffffffffff; 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate if (code != 0 && code < NSYSCALL) { 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate nargs = LWP_GETSYSENT(lwp)[code].sy_narg; 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate ASSERT(nargs <= MAXSYSARGS); 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate *nargsp = nargs; 212*7c478bd9Sstevel@tonic-gate ap = lwp->lwp_ap; 213*7c478bd9Sstevel@tonic-gate while (nargs-- > 0) 214*7c478bd9Sstevel@tonic-gate *argp++ = *ap++ & mask; 215*7c478bd9Sstevel@tonic-gate } else { 216*7c478bd9Sstevel@tonic-gate *nargsp = 0; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate return (code); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 222*7c478bd9Sstevel@tonic-gate /* 223*7c478bd9Sstevel@tonic-gate * Get the arguments to the current 32-bit system call. 224*7c478bd9Sstevel@tonic-gate */ 225*7c478bd9Sstevel@tonic-gate uint_t 226*7c478bd9Sstevel@tonic-gate get_syscall32_args(klwp_t *lwp, int *argp, int *nargsp) 227*7c478bd9Sstevel@tonic-gate { 228*7c478bd9Sstevel@tonic-gate long args[MAXSYSARGS]; 229*7c478bd9Sstevel@tonic-gate uint_t i, code; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate code = get_syscall_args(lwp, args, nargsp); 232*7c478bd9Sstevel@tonic-gate for (i = 0; i != *nargsp; i++) 233*7c478bd9Sstevel@tonic-gate *argp++ = (int)args[i]; 234*7c478bd9Sstevel@tonic-gate return (code); 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate #endif 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * Save the system call arguments in a safe place. 240*7c478bd9Sstevel@tonic-gate * lwp->lwp_ap normally points to the out regs in the reg structure. 241*7c478bd9Sstevel@tonic-gate * If the user is going to change the out registers, g1, or the stack, 242*7c478bd9Sstevel@tonic-gate * and might want to get the args (for /proc tracing), it must copy 243*7c478bd9Sstevel@tonic-gate * the args elsewhere via save_syscall_args(). 244*7c478bd9Sstevel@tonic-gate * 245*7c478bd9Sstevel@tonic-gate * This may be called from stop() even when we're not in a system call. 246*7c478bd9Sstevel@tonic-gate * Since there's no easy way to tell, this must be safe (not panic). 247*7c478bd9Sstevel@tonic-gate * If the copyins get data faults, return non-zero. 248*7c478bd9Sstevel@tonic-gate */ 249*7c478bd9Sstevel@tonic-gate int 250*7c478bd9Sstevel@tonic-gate save_syscall_args() 251*7c478bd9Sstevel@tonic-gate { 252*7c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 253*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 254*7c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 255*7c478bd9Sstevel@tonic-gate uint_t code = t->t_sysnum; 256*7c478bd9Sstevel@tonic-gate uint_t nargs; 257*7c478bd9Sstevel@tonic-gate int i; 258*7c478bd9Sstevel@tonic-gate caddr_t ua; 259*7c478bd9Sstevel@tonic-gate model_t datamodel; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate if (lwp->lwp_argsaved || code == 0) 262*7c478bd9Sstevel@tonic-gate return (0); /* args already saved or not needed */ 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate if (code >= NSYSCALL) { 265*7c478bd9Sstevel@tonic-gate nargs = 0; /* illegal syscall */ 266*7c478bd9Sstevel@tonic-gate } else { 267*7c478bd9Sstevel@tonic-gate struct sysent *se = LWP_GETSYSENT(lwp); 268*7c478bd9Sstevel@tonic-gate struct sysent *callp = se + code; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate nargs = callp->sy_narg; 271*7c478bd9Sstevel@tonic-gate if (LOADABLE_SYSCALL(callp) && nargs == 0) { 272*7c478bd9Sstevel@tonic-gate krwlock_t *module_lock; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * Find out how many arguments the system 276*7c478bd9Sstevel@tonic-gate * call uses. 277*7c478bd9Sstevel@tonic-gate * 278*7c478bd9Sstevel@tonic-gate * We have the property that loaded syscalls 279*7c478bd9Sstevel@tonic-gate * never change the number of arguments they 280*7c478bd9Sstevel@tonic-gate * use after they've been loaded once. This 281*7c478bd9Sstevel@tonic-gate * allows us to stop for /proc tracing without 282*7c478bd9Sstevel@tonic-gate * holding the module lock. 283*7c478bd9Sstevel@tonic-gate * /proc is assured that sy_narg is valid. 284*7c478bd9Sstevel@tonic-gate */ 285*7c478bd9Sstevel@tonic-gate module_lock = lock_syscall(se, code); 286*7c478bd9Sstevel@tonic-gate nargs = callp->sy_narg; 287*7c478bd9Sstevel@tonic-gate rw_exit(module_lock); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * Fetch the system call arguments. 293*7c478bd9Sstevel@tonic-gate */ 294*7c478bd9Sstevel@tonic-gate if (nargs == 0) 295*7c478bd9Sstevel@tonic-gate goto out; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate ASSERT(nargs <= MAXSYSARGS); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate if ((datamodel = lwp_getdatamodel(lwp)) == DATAMODEL_ILP32) { 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate if (rp->r_g1 == 0) { /* indirect syscall */ 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[0] = (uint32_t)rp->r_o1; 305*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[1] = (uint32_t)rp->r_o2; 306*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[2] = (uint32_t)rp->r_o3; 307*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[3] = (uint32_t)rp->r_o4; 308*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[4] = (uint32_t)rp->r_o5; 309*7c478bd9Sstevel@tonic-gate if (nargs > 5) { 310*7c478bd9Sstevel@tonic-gate ua = (caddr_t)(caddr32_t)(rp->r_sp + 311*7c478bd9Sstevel@tonic-gate MINFRAME32); 312*7c478bd9Sstevel@tonic-gate for (i = 5; i < nargs; i++) { 313*7c478bd9Sstevel@tonic-gate uint32_t a; 314*7c478bd9Sstevel@tonic-gate if (fuword32(ua, &a) != 0) 315*7c478bd9Sstevel@tonic-gate return (-1); 316*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[i] = a; 317*7c478bd9Sstevel@tonic-gate ua += sizeof (a); 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } else { 321*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[0] = (uint32_t)rp->r_o0; 322*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[1] = (uint32_t)rp->r_o1; 323*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[2] = (uint32_t)rp->r_o2; 324*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[3] = (uint32_t)rp->r_o3; 325*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[4] = (uint32_t)rp->r_o4; 326*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[5] = (uint32_t)rp->r_o5; 327*7c478bd9Sstevel@tonic-gate if (nargs > 6) { 328*7c478bd9Sstevel@tonic-gate ua = (caddr_t)(caddr32_t)(rp->r_sp + 329*7c478bd9Sstevel@tonic-gate MINFRAME32); 330*7c478bd9Sstevel@tonic-gate for (i = 6; i < nargs; i++) { 331*7c478bd9Sstevel@tonic-gate uint32_t a; 332*7c478bd9Sstevel@tonic-gate if (fuword32(ua, &a) != 0) 333*7c478bd9Sstevel@tonic-gate return (-1); 334*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[i] = a; 335*7c478bd9Sstevel@tonic-gate ua += sizeof (a); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate } else { 340*7c478bd9Sstevel@tonic-gate ASSERT(datamodel == DATAMODEL_LP64); 341*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[0] = rp->r_o0; 342*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[1] = rp->r_o1; 343*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[2] = rp->r_o2; 344*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[3] = rp->r_o3; 345*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[4] = rp->r_o4; 346*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[5] = rp->r_o5; 347*7c478bd9Sstevel@tonic-gate if (nargs > 6) { 348*7c478bd9Sstevel@tonic-gate ua = (caddr_t)rp->r_sp + MINFRAME + STACK_BIAS; 349*7c478bd9Sstevel@tonic-gate for (i = 6; i < nargs; i++) { 350*7c478bd9Sstevel@tonic-gate unsigned long a; 351*7c478bd9Sstevel@tonic-gate if (fulword(ua, &a) != 0) 352*7c478bd9Sstevel@tonic-gate return (-1); 353*7c478bd9Sstevel@tonic-gate lwp->lwp_arg[i] = a; 354*7c478bd9Sstevel@tonic-gate ua += sizeof (a); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate out: 360*7c478bd9Sstevel@tonic-gate lwp->lwp_ap = lwp->lwp_arg; 361*7c478bd9Sstevel@tonic-gate lwp->lwp_argsaved = 1; 362*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; /* so lwp_ap will be reset */ 363*7c478bd9Sstevel@tonic-gate return (0); 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate void 367*7c478bd9Sstevel@tonic-gate reset_syscall_args(void) 368*7c478bd9Sstevel@tonic-gate { 369*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate lwp->lwp_ap = (long *)&lwptoregs(lwp)->r_o0; 372*7c478bd9Sstevel@tonic-gate lwp->lwp_argsaved = 0; 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* 376*7c478bd9Sstevel@tonic-gate * nonexistent system call-- signal lwp (may want to handle it) 377*7c478bd9Sstevel@tonic-gate * flag error if lwp won't see signal immediately 378*7c478bd9Sstevel@tonic-gate * This works for old or new calling sequence. 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate int64_t 381*7c478bd9Sstevel@tonic-gate nosys() 382*7c478bd9Sstevel@tonic-gate { 383*7c478bd9Sstevel@tonic-gate tsignal(curthread, SIGSYS); 384*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(ENOSYS)); 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate /* 388*7c478bd9Sstevel@tonic-gate * Perform pre-system-call processing, including stopping for tracing, 389*7c478bd9Sstevel@tonic-gate * auditing, microstate-accounting, etc. 390*7c478bd9Sstevel@tonic-gate * 391*7c478bd9Sstevel@tonic-gate * This routine is called only if the t_pre_sys flag is set. Any condition 392*7c478bd9Sstevel@tonic-gate * requiring pre-syscall handling must set the t_pre_sys flag. If the 393*7c478bd9Sstevel@tonic-gate * condition is persistent, this routine will repost t_pre_sys. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate int 396*7c478bd9Sstevel@tonic-gate pre_syscall(int arg0) 397*7c478bd9Sstevel@tonic-gate { 398*7c478bd9Sstevel@tonic-gate unsigned int code; 399*7c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 400*7c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(t); 401*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 402*7c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 403*7c478bd9Sstevel@tonic-gate int repost; 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate t->t_pre_sys = repost = 0; /* clear pre-syscall processing flag */ 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate ASSERT(t->t_schedflag & TS_DONT_SWAP); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate syscall_mstate(LMS_USER, LMS_SYSTEM); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * The syscall arguments in the out registers should be pointed to 413*7c478bd9Sstevel@tonic-gate * by lwp_ap. If the args need to be copied so that the outs can 414*7c478bd9Sstevel@tonic-gate * be changed without losing the ability to get the args for /proc, 415*7c478bd9Sstevel@tonic-gate * they can be saved by save_syscall_args(), and lwp_ap will be 416*7c478bd9Sstevel@tonic-gate * restored by post_syscall(). 417*7c478bd9Sstevel@tonic-gate */ 418*7c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_ap == (long *)&rp->r_o0); 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * Make sure the thread is holding the latest credentials for the 422*7c478bd9Sstevel@tonic-gate * process. The credentials in the process right now apply to this 423*7c478bd9Sstevel@tonic-gate * thread for the entire system call. 424*7c478bd9Sstevel@tonic-gate */ 425*7c478bd9Sstevel@tonic-gate if (t->t_cred != p->p_cred) { 426*7c478bd9Sstevel@tonic-gate cred_t *oldcred = t->t_cred; 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred must 429*7c478bd9Sstevel@tonic-gate * always be either NULL, or point to a valid, allocated cred 430*7c478bd9Sstevel@tonic-gate * structure. 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate t->t_cred = crgetcred(); 433*7c478bd9Sstevel@tonic-gate crfree(oldcred); 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* 437*7c478bd9Sstevel@tonic-gate * Undo special arrangements to single-step the lwp 438*7c478bd9Sstevel@tonic-gate * so that a debugger will see valid register contents. 439*7c478bd9Sstevel@tonic-gate * Also so that the pc is valid for syncfpu(). 440*7c478bd9Sstevel@tonic-gate * Also so that a syscall like exec() can be stepped. 441*7c478bd9Sstevel@tonic-gate */ 442*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_step != STEP_NONE) { 443*7c478bd9Sstevel@tonic-gate (void) prundostep(); 444*7c478bd9Sstevel@tonic-gate repost = 1; 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * Check for indirect system call in case we stop for tracing. 449*7c478bd9Sstevel@tonic-gate * Don't allow multiple indirection. 450*7c478bd9Sstevel@tonic-gate */ 451*7c478bd9Sstevel@tonic-gate code = t->t_sysnum; 452*7c478bd9Sstevel@tonic-gate if (code == 0 && arg0 != 0) { /* indirect syscall */ 453*7c478bd9Sstevel@tonic-gate code = arg0; 454*7c478bd9Sstevel@tonic-gate t->t_sysnum = arg0; 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * From the proc(4) manual page: 459*7c478bd9Sstevel@tonic-gate * When entry to a system call is being traced, the traced process 460*7c478bd9Sstevel@tonic-gate * stops after having begun the call to the system but before the 461*7c478bd9Sstevel@tonic-gate * system call arguments have been fetched from the process. 462*7c478bd9Sstevel@tonic-gate * If proc changes the args we must refetch them after starting. 463*7c478bd9Sstevel@tonic-gate */ 464*7c478bd9Sstevel@tonic-gate if (PTOU(p)->u_systrap) { 465*7c478bd9Sstevel@tonic-gate if (prismember(&PTOU(p)->u_entrymask, code)) { 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * Recheck stop condition, now that lock is held. 468*7c478bd9Sstevel@tonic-gate */ 469*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 470*7c478bd9Sstevel@tonic-gate if (PTOU(p)->u_systrap && 471*7c478bd9Sstevel@tonic-gate prismember(&PTOU(p)->u_entrymask, code)) { 472*7c478bd9Sstevel@tonic-gate stop(PR_SYSENTRY, code); 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * Must refetch args since they were 475*7c478bd9Sstevel@tonic-gate * possibly modified by /proc. Indicate 476*7c478bd9Sstevel@tonic-gate * that the valid copy is in the 477*7c478bd9Sstevel@tonic-gate * registers. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate lwp->lwp_argsaved = 0; 480*7c478bd9Sstevel@tonic-gate lwp->lwp_ap = (long *)&rp->r_o0; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate repost = 1; 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate if (lwp->lwp_sysabort) { 488*7c478bd9Sstevel@tonic-gate /* 489*7c478bd9Sstevel@tonic-gate * lwp_sysabort may have been set via /proc while the process 490*7c478bd9Sstevel@tonic-gate * was stopped on PR_SYSENTRY. If so, abort the system call. 491*7c478bd9Sstevel@tonic-gate * Override any error from the copyin() of the arguments. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate lwp->lwp_sysabort = 0; 494*7c478bd9Sstevel@tonic-gate (void) set_errno(EINTR); /* sets post-sys processing */ 495*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; /* repost anyway */ 496*7c478bd9Sstevel@tonic-gate return (1); /* don't do system call, return EINTR */ 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 500*7c478bd9Sstevel@tonic-gate if (audit_active) { /* begin auditing for this syscall */ 501*7c478bd9Sstevel@tonic-gate int error; 502*7c478bd9Sstevel@tonic-gate if (error = audit_start(T_SYSCALL, code, 0, lwp)) { 503*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; /* repost anyway */ 504*7c478bd9Sstevel@tonic-gate lwp->lwp_error = 0; /* for old drivers */ 505*7c478bd9Sstevel@tonic-gate return (error); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate repost = 1; 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */ 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate #ifndef NPROBE 512*7c478bd9Sstevel@tonic-gate /* Kernel probe */ 513*7c478bd9Sstevel@tonic-gate if (tnf_tracing_active) { 514*7c478bd9Sstevel@tonic-gate TNF_PROBE_1(syscall_start, "syscall thread", /* CSTYLED */, 515*7c478bd9Sstevel@tonic-gate tnf_sysnum, sysnum, t->t_sysnum); 516*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; /* make sure post_syscall runs */ 517*7c478bd9Sstevel@tonic-gate repost = 1; 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate #endif /* NPROBE */ 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate #ifdef SYSCALLTRACE 522*7c478bd9Sstevel@tonic-gate if (syscalltrace) { 523*7c478bd9Sstevel@tonic-gate int i; 524*7c478bd9Sstevel@tonic-gate long *ap; 525*7c478bd9Sstevel@tonic-gate char *cp; 526*7c478bd9Sstevel@tonic-gate char *sysname; 527*7c478bd9Sstevel@tonic-gate struct sysent *callp; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate if (code >= NSYSCALL) 530*7c478bd9Sstevel@tonic-gate callp = &nosys_ent; /* nosys has no args */ 531*7c478bd9Sstevel@tonic-gate else 532*7c478bd9Sstevel@tonic-gate callp = LWP_GETSYSENT(lwp) + code; 533*7c478bd9Sstevel@tonic-gate (void) save_syscall_args(); 534*7c478bd9Sstevel@tonic-gate mutex_enter(&systrace_lock); 535*7c478bd9Sstevel@tonic-gate printf("%d: ", p->p_pid); 536*7c478bd9Sstevel@tonic-gate if (code >= NSYSCALL) 537*7c478bd9Sstevel@tonic-gate printf("0x%x", code); 538*7c478bd9Sstevel@tonic-gate else { 539*7c478bd9Sstevel@tonic-gate sysname = mod_getsysname(code); 540*7c478bd9Sstevel@tonic-gate printf("%s[0x%x]", sysname == NULL ? "NULL" : 541*7c478bd9Sstevel@tonic-gate sysname, code); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate cp = "("; 544*7c478bd9Sstevel@tonic-gate for (i = 0, ap = lwp->lwp_ap; i < callp->sy_narg; i++, ap++) { 545*7c478bd9Sstevel@tonic-gate printf("%s%lx", cp, *ap); 546*7c478bd9Sstevel@tonic-gate cp = ", "; 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate if (i) 549*7c478bd9Sstevel@tonic-gate printf(")"); 550*7c478bd9Sstevel@tonic-gate printf(" %s id=0x%p\n", PTOU(p)->u_comm, curthread); 551*7c478bd9Sstevel@tonic-gate mutex_exit(&systrace_lock); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate #endif /* SYSCALLTRACE */ 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate /* 556*7c478bd9Sstevel@tonic-gate * If there was a continuing reason for pre-syscall processing, 557*7c478bd9Sstevel@tonic-gate * set the t_pre_sys flag for the next system call. 558*7c478bd9Sstevel@tonic-gate */ 559*7c478bd9Sstevel@tonic-gate if (repost) 560*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; 561*7c478bd9Sstevel@tonic-gate lwp->lwp_error = 0; /* for old drivers */ 562*7c478bd9Sstevel@tonic-gate lwp->lwp_badpriv = PRIV_NONE; /* for privilege tracing */ 563*7c478bd9Sstevel@tonic-gate return (0); 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate /* 567*7c478bd9Sstevel@tonic-gate * Post-syscall processing. Perform abnormal system call completion 568*7c478bd9Sstevel@tonic-gate * actions such as /proc tracing, profiling, signals, preemption, etc. 569*7c478bd9Sstevel@tonic-gate * 570*7c478bd9Sstevel@tonic-gate * This routine is called only if t_post_sys, t_sig_check, or t_astflag is set. 571*7c478bd9Sstevel@tonic-gate * Any condition requiring pre-syscall handling must set one of these. 572*7c478bd9Sstevel@tonic-gate * If the condition is persistent, this routine will repost t_post_sys. 573*7c478bd9Sstevel@tonic-gate */ 574*7c478bd9Sstevel@tonic-gate void 575*7c478bd9Sstevel@tonic-gate post_syscall(long rval1, long rval2) 576*7c478bd9Sstevel@tonic-gate { 577*7c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 578*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 579*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 580*7c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 581*7c478bd9Sstevel@tonic-gate uint_t error; 582*7c478bd9Sstevel@tonic-gate int code = t->t_sysnum; 583*7c478bd9Sstevel@tonic-gate int repost = 0; 584*7c478bd9Sstevel@tonic-gate int proc_stop = 0; /* non-zero if stopping for /proc */ 585*7c478bd9Sstevel@tonic-gate int sigprof = 0; /* non-zero if sending SIGPROF */ 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate t->t_post_sys = 0; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate error = lwp->lwp_errno; 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * Code can be zero if this is a new LWP returning after a forkall(), 593*7c478bd9Sstevel@tonic-gate * other than the one which matches the one in the parent which called 594*7c478bd9Sstevel@tonic-gate * forkall(). In these LWPs, skip most of post-syscall activity. 595*7c478bd9Sstevel@tonic-gate */ 596*7c478bd9Sstevel@tonic-gate if (code == 0) 597*7c478bd9Sstevel@tonic-gate goto sig_check; 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 600*7c478bd9Sstevel@tonic-gate if (audit_active) { /* put out audit record for this syscall */ 601*7c478bd9Sstevel@tonic-gate rval_t rval; /* fix audit_finish() someday */ 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* XX64 -- truncation of 64-bit return values? */ 604*7c478bd9Sstevel@tonic-gate rval.r_val1 = (int)rval1; 605*7c478bd9Sstevel@tonic-gate rval.r_val2 = (int)rval2; 606*7c478bd9Sstevel@tonic-gate audit_finish(T_SYSCALL, code, error, &rval); 607*7c478bd9Sstevel@tonic-gate repost = 1; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */ 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate if (curthread->t_pdmsg != NULL) { 612*7c478bd9Sstevel@tonic-gate char *m = curthread->t_pdmsg; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate uprintf("%s", m); 615*7c478bd9Sstevel@tonic-gate kmem_free(m, strlen(m) + 1); 616*7c478bd9Sstevel@tonic-gate curthread->t_pdmsg = NULL; 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* 620*7c478bd9Sstevel@tonic-gate * If we're going to stop for /proc tracing, set the flag and 621*7c478bd9Sstevel@tonic-gate * save the arguments so that the return values don't smash them. 622*7c478bd9Sstevel@tonic-gate */ 623*7c478bd9Sstevel@tonic-gate if (PTOU(p)->u_systrap) { 624*7c478bd9Sstevel@tonic-gate if (prismember(&PTOU(p)->u_exitmask, code)) { 625*7c478bd9Sstevel@tonic-gate proc_stop = 1; 626*7c478bd9Sstevel@tonic-gate (void) save_syscall_args(); 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate repost = 1; 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate /* 632*7c478bd9Sstevel@tonic-gate * Similarly check to see if SIGPROF might be sent. 633*7c478bd9Sstevel@tonic-gate */ 634*7c478bd9Sstevel@tonic-gate if (curthread->t_rprof != NULL && 635*7c478bd9Sstevel@tonic-gate curthread->t_rprof->rp_anystate != 0) { 636*7c478bd9Sstevel@tonic-gate (void) save_syscall_args(); 637*7c478bd9Sstevel@tonic-gate sigprof = 1; 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate if (lwp->lwp_eosys == NORMALRETURN) { 641*7c478bd9Sstevel@tonic-gate if (error == 0) { 642*7c478bd9Sstevel@tonic-gate #ifdef SYSCALLTRACE 643*7c478bd9Sstevel@tonic-gate if (syscalltrace) { 644*7c478bd9Sstevel@tonic-gate mutex_enter(&systrace_lock); 645*7c478bd9Sstevel@tonic-gate printf( 646*7c478bd9Sstevel@tonic-gate "%d: r_val1=0x%lx, r_val2=0x%lx, id 0x%p\n", 647*7c478bd9Sstevel@tonic-gate p->p_pid, rval1, rval2, curthread); 648*7c478bd9Sstevel@tonic-gate mutex_exit(&systrace_lock); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate #endif /* SYSCALLTRACE */ 651*7c478bd9Sstevel@tonic-gate rp->r_tstate &= ~TSTATE_IC; 652*7c478bd9Sstevel@tonic-gate rp->r_o0 = rval1; 653*7c478bd9Sstevel@tonic-gate rp->r_o1 = rval2; 654*7c478bd9Sstevel@tonic-gate } else { 655*7c478bd9Sstevel@tonic-gate int sig; 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate #ifdef SYSCALLTRACE 658*7c478bd9Sstevel@tonic-gate if (syscalltrace) { 659*7c478bd9Sstevel@tonic-gate mutex_enter(&systrace_lock); 660*7c478bd9Sstevel@tonic-gate printf("%d: error=%d, id 0x%p\n", 661*7c478bd9Sstevel@tonic-gate p->p_pid, error, curthread); 662*7c478bd9Sstevel@tonic-gate mutex_exit(&systrace_lock); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate #endif /* SYSCALLTRACE */ 665*7c478bd9Sstevel@tonic-gate if (error == EINTR && t->t_activefd.a_stale) 666*7c478bd9Sstevel@tonic-gate error = EBADF; 667*7c478bd9Sstevel@tonic-gate if (error == EINTR && 668*7c478bd9Sstevel@tonic-gate (sig = lwp->lwp_cursig) != 0 && 669*7c478bd9Sstevel@tonic-gate sigismember(&PTOU(p)->u_sigrestart, sig) && 670*7c478bd9Sstevel@tonic-gate PTOU(p)->u_signal[sig - 1] != SIG_DFL && 671*7c478bd9Sstevel@tonic-gate PTOU(p)->u_signal[sig - 1] != SIG_IGN) 672*7c478bd9Sstevel@tonic-gate error = ERESTART; 673*7c478bd9Sstevel@tonic-gate rp->r_o0 = error; 674*7c478bd9Sstevel@tonic-gate rp->r_tstate |= TSTATE_IC; 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * The default action is to redo the trap instruction. 678*7c478bd9Sstevel@tonic-gate * We increment the pc and npc past it for NORMALRETURN. 679*7c478bd9Sstevel@tonic-gate * JUSTRETURN has set up a new pc and npc already. 680*7c478bd9Sstevel@tonic-gate * RESTARTSYS automatically restarts by leaving pc and npc 681*7c478bd9Sstevel@tonic-gate * alone. 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate rp->r_pc = rp->r_npc; 684*7c478bd9Sstevel@tonic-gate rp->r_npc += 4; 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * From the proc(4) manual page: 689*7c478bd9Sstevel@tonic-gate * When exit from a system call is being traced, the traced process 690*7c478bd9Sstevel@tonic-gate * stops on completion of the system call just prior to checking for 691*7c478bd9Sstevel@tonic-gate * signals and returning to user level. At this point all return 692*7c478bd9Sstevel@tonic-gate * values have been stored into the traced process's saved registers. 693*7c478bd9Sstevel@tonic-gate */ 694*7c478bd9Sstevel@tonic-gate if (proc_stop) { 695*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 696*7c478bd9Sstevel@tonic-gate if (PTOU(p)->u_systrap && 697*7c478bd9Sstevel@tonic-gate prismember(&PTOU(p)->u_exitmask, code)) 698*7c478bd9Sstevel@tonic-gate stop(PR_SYSEXIT, code); 699*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate /* 703*7c478bd9Sstevel@tonic-gate * If we are the parent returning from a successful 704*7c478bd9Sstevel@tonic-gate * vfork, wait for the child to exec or exit. 705*7c478bd9Sstevel@tonic-gate * This code must be here and not in the bowels of the system 706*7c478bd9Sstevel@tonic-gate * so that /proc can intercept exit from vfork in a timely way. 707*7c478bd9Sstevel@tonic-gate */ 708*7c478bd9Sstevel@tonic-gate if (code == SYS_vfork && rp->r_o1 == 0 && error == 0) 709*7c478bd9Sstevel@tonic-gate vfwait((pid_t)rval1); 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate /* 712*7c478bd9Sstevel@tonic-gate * If profiling is active, bill the current PC in user-land 713*7c478bd9Sstevel@tonic-gate * and keep reposting until profiling is disabled. 714*7c478bd9Sstevel@tonic-gate */ 715*7c478bd9Sstevel@tonic-gate if (p->p_prof.pr_scale) { 716*7c478bd9Sstevel@tonic-gate if (lwp->lwp_oweupc) 717*7c478bd9Sstevel@tonic-gate profil_tick(rp->r_pc); 718*7c478bd9Sstevel@tonic-gate repost = 1; 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate t->t_sysnum = 0; /* no longer in a system call */ 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate sig_check: 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * Reset flag for next time. 726*7c478bd9Sstevel@tonic-gate * We must do this after stopping on PR_SYSEXIT 727*7c478bd9Sstevel@tonic-gate * because /proc uses the information in lwp_eosys. 728*7c478bd9Sstevel@tonic-gate */ 729*7c478bd9Sstevel@tonic-gate lwp->lwp_eosys = NORMALRETURN; 730*7c478bd9Sstevel@tonic-gate clear_stale_fd(); 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate if (t->t_astflag | t->t_sig_check) { 733*7c478bd9Sstevel@tonic-gate /* 734*7c478bd9Sstevel@tonic-gate * Turn off the AST flag before checking all the conditions that 735*7c478bd9Sstevel@tonic-gate * may have caused an AST. This flag is on whenever a signal or 736*7c478bd9Sstevel@tonic-gate * unusual condition should be handled after the next trap or 737*7c478bd9Sstevel@tonic-gate * syscall. 738*7c478bd9Sstevel@tonic-gate */ 739*7c478bd9Sstevel@tonic-gate astoff(t); 740*7c478bd9Sstevel@tonic-gate t->t_sig_check = 0; 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 743*7c478bd9Sstevel@tonic-gate if (curthread->t_proc_flag & TP_CHANGEBIND) { 744*7c478bd9Sstevel@tonic-gate timer_lwpbind(); 745*7c478bd9Sstevel@tonic-gate curthread->t_proc_flag &= ~TP_CHANGEBIND; 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate /* 750*7c478bd9Sstevel@tonic-gate * for kaio requests on the special kaio poll queue, 751*7c478bd9Sstevel@tonic-gate * copyout their results to user memory. 752*7c478bd9Sstevel@tonic-gate */ 753*7c478bd9Sstevel@tonic-gate if (p->p_aio) 754*7c478bd9Sstevel@tonic-gate aio_cleanup(0); 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate /* 757*7c478bd9Sstevel@tonic-gate * If this LWP was asked to hold, call holdlwp(), which will 758*7c478bd9Sstevel@tonic-gate * stop. holdlwps() sets this up and calls pokelwps() which 759*7c478bd9Sstevel@tonic-gate * sets the AST flag. 760*7c478bd9Sstevel@tonic-gate * 761*7c478bd9Sstevel@tonic-gate * Also check TP_EXITLWP, since this is used by fresh new LWPs 762*7c478bd9Sstevel@tonic-gate * through lwp_rtt(). That flag is set if the lwp_create(2) 763*7c478bd9Sstevel@tonic-gate * syscall failed after creating the LWP. 764*7c478bd9Sstevel@tonic-gate */ 765*7c478bd9Sstevel@tonic-gate if (ISHOLD(p) || (t->t_proc_flag & TP_EXITLWP)) 766*7c478bd9Sstevel@tonic-gate holdlwp(); 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate /* 769*7c478bd9Sstevel@tonic-gate * All code that sets signals and makes ISSIG_PENDING 770*7c478bd9Sstevel@tonic-gate * evaluate true must set t_sig_check afterwards. 771*7c478bd9Sstevel@tonic-gate */ 772*7c478bd9Sstevel@tonic-gate if (ISSIG_PENDING(t, lwp, p)) { 773*7c478bd9Sstevel@tonic-gate if (issig(FORREAL)) 774*7c478bd9Sstevel@tonic-gate psig(); 775*7c478bd9Sstevel@tonic-gate t->t_sig_check = 1; /* recheck next time */ 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate if (sigprof) { 779*7c478bd9Sstevel@tonic-gate realsigprof(code, error); 780*7c478bd9Sstevel@tonic-gate t->t_sig_check = 1; /* recheck next time */ 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate /* 784*7c478bd9Sstevel@tonic-gate * If a performance counter overflow interrupt was 785*7c478bd9Sstevel@tonic-gate * delivered *during* the syscall, then re-enable the 786*7c478bd9Sstevel@tonic-gate * AST so that we take a trip through trap() to cause 787*7c478bd9Sstevel@tonic-gate * the SIGEMT to be delivered. 788*7c478bd9Sstevel@tonic-gate */ 789*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) 790*7c478bd9Sstevel@tonic-gate aston(t); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* 793*7c478bd9Sstevel@tonic-gate * If an asynchronous hardware error is pending, turn AST flag 794*7c478bd9Sstevel@tonic-gate * back on. AST will be checked again before we return to user 795*7c478bd9Sstevel@tonic-gate * mode and we'll come back through trap() to handle the error. 796*7c478bd9Sstevel@tonic-gate */ 797*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) 798*7c478bd9Sstevel@tonic-gate aston(t); 799*7c478bd9Sstevel@tonic-gate } 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate /* 802*7c478bd9Sstevel@tonic-gate * Restore register window if a debugger modified it. 803*7c478bd9Sstevel@tonic-gate * Set up to perform a single-step if a debugger requested it. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 806*7c478bd9Sstevel@tonic-gate xregrestore(lwp, 1); 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate lwp->lwp_errno = 0; /* clear error for next time */ 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate #ifndef NPROBE 811*7c478bd9Sstevel@tonic-gate /* Kernel probe */ 812*7c478bd9Sstevel@tonic-gate if (tnf_tracing_active) { 813*7c478bd9Sstevel@tonic-gate TNF_PROBE_3(syscall_end, "syscall thread", /* CSTYLED */, 814*7c478bd9Sstevel@tonic-gate tnf_long, rval1, rval1, 815*7c478bd9Sstevel@tonic-gate tnf_long, rval2, rval2, 816*7c478bd9Sstevel@tonic-gate tnf_long, errno, (long)error); 817*7c478bd9Sstevel@tonic-gate repost = 1; 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate #endif /* NPROBE */ 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate /* 822*7c478bd9Sstevel@tonic-gate * Set state to LWP_USER here so preempt won't give us a kernel 823*7c478bd9Sstevel@tonic-gate * priority if it occurs after this point. Call CL_TRAPRET() to 824*7c478bd9Sstevel@tonic-gate * restore the user-level priority. 825*7c478bd9Sstevel@tonic-gate * 826*7c478bd9Sstevel@tonic-gate * It is important that no locks (other than spinlocks) be entered 827*7c478bd9Sstevel@tonic-gate * after this point before returning to user mode (unless lwp_state 828*7c478bd9Sstevel@tonic-gate * is set back to LWP_SYS). 829*7c478bd9Sstevel@tonic-gate * 830*7c478bd9Sstevel@tonic-gate * Sampled times past this point are charged to the user. 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate lwp->lwp_state = LWP_USER; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate if (t->t_trapret) { 835*7c478bd9Sstevel@tonic-gate t->t_trapret = 0; 836*7c478bd9Sstevel@tonic-gate thread_lock(t); 837*7c478bd9Sstevel@tonic-gate CL_TRAPRET(t); 838*7c478bd9Sstevel@tonic-gate thread_unlock(t); 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate if (CPU->cpu_runrun) 841*7c478bd9Sstevel@tonic-gate preempt(); 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * t_post_sys will be set if pcb_step is active. 845*7c478bd9Sstevel@tonic-gate */ 846*7c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_step != STEP_NONE) { 847*7c478bd9Sstevel@tonic-gate prdostep(); 848*7c478bd9Sstevel@tonic-gate repost = 1; 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate /* 852*7c478bd9Sstevel@tonic-gate * In case the args were copied to the lwp, reset the 853*7c478bd9Sstevel@tonic-gate * pointer so the next syscall will have the right lwp_ap pointer. 854*7c478bd9Sstevel@tonic-gate */ 855*7c478bd9Sstevel@tonic-gate lwp->lwp_ap = (long *)&rp->r_o0; 856*7c478bd9Sstevel@tonic-gate lwp->lwp_argsaved = 0; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* 859*7c478bd9Sstevel@tonic-gate * If there was a continuing reason for post-syscall processing, 860*7c478bd9Sstevel@tonic-gate * set the t_post_sys flag for the next system call. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate if (repost) 863*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * If there is a ustack registered for this lwp, and the stack rlimit 867*7c478bd9Sstevel@tonic-gate * has been altered, read in the ustack. If the saved stack rlimit 868*7c478bd9Sstevel@tonic-gate * matches the bounds of the ustack, update the ustack to reflect 869*7c478bd9Sstevel@tonic-gate * the new rlimit. If the new stack rlimit is RLIM_INFINITY, disable 870*7c478bd9Sstevel@tonic-gate * stack checking by setting the size to 0. 871*7c478bd9Sstevel@tonic-gate */ 872*7c478bd9Sstevel@tonic-gate if (lwp->lwp_ustack != 0 && lwp->lwp_old_stk_ctl != 0) { 873*7c478bd9Sstevel@tonic-gate rlim64_t new_size; 874*7c478bd9Sstevel@tonic-gate model_t model; 875*7c478bd9Sstevel@tonic-gate caddr_t top; 876*7c478bd9Sstevel@tonic-gate struct rlimit64 rl; 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 879*7c478bd9Sstevel@tonic-gate new_size = p->p_stk_ctl; 880*7c478bd9Sstevel@tonic-gate model = p->p_model; 881*7c478bd9Sstevel@tonic-gate top = p->p_usrstack; 882*7c478bd9Sstevel@tonic-gate (void) rctl_rlimit_get(rctlproc_legacy[RLIMIT_STACK], p, &rl); 883*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate if (rl.rlim_cur == RLIM64_INFINITY) 886*7c478bd9Sstevel@tonic-gate new_size = 0; 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_NATIVE) { 889*7c478bd9Sstevel@tonic-gate stack_t stk; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate if (copyin((stack_t *)lwp->lwp_ustack, &stk, 892*7c478bd9Sstevel@tonic-gate sizeof (stack_t)) == 0 && 893*7c478bd9Sstevel@tonic-gate (stk.ss_size == lwp->lwp_old_stk_ctl || 894*7c478bd9Sstevel@tonic-gate stk.ss_size == 0) && 895*7c478bd9Sstevel@tonic-gate stk.ss_sp == top - stk.ss_size) { 896*7c478bd9Sstevel@tonic-gate stk.ss_sp = (void *)((uintptr_t)stk.ss_sp + 897*7c478bd9Sstevel@tonic-gate stk.ss_size - new_size); 898*7c478bd9Sstevel@tonic-gate stk.ss_size = new_size; 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate (void) copyout(&stk, 901*7c478bd9Sstevel@tonic-gate (stack_t *)lwp->lwp_ustack, 902*7c478bd9Sstevel@tonic-gate sizeof (stack_t)); 903*7c478bd9Sstevel@tonic-gate } 904*7c478bd9Sstevel@tonic-gate } else { 905*7c478bd9Sstevel@tonic-gate stack32_t stk32; 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate if (copyin((stack32_t *)lwp->lwp_ustack, &stk32, 908*7c478bd9Sstevel@tonic-gate sizeof (stack32_t)) == 0 && 909*7c478bd9Sstevel@tonic-gate (stk32.ss_size == lwp->lwp_old_stk_ctl || 910*7c478bd9Sstevel@tonic-gate stk32.ss_size == 0) && 911*7c478bd9Sstevel@tonic-gate stk32.ss_sp == (caddr32_t)(top - stk32.ss_size)) { 912*7c478bd9Sstevel@tonic-gate stk32.ss_sp += stk32.ss_size - new_size; 913*7c478bd9Sstevel@tonic-gate stk32.ss_size = new_size; 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate (void) copyout(&stk32, 916*7c478bd9Sstevel@tonic-gate (stack32_t *)lwp->lwp_ustack, 917*7c478bd9Sstevel@tonic-gate sizeof (stack32_t)); 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate lwp->lwp_old_stk_ctl = 0; 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate syscall_mstate(LMS_SYSTEM, LMS_USER); 925*7c478bd9Sstevel@tonic-gate } 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate /* 928*7c478bd9Sstevel@tonic-gate * Call a system call which takes a pointer to the user args struct and 929*7c478bd9Sstevel@tonic-gate * a pointer to the return values. This is a bit slower than the standard 930*7c478bd9Sstevel@tonic-gate * C arg-passing method in some cases. 931*7c478bd9Sstevel@tonic-gate */ 932*7c478bd9Sstevel@tonic-gate int64_t 933*7c478bd9Sstevel@tonic-gate syscall_ap() 934*7c478bd9Sstevel@tonic-gate { 935*7c478bd9Sstevel@tonic-gate uint_t error; 936*7c478bd9Sstevel@tonic-gate struct sysent *callp; 937*7c478bd9Sstevel@tonic-gate rval_t rval; 938*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 939*7c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate callp = LWP_GETSYSENT(lwp) + curthread->t_sysnum; 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* 944*7c478bd9Sstevel@tonic-gate * If the arguments don't fit in registers %o0 - o5, make sure they 945*7c478bd9Sstevel@tonic-gate * have been copied to the lwp_arg array. 946*7c478bd9Sstevel@tonic-gate */ 947*7c478bd9Sstevel@tonic-gate if (callp->sy_narg > 6 && save_syscall_args()) 948*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(EFAULT)); 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate rval.r_val1 = 0; 951*7c478bd9Sstevel@tonic-gate rval.r_val2 = (int)rp->r_o1; 952*7c478bd9Sstevel@tonic-gate lwp->lwp_error = 0; /* for old drivers */ 953*7c478bd9Sstevel@tonic-gate error = (*(callp->sy_call))(lwp->lwp_ap, &rval); 954*7c478bd9Sstevel@tonic-gate if (error) 955*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 956*7c478bd9Sstevel@tonic-gate return (rval.r_vals); 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate /* 960*7c478bd9Sstevel@tonic-gate * Load system call module. 961*7c478bd9Sstevel@tonic-gate * Returns with pointer to held read lock for module. 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate static krwlock_t * 964*7c478bd9Sstevel@tonic-gate lock_syscall(struct sysent *table, uint_t code) 965*7c478bd9Sstevel@tonic-gate { 966*7c478bd9Sstevel@tonic-gate krwlock_t *module_lock; 967*7c478bd9Sstevel@tonic-gate struct modctl *modp; 968*7c478bd9Sstevel@tonic-gate int id; 969*7c478bd9Sstevel@tonic-gate struct sysent *callp; 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate module_lock = table[code].sy_lock; 972*7c478bd9Sstevel@tonic-gate callp = &table[code]; 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * Optimization to only call modload if we don't have a loaded 976*7c478bd9Sstevel@tonic-gate * syscall. 977*7c478bd9Sstevel@tonic-gate */ 978*7c478bd9Sstevel@tonic-gate rw_enter(module_lock, RW_READER); 979*7c478bd9Sstevel@tonic-gate if (LOADED_SYSCALL(callp)) 980*7c478bd9Sstevel@tonic-gate return (module_lock); 981*7c478bd9Sstevel@tonic-gate rw_exit(module_lock); 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate for (;;) { 984*7c478bd9Sstevel@tonic-gate if ((id = modload("sys", syscallnames[code])) == -1) 985*7c478bd9Sstevel@tonic-gate break; 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate /* 988*7c478bd9Sstevel@tonic-gate * If we loaded successfully at least once, the modctl 989*7c478bd9Sstevel@tonic-gate * will still be valid, so we try to grab it by filename. 990*7c478bd9Sstevel@tonic-gate * If this call fails, it's because the mod_filename 991*7c478bd9Sstevel@tonic-gate * was changed after the call to modload() (mod_hold_by_name() 992*7c478bd9Sstevel@tonic-gate * is the likely culprit). We can safely just take 993*7c478bd9Sstevel@tonic-gate * another lap if this is the case; the modload() will 994*7c478bd9Sstevel@tonic-gate * change the mod_filename back to one by which we can 995*7c478bd9Sstevel@tonic-gate * find the modctl. 996*7c478bd9Sstevel@tonic-gate */ 997*7c478bd9Sstevel@tonic-gate modp = mod_find_by_filename("sys", syscallnames[code]); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate if (modp == NULL) 1000*7c478bd9Sstevel@tonic-gate continue; 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate if (!modp->mod_installed) { 1005*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 1006*7c478bd9Sstevel@tonic-gate continue; 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate break; 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate 1011*7c478bd9Sstevel@tonic-gate rw_enter(module_lock, RW_READER); 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate if (id != -1) 1014*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate return (module_lock); 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate /* 1020*7c478bd9Sstevel@tonic-gate * Loadable syscall support. 1021*7c478bd9Sstevel@tonic-gate * If needed, load the module, then reserve it by holding a read 1022*7c478bd9Sstevel@tonic-gate * lock for the duration of the call. 1023*7c478bd9Sstevel@tonic-gate * Later, if the syscall is not unloadable, it could patch the vector. 1024*7c478bd9Sstevel@tonic-gate */ 1025*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1026*7c478bd9Sstevel@tonic-gate int64_t 1027*7c478bd9Sstevel@tonic-gate loadable_syscall( 1028*7c478bd9Sstevel@tonic-gate long a0, long a1, long a2, long a3, 1029*7c478bd9Sstevel@tonic-gate long a4, long a5, long a6, long a7) 1030*7c478bd9Sstevel@tonic-gate { 1031*7c478bd9Sstevel@tonic-gate int64_t rval; 1032*7c478bd9Sstevel@tonic-gate struct sysent *callp; 1033*7c478bd9Sstevel@tonic-gate struct sysent *se = LWP_GETSYSENT(ttolwp(curthread)); 1034*7c478bd9Sstevel@tonic-gate krwlock_t *module_lock; 1035*7c478bd9Sstevel@tonic-gate int code; 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate code = curthread->t_sysnum; 1038*7c478bd9Sstevel@tonic-gate callp = se + code; 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * Try to autoload the system call if necessary. 1042*7c478bd9Sstevel@tonic-gate */ 1043*7c478bd9Sstevel@tonic-gate module_lock = lock_syscall(se, code); 1044*7c478bd9Sstevel@tonic-gate THREAD_KPRI_RELEASE(); /* drop priority given by rw_enter */ 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * we've locked either the loaded syscall or nosys 1048*7c478bd9Sstevel@tonic-gate */ 1049*7c478bd9Sstevel@tonic-gate if (callp->sy_flags & SE_ARGC) { 1050*7c478bd9Sstevel@tonic-gate int64_t (*sy_call)(); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate sy_call = (int64_t (*)())callp->sy_call; 1053*7c478bd9Sstevel@tonic-gate rval = (*sy_call)(a0, a1, a2, a3, a4, a5); 1054*7c478bd9Sstevel@tonic-gate } else { 1055*7c478bd9Sstevel@tonic-gate rval = syscall_ap(); 1056*7c478bd9Sstevel@tonic-gate } 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate THREAD_KPRI_REQUEST(); /* regain priority from read lock */ 1059*7c478bd9Sstevel@tonic-gate rw_exit(module_lock); 1060*7c478bd9Sstevel@tonic-gate return (rval); 1061*7c478bd9Sstevel@tonic-gate } 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate /* 1064*7c478bd9Sstevel@tonic-gate * Handle indirect system calls. 1065*7c478bd9Sstevel@tonic-gate * This interface should be deprecated. The library can handle 1066*7c478bd9Sstevel@tonic-gate * this more efficiently, but keep this implementation for old binaries. 1067*7c478bd9Sstevel@tonic-gate * 1068*7c478bd9Sstevel@tonic-gate * XX64 Needs some work. 1069*7c478bd9Sstevel@tonic-gate */ 1070*7c478bd9Sstevel@tonic-gate int64_t 1071*7c478bd9Sstevel@tonic-gate indir(int code, long a0, long a1, long a2, long a3, long a4) 1072*7c478bd9Sstevel@tonic-gate { 1073*7c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1074*7c478bd9Sstevel@tonic-gate struct sysent *callp; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate if (code <= 0 || code >= NSYSCALL) 1077*7c478bd9Sstevel@tonic-gate return (nosys()); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate ASSERT(lwp->lwp_ap != NULL); 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate curthread->t_sysnum = code; 1082*7c478bd9Sstevel@tonic-gate callp = LWP_GETSYSENT(lwp) + code; 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate /* 1085*7c478bd9Sstevel@tonic-gate * Handle argument setup, unless already done in pre_syscall(). 1086*7c478bd9Sstevel@tonic-gate */ 1087*7c478bd9Sstevel@tonic-gate if (callp->sy_narg > 5) { 1088*7c478bd9Sstevel@tonic-gate if (save_syscall_args()) /* move args to LWP array */ 1089*7c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(EFAULT)); 1090*7c478bd9Sstevel@tonic-gate } else if (!lwp->lwp_argsaved) { 1091*7c478bd9Sstevel@tonic-gate long *ap; 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate ap = lwp->lwp_ap; /* args haven't been saved */ 1094*7c478bd9Sstevel@tonic-gate lwp->lwp_ap = ap + 1; /* advance arg pointer */ 1095*7c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; /* so lwp_ap will be reset */ 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate return ((*callp->sy_callc)(a0, a1, a2, a3, a4, lwp->lwp_arg[5])); 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate /* 1101*7c478bd9Sstevel@tonic-gate * set_errno - set an error return from the current system call. 1102*7c478bd9Sstevel@tonic-gate * This could be a macro. 1103*7c478bd9Sstevel@tonic-gate * This returns the value it is passed, so that the caller can 1104*7c478bd9Sstevel@tonic-gate * use tail-recursion-elimination and do return (set_errno(ERRNO)); 1105*7c478bd9Sstevel@tonic-gate */ 1106*7c478bd9Sstevel@tonic-gate uint_t 1107*7c478bd9Sstevel@tonic-gate set_errno(uint_t error) 1108*7c478bd9Sstevel@tonic-gate { 1109*7c478bd9Sstevel@tonic-gate ASSERT(error != 0); /* must not be used to clear errno */ 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; /* have post_syscall do error return */ 1112*7c478bd9Sstevel@tonic-gate return (ttolwp(curthread)->lwp_errno = error); 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * set_proc_pre_sys - Set pre-syscall processing for entire process. 1117*7c478bd9Sstevel@tonic-gate */ 1118*7c478bd9Sstevel@tonic-gate void 1119*7c478bd9Sstevel@tonic-gate set_proc_pre_sys(proc_t *p) 1120*7c478bd9Sstevel@tonic-gate { 1121*7c478bd9Sstevel@tonic-gate kthread_t *t; 1122*7c478bd9Sstevel@tonic-gate kthread_t *first; 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate t = first = p->p_tlist; 1127*7c478bd9Sstevel@tonic-gate do { 1128*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; 1129*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != first); 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate /* 1133*7c478bd9Sstevel@tonic-gate * set_proc_post_sys - Set post-syscall processing for entire process. 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate void 1136*7c478bd9Sstevel@tonic-gate set_proc_post_sys(proc_t *p) 1137*7c478bd9Sstevel@tonic-gate { 1138*7c478bd9Sstevel@tonic-gate kthread_t *t; 1139*7c478bd9Sstevel@tonic-gate kthread_t *first; 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate t = first = p->p_tlist; 1144*7c478bd9Sstevel@tonic-gate do { 1145*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; 1146*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != first); 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate /* 1150*7c478bd9Sstevel@tonic-gate * set_proc_sys - Set pre- and post-syscall processing for entire process. 1151*7c478bd9Sstevel@tonic-gate */ 1152*7c478bd9Sstevel@tonic-gate void 1153*7c478bd9Sstevel@tonic-gate set_proc_sys(proc_t *p) 1154*7c478bd9Sstevel@tonic-gate { 1155*7c478bd9Sstevel@tonic-gate kthread_t *t; 1156*7c478bd9Sstevel@tonic-gate kthread_t *first; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate t = first = p->p_tlist; 1161*7c478bd9Sstevel@tonic-gate do { 1162*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; 1163*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; 1164*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != first); 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate /* 1168*7c478bd9Sstevel@tonic-gate * set_all_proc_sys - set pre- and post-syscall processing flags for all 1169*7c478bd9Sstevel@tonic-gate * user processes. 1170*7c478bd9Sstevel@tonic-gate * 1171*7c478bd9Sstevel@tonic-gate * This is needed when auditing, tracing, or other facilities which affect 1172*7c478bd9Sstevel@tonic-gate * all processes are turned on. 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate void 1175*7c478bd9Sstevel@tonic-gate set_all_proc_sys() 1176*7c478bd9Sstevel@tonic-gate { 1177*7c478bd9Sstevel@tonic-gate kthread_t *t; 1178*7c478bd9Sstevel@tonic-gate kthread_t *first; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 1181*7c478bd9Sstevel@tonic-gate t = first = curthread; 1182*7c478bd9Sstevel@tonic-gate do { 1183*7c478bd9Sstevel@tonic-gate t->t_pre_sys = 1; 1184*7c478bd9Sstevel@tonic-gate t->t_post_sys = 1; 1185*7c478bd9Sstevel@tonic-gate } while ((t = t->t_next) != first); 1186*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate /* 1190*7c478bd9Sstevel@tonic-gate * set_proc_ast - Set asynchronous service trap (AST) flag for all 1191*7c478bd9Sstevel@tonic-gate * threads in process. 1192*7c478bd9Sstevel@tonic-gate */ 1193*7c478bd9Sstevel@tonic-gate void 1194*7c478bd9Sstevel@tonic-gate set_proc_ast(proc_t *p) 1195*7c478bd9Sstevel@tonic-gate { 1196*7c478bd9Sstevel@tonic-gate kthread_t *t; 1197*7c478bd9Sstevel@tonic-gate kthread_t *first; 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate t = first = p->p_tlist; 1202*7c478bd9Sstevel@tonic-gate do { 1203*7c478bd9Sstevel@tonic-gate aston(t); 1204*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != first); 1205*7c478bd9Sstevel@tonic-gate } 1206