예제 #1
0
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);
}
예제 #2
0
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);
}