int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { struct proc *p; struct trapframe *frame; caddr_t params; int error, n; p = td->td_proc; frame = td->td_frame; sa->code = frame->fixreg[0]; params = (caddr_t)(frame->fixreg + FIRSTARG); n = NARGREG; if (sa->code == SYS_syscall) { /* * code is first argument, * followed by actual args. */ sa->code = *(u_int *) params; params += sizeof(register_t); n -= 1; } else if (sa->code == SYS___syscall) { /* * Like syscall, but code is a quad, * so as to maintain quad alignment * for the rest of the args. */ params += sizeof(register_t); sa->code = *(u_int *) params; params += sizeof(register_t); n -= 2; } if (p->p_sysent->sv_mask) sa->code &= p->p_sysent->sv_mask; if (sa->code >= p->p_sysent->sv_size) sa->callp = &p->p_sysent->sv_table[0]; else sa->callp = &p->p_sysent->sv_table[sa->code]; sa->narg = sa->callp->sy_narg; bcopy(params, sa->args, n * sizeof(register_t)); if (sa->narg > n) { error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n, (sa->narg - n) * sizeof(register_t)); } else error = 0; if (error == 0) { td->td_retval[0] = 0; td->td_retval[1] = frame->fixreg[FIRSTARG + 1]; } return (error); }
void EMULNAME(syscall)(struct trapframe *tf) { struct lwp * const l = curlwp; struct proc * const p = l->l_proc; const struct sysent *callp; size_t argsize; register_t code; register_t realcode; register_t *params, rval[2]; register_t args[10]; int error; int n; LWP_CACHE_CREDS(l, p); curcpu()->ci_ev_scalls.ev_count++; code = tf->tf_fixreg[0]; params = tf->tf_fixreg + FIRSTARG; n = NARGREG; realcode = code; { switch (code) { case EMULNAMEU(SYS_syscall): /* * code is first argument, * followed by actual args. */ code = *params++; n -= 1; break; #if !defined(COMPAT_LINUX) case EMULNAMEU(SYS___syscall): params++; code = *params++; n -= 2; break; #endif default: break; } code &= EMULNAMEU(SYS_NSYSENT) - 1; callp = p->p_emul->e_sysent + code; realcode = code; } argsize = callp->sy_argsize; if (argsize > n * sizeof(register_t)) { memcpy(args, params, n * sizeof(register_t)); error = copyin(MOREARGS(tf->tf_fixreg[1]), args + n, argsize - n * sizeof(register_t)); if (error) goto bad; params = args; } error = sy_invoke(callp, l, params, rval, code); if (__predict_true(error == 0)) { tf->tf_fixreg[FIRSTARG] = rval[0]; tf->tf_fixreg[FIRSTARG + 1] = rval[1]; tf->tf_cr &= ~0x10000000; } else { switch (error) { case ERESTART: /* * Set user's pc back to redo the system call. */ tf->tf_srr0 -= 4; break; case EJUSTRETURN: /* nothing to do */ break; default: bad: if (p->p_emul->e_errno) error = p->p_emul->e_errno[error]; tf->tf_fixreg[FIRSTARG] = error; tf->tf_cr |= 0x10000000; break; } } userret(l, tf); }