Re-factor syscall, and make it use syscall_{plain,fancy}.

This commit is contained in:
christos 2005-07-10 00:50:16 +00:00
parent f1461c7e8a
commit 1e568eda97
9 changed files with 576 additions and 479 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.sparc64,v 1.95 2004/09/14 16:51:58 jdolecek Exp $
# $NetBSD: files.sparc64,v 1.96 2005/07/10 00:50:16 christos Exp $
# @(#)files.sparc64 8.1 (Berkeley) 7/19/93
# sparc64-specific configuration info
@ -186,6 +186,7 @@ file arch/sparc/sparc/openfirm.c
file arch/sparc64/sparc64/ofw_machdep.c
file arch/sparc64/sparc64/pmap.c
file arch/sparc64/sparc64/sys_machdep.c
file arch/sparc64/sparc64/syscall.c
file arch/sparc64/sparc64/trap.c
file arch/sparc64/sparc64/vm_machdep.c
file arch/sparc64/sparc64/ipifuncs.c multiprocessor

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.5 2005/01/02 00:14:46 christos Exp $ */
/* $NetBSD: proc.h,v 1.6 2005/07/10 00:50:16 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@ -52,11 +52,13 @@ struct mdlwp {
/*
* Machine-dependent part of the proc structure for SPARC.
*/
/* LINTED 0 sized structure */
struct mdproc {
void (*md_syscall)(struct trapframe *, register_t, register_t);
};
/* md_flags */
#define MDP_FIXALIGN 0x1 /* Fix unaligned memory accesses */
#define netbsd32_syscall_intern syscall_intern
#endif /* _SPARC64_PROC_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: svr4_32_machdep.h,v 1.4 2003/01/18 06:55:22 thorpej Exp $ */
/* $NetBSD: svr4_32_machdep.h,v 1.5 2005/07/10 00:50:16 christos Exp $ */
/*-
* Copyright (c) 1994 The NetBSD Foundation, Inc.
@ -91,6 +91,8 @@ typedef struct svr4_32_mcontext {
struct svr4_32_ucontext;
#define svr4_32_syscall_intern syscall_intern
int svr4_32_trap __P((int, struct lwp *));
#endif /* !_SPARC_SVR4_32_MACHDEP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: svr4_machdep.h,v 1.8 2003/01/18 06:55:22 thorpej Exp $ */
/* $NetBSD: svr4_machdep.h,v 1.9 2005/07/10 00:50:16 christos Exp $ */
/*-
* Copyright (c) 1994 The NetBSD Foundation, Inc.
@ -144,6 +144,8 @@ typedef struct svr4_mcontext {
struct svr4_ucontext;
#define svr4_syscall_intern syscall_intern
int svr4_trap __P((int, struct lwp *));
#endif /* !_SPARC_SVR4_MACHDEP_H_ */

View File

@ -1,3 +1,5 @@
/* $NetBSD: types.h,v 1.22 2002/07/20 11:52:22 mrg Exp $ */
/* $NetBSD: types.h,v 1.23 2005/07/10 00:50:16 christos Exp $ */
#include <sparc/types.h>
#define __HAVE_SYSCALL_INTERN

View File

@ -1,4 +1,4 @@
# $NetBSD: genassym.cf,v 1.37 2004/12/03 02:04:00 chs Exp $
# $NetBSD: genassym.cf,v 1.38 2005/07/10 00:50:16 christos Exp $
#
# Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -134,6 +134,7 @@ define LSRUN LSRUN
define LSONPROC LSONPROC
# proc fields and values
define P_MD_SYSCALL offsetof(struct proc, p_md.md_syscall)
define P_STAT offsetof(struct proc, p_stat)
define P_VMSPACE offsetof(struct proc, p_vmspace)
define P_PID offsetof(struct proc, p_pid)

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.205 2005/05/31 00:45:05 chs Exp $ */
/* $NetBSD: locore.s,v 1.206 2005/07/10 00:50:16 christos Exp $ */
/*
* Copyright (c) 1996-2002 Eduardo Horvath
@ -3915,7 +3915,11 @@ syscall_setup:
clr %g4
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI
call _C_LABEL(syscall) ! syscall(&tf, code, pc)
set CURLWP, %l1
LDPTR [%l1], %l1
LDPTR [%l1 + L_PROC], %l1 ! now %l1 points to p
LDPTR [%l1 + P_MD_SYSCALL], %l1
call %l1
wrpr %g0, PSTATE_INTR, %pstate ! turn on interrupts
/* see `proc_trampoline' for the reason for this label */

View File

@ -0,0 +1,550 @@
/* $NetBSD: syscall.c,v 1.1 2005/07/10 00:50:16 christos Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved.
* Copyright (c) 1996
* The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
* This product includes software developed by Harvard University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* This product includes software developed by Harvard University.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)trap.c 8.4 (Berkeley) 9/23/93
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.1 2005/07/10 00:50:16 christos Exp $");
#define NEW_FPSTATE
#include "opt_syscall_debug.h"
#include "opt_ktrace.h"
#include "opt_systrace.h"
#include "opt_compat_svr4.h"
#include "opt_compat_netbsd32.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/sa.h>
#include <sys/savar.h>
#include <sys/user.h>
#include <sys/signal.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef SYSTRACE
#include <sys/systrace.h>
#endif
#include <sys/syscall.h>
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/trap.h>
#include <machine/instr.h>
#include <machine/pmap.h>
#include <machine/frame.h>
#include <machine/userret.h>
#include <sparc/fpu/fpu_extern.h>
#include <sparc64/sparc64/cache.h>
#ifndef offsetof
#define offsetof(s, f) ((size_t)&((s *)0)->f)
#endif
#define MAXARGS 8
union args {
register32_t i[MAXARGS];
register64_t l[MAXARGS];
register_t r[MAXARGS];
};
static __inline int handle_old(struct trapframe64 *, register_t *);
static __inline int getargs(struct trapframe64 *, register_t, int,
const struct sysent **, union args *);
void syscall_plain(struct trapframe64 *, register_t, register_t);
void syscall_fancy(struct trapframe64 *, register_t, register_t);
/*
* Handle old style system calls.
*/
static __inline int
handle_old(struct trapframe64 *tf, register_t *code)
{
int new = *code & (SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
*code &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
if (new)
tf->tf_pc = tf->tf_global[new & SYSCALL_G2RFLAG ? 2 : 7];
else
tf->tf_pc = tf->tf_npc;
return new;
}
/*
* The first six system call arguments are in the six %o registers.
* Any arguments beyond that are in the `argument extension' area
* of the user's stack frame (see <machine/frame.h>).
*
* Check for ``special'' codes that alter this, namely syscall and
* __syscall. The latter takes a quad syscall number, so that other
* arguments are at their natural alignments. Adjust the number
* of ``easy'' arguments as appropriate; we will copy the hard
* ones later as needed.
*/
static __inline int
getargs(struct trapframe64 *tf, register_t code, int nsys,
const struct sysent **callp, union args *args)
{
int64_t *ap = &tf->tf_out[0];
int i, error, nap = 6;
int s64 = tf->tf_out[6] & 1L; /* Do we have a 64-bit stack? */
switch (code) {
case SYS_syscall:
code = *ap++;
nap--;
break;
case SYS___syscall:
if (s64) {
/* longs *are* quadwords */
code = ap[0];
ap += 1;
nap -= 1;
} else {
code = ap[_QUAD_LOWWORD];
ap += 2;
nap -= 2;
}
break;
}
if (code < 0 || code >= nsys)
return ENOSYS;
*callp += code;
if (s64) {
/* 64-bit stack -- not really supported on 32-bit kernels */
register64_t *argp;
i = (*callp)->sy_narg;
if (__predict_false(i > nap)) { /* usually false */
void *pos = (char *)(u_long)tf->tf_out[6] + BIAS +
offsetof(struct frame64, fr_argx);
#ifdef DIAGNOSTIC
KASSERT(i <= MAXARGS);
#endif
/* Read the whole block in */
error = copyin(pos, &args->l[nap],
(i - nap) * sizeof(*argp));
if (error)
return error;
i = nap;
}
for (argp = args->l; i--;)
*argp++ = *ap++;
} else {
register32_t *argp;
i = (long)(*callp)->sy_argsize / sizeof(register32_t);
if (__predict_false(i > nap)) { /* usually false */
void *pos = (char *)(u_long)tf->tf_out[6] +
offsetof(struct frame32, fr_argx);
#ifdef DIAGNOSTIC
KASSERT(i <= MAXARGS);
#endif
/* Read the whole block in */
error = copyin(pos, &args->i[nap],
(i - nap) * sizeof(*argp));
if (error)
return error;
i = nap;
}
/* Need to convert from int64 to int32 or we lose */
for (argp = args->i; i--;)
*argp++ = *ap++;
}
return 0;
}
void
syscall_intern(struct proc *p)
{
#ifdef KTRACE
if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
p->p_md.md_syscall = syscall_fancy;
return;
}
#endif
#ifdef SYSTRACE
if (ISSET(p->p_flag, P_SYSTRACE)) {
p->p_md.md_syscall = syscall_fancy;
return;
}
#endif
p->p_md.md_syscall = syscall_plain;
}
/*
* System calls. `pc' is just a copy of tf->tf_pc.
*
* Note that the things labelled `out' registers in the trapframe were the
* `in' registers within the syscall trap code (because of the automatic
* `save' effect of each trap). They are, however, the %o registers of the
* thing that made the system call, and are named that way here.
*
* 32-bit system calls on a 64-bit system are a problem. Each system call
* argument is stored in the smaller of the argument's true size or a
* `register_t'. Now on a 64-bit machine all normal types can be stored in a
* `register_t'. (The only exceptions would be 128-bit `quad's or 128-bit
* extended precision floating point values, which we don't support.) For
* 32-bit syscalls, 64-bit integers like `off_t's, double precision floating
* point values, and several other types cannot fit in a 32-bit `register_t'.
* These will require reading in two `register_t' values for one argument.
*
* In order to calculate the true size of the arguments and therefore whether
* any argument needs to be split into two slots, the system call args
* structure needs to be built with the appropriately sized register_t.
* Otherwise the emul needs to do some magic to split oversized arguments.
*
* We can handle most this stuff for normal syscalls by using either a 32-bit
* or 64-bit array of `register_t' arguments. Unfortunately ktrace always
* expects arguments to be `register_t's, so it loses badly. What's worse,
* ktrace may need to do size translations to massage the argument array
* appropriately according to the emulation that is doing the ktrace.
*
*/
void
syscall_plain(struct trapframe64 *tf, register_t code, register_t pc)
{
const struct sysent *callp;
struct lwp *l = curlwp;
union args args;
#ifdef SYSCALL_DEBUG
union args *ap;
#ifdef __arch64__
union args args64;
int i;
ap = &args64;
#else
ap = &args;
#endif
#endif
struct proc *p = l->l_proc;
int error, new, nsys;
register_t rval[2];
u_quad_t sticks;
vaddr_t opc, onpc;
uvmexp.syscalls++;
sticks = p->p_sticks;
l->l_md.md_tf = tf;
callp = p->p_emul->e_sysent;
nsys = p->p_emul->e_nsysent;
/*
* save pc/npc in case of ERESTART
* adjust pc/npc to new values
*/
opc = tf->tf_pc;
onpc = tf->tf_npc;
new = handle_old(tf, &code);
tf->tf_npc = tf->tf_pc + 4;
if ((error = getargs(tf, code, nsys, &callp, &args)) != 0)
goto bad;
#ifdef SYSCALL_DEBUG
#ifdef __arch64__
for (i = 0; i < callp->sy_narg; i++)
args64.l[i] = args.i[i];
#endif
scdebug_call(l, code, ap->r);
#endif /* SYSCALL_DEBUG */
rval[0] = 0;
rval[1] = tf->tf_out[1];
/* Lock the kernel if the syscall isn't MP-safe. */
if (callp->sy_flags & SYCALL_MPSAFE) {
error = (*callp->sy_call)(l, &args, rval);
} else {
KERNEL_PROC_LOCK(l);
error = (*callp->sy_call)(l, &args, rval);
KERNEL_PROC_UNLOCK(l);
}
switch (error) {
case 0:
/* Note: fork() does not return here in the child */
tf->tf_out[0] = rval[0];
tf->tf_out[1] = rval[1];
if (!new)
/* old system call convention: clear C on success */
tf->tf_tstate &= ~(((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* success */
break;
case ERESTART:
tf->tf_pc = opc;
tf->tf_npc = onpc;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
bad:
if (p->p_emul->e_errno)
error = p->p_emul->e_errno[error];
tf->tf_out[0] = error;
tf->tf_tstate |= (((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* fail */
tf->tf_pc = onpc;
tf->tf_npc = tf->tf_pc + 4;
break;
}
#ifdef SYSCALL_DEBUG
scdebug_ret(l, code, error, rval);
#endif /* SYSCALL_DEBUG */
userret(l, pc, sticks);
share_fpu(l, tf);
}
void
syscall_fancy(struct trapframe64 *tf, register_t code, register_t pc)
{
const struct sysent *callp;
struct lwp *l = curlwp;
union args args, *ap;
#ifdef __arch64__
union args args64;
int i;
ap = &args64;
#else
ap = &args;
#endif
struct proc *p = l->l_proc;
int error, new, nsys;
register_t rval[2];
u_quad_t sticks;
vaddr_t opc, onpc;
uvmexp.syscalls++;
sticks = p->p_sticks;
l->l_md.md_tf = tf;
callp = p->p_emul->e_sysent;
nsys = p->p_emul->e_nsysent;
/*
* save pc/npc in case of ERESTART
* adjust pc/npc to new values
*/
opc = tf->tf_pc;
onpc = tf->tf_npc;
new = handle_old(tf, &code);
tf->tf_npc = tf->tf_pc + 4;
if ((error = getargs(tf, code, nsys, &callp, &args)) != 0)
goto bad;
#ifdef __arch64__
for (i = 0; i < callp->sy_narg; i++)
args64.l[i] = args.i[i];
#endif
KERNEL_PROC_LOCK(l);
if ((error = trace_enter(l, code, code, NULL, ap->r)) != 0) {
KERNEL_PROC_UNLOCK(l);
goto out;
}
rval[0] = 0;
rval[1] = tf->tf_out[1];
if (callp->sy_flags & SYCALL_MPSAFE) {
KERNEL_PROC_UNLOCK(l);
error = (*callp->sy_call)(l, &args, rval);
} else {
error = (*callp->sy_call)(l, &args, rval);
KERNEL_PROC_UNLOCK(l);
}
out:
switch (error) {
case 0:
/* Note: fork() does not return here in the child */
tf->tf_out[0] = rval[0];
tf->tf_out[1] = rval[1];
if (!new)
/* old system call convention: clear C on success */
tf->tf_tstate &= ~(((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* success */
break;
case ERESTART:
tf->tf_pc = opc;
tf->tf_npc = onpc;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
bad:
if (p->p_emul->e_errno)
error = p->p_emul->e_errno[error];
tf->tf_out[0] = error;
tf->tf_tstate |= (((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* fail */
tf->tf_pc = onpc;
tf->tf_npc = tf->tf_pc + 4;
break;
}
trace_exit(l, code, ap->r, rval, error);
userret(l, pc, sticks);
share_fpu(l, tf);
}
/*
* Process the tail end of a fork() for the child.
*/
void
child_return(arg)
void *arg;
{
struct lwp *l = arg;
#ifdef KTRACE
struct proc *p = l->l_proc;
#endif
/*
* Return values in the frame set by cpu_lwp_fork().
*/
KERNEL_PROC_UNLOCK(l);
userret(l, l->l_md.md_tf->tf_pc, 0);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p,
(p->p_flag & P_PPWAIT) ? SYS_vfork : SYS_fork, 0, 0);
#endif
}
/*
* Start a new LWP
*/
void
startlwp(arg)
void *arg;
{
int err;
ucontext_t *uc = arg;
struct lwp *l = curlwp;
err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
#if DIAGNOSTIC
if (err) {
printf("Error %d from cpu_setmcontext.", err);
}
#endif
pool_put(&lwp_uc_pool, uc);
KERNEL_PROC_UNLOCK(l);
userret(l, 0, 0);
}
void
upcallret(struct lwp *l)
{
KERNEL_PROC_UNLOCK(l);
userret(l, 0, 0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.120 2005/05/31 00:53:02 christos Exp $ */
/* $NetBSD: trap.c,v 1.121 2005/07/10 00:50:16 christos Exp $ */
/*
* Copyright (c) 1996-2002 Eduardo Horvath. All rights reserved.
@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.120 2005/05/31 00:53:02 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.121 2005/07/10 00:50:16 christos Exp $");
#define NEW_FPSTATE
@ -69,7 +69,6 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.120 2005/05/31 00:53:02 christos Exp $");
#include <sys/ras.h>
#include <sys/sa.h>
#include <sys/savar.h>
#include <sys/userret.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/resource.h>
@ -77,12 +76,6 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.120 2005/05/31 00:53:02 christos Exp $");
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/syslog.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef SYSTRACE
#include <sys/systrace.h>
#endif
#include <uvm/uvm_extern.h>
@ -91,6 +84,7 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.120 2005/05/31 00:53:02 christos Exp $");
#include <machine/trap.h>
#include <machine/instr.h>
#include <machine/pmap.h>
#include <machine/userret.h>
#ifdef DDB
#include <machine/db_machdep.h>
@ -379,8 +373,6 @@ const char *trap_type[] = {
#define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type)
static __inline void share_fpu __P((struct lwp *, struct trapframe64 *));
static __inline void userret __P((struct lwp *, int, u_quad_t));
void trap __P((struct trapframe64 *tf, unsigned type, vaddr_t pc, long tstate));
void data_access_fault __P((struct trapframe64 *tf, unsigned type, vaddr_t pc,
@ -391,7 +383,6 @@ void text_access_fault __P((struct trapframe64 *tf, unsigned type,
vaddr_t pc, u_long sfsr));
void text_access_error __P((struct trapframe64 *tf, unsigned type,
vaddr_t pc, u_long sfsr, vaddr_t afva, u_long afsr));
void syscall __P((struct trapframe64 *, register_t code, register_t pc));
#ifdef DEBUG
void print_trapframe __P((struct trapframe64 *));
@ -432,55 +423,6 @@ print_trapframe(tf)
}
#endif
/*
* Define the code needed before returning to user mode, for
* trap, mem_access_fault, and syscall.
*/
static __inline void
userret(l, pc, oticks)
struct lwp *l;
int pc;
u_quad_t oticks;
{
struct proc *p = l->l_proc;
mi_userret(l);
if (want_ast) {
want_ast = 0;
if (p->p_flag & P_OWEUPC) {
p->p_flag &= ~P_OWEUPC;
ADDUPROF(p);
}
}
/*
* If profiling, charge recent system time to the trapped pc.
*/
if (p->p_flag & P_PROFIL)
addupc_task(p, pc, (int)(p->p_sticks - oticks));
curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
}
/*
* If someone stole the FPU while we were away, do not enable it
* on return. This is not done in userret() above as it must follow
* the ktrsysret() in syscall(). Actually, it is likely that the
* ktrsysret should occur before the call to userret.
*
* Oh, and don't touch the FPU bit if we're returning to the kernel.
*/
static __inline void
share_fpu(l, tf)
struct lwp *l;
struct trapframe64 *tf;
{
if (!(tf->tf_tstate & (PSTATE_PRIV << TSTATE_PSTATE_SHIFT)) &&
fplwp != l)
tf->tf_tstate &= ~(PSTATE_PEF << TSTATE_PSTATE_SHIFT);
}
/*
* Called from locore.s trap handling, for non-MMU-related traps.
* (MMU-related traps go through mem_access_fault, below.)
@ -1802,412 +1744,3 @@ out:
}
#endif
}
/*
* System calls. `pc' is just a copy of tf->tf_pc.
*
* Note that the things labelled `out' registers in the trapframe were the
* `in' registers within the syscall trap code (because of the automatic
* `save' effect of each trap). They are, however, the %o registers of the
* thing that made the system call, and are named that way here.
*
* 32-bit system calls on a 64-bit system are a problem. Each system call
* argument is stored in the smaller of the argument's true size or a
* `register_t'. Now on a 64-bit machine all normal types can be stored in a
* `register_t'. (The only exceptions would be 128-bit `quad's or 128-bit
* extended precision floating point values, which we don't support.) For
* 32-bit syscalls, 64-bit integers like `off_t's, double precision floating
* point values, and several other types cannot fit in a 32-bit `register_t'.
* These will require reading in two `register_t' values for one argument.
*
* In order to calculate the true size of the arguments and therefore whether
* any argument needs to be split into two slots, the system call args
* structure needs to be built with the appropriately sized register_t.
* Otherwise the emul needs to do some magic to split oversized arguments.
*
* We can handle most this stuff for normal syscalls by using either a 32-bit
* or 64-bit array of `register_t' arguments. Unfortunately ktrace always
* expects arguments to be `register_t's, so it loses badly. What's worse,
* ktrace may need to do size translations to massage the argument array
* appropriately according to the emulation that is doing the ktrace.
*
*/
void
syscall(tf, code, pc)
struct trapframe64 *tf;
register_t code;
register_t pc;
{
int i, nsys, nap;
int64_t *ap;
const struct sysent *callp;
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
int error = 0, new;
union args {
register32_t i[8];
register64_t l[8];
register_t r[8];
} args;
register_t rval[2];
u_quad_t sticks;
vaddr_t opc, onpc;
#ifdef DEBUG
write_user_windows();
if (tf->tf_pc == tf->tf_npc) {
printf("syscall: tpc %p == tnpc %p\n", (void *)(u_long)tf->tf_pc,
(void *)(u_long)tf->tf_npc);
Debugger();
}
if ((trapdebug & TDB_NSAVED && curpcb->pcb_nsaved) ||
trapdebug & (TDB_SYSCALL | TDB_FOLLOW))
printf("%d syscall(%lx, %p, %lx)\n",
curproc ? curproc->p_pid : -1, (u_long)code, tf,
(u_long)pc);
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if ((trapdebug & TDB_TL) && tl()) {
printf("%d tl %d syscall(%lx, %p, %lx)\n",
curproc ? curproc->p_pid : -1, tl(), (u_long)code, tf,
(u_long)pc);
Debugger();
}
#endif
uvmexp.syscalls++;
#ifdef DIAGNOSTIC
if (tf->tf_tstate & TSTATE_PRIV)
panic("syscall from kernel");
if (curpcb != &l->l_addr->u_pcb)
panic("syscall: curpcb/ppcb mismatch");
if (tf != (struct trapframe64 *)((caddr_t)curpcb + USPACE) - 1)
panic("syscall: trapframe");
#endif
sticks = p->p_sticks;
l->l_md.md_tf = tf;
new = code & (SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
code &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
callp = p->p_emul->e_sysent;
nsys = p->p_emul->e_nsysent;
/*
* save pc/npc in case of ERESTART
* adjust pc/npc to new values
*/
opc = tf->tf_pc;
onpc = tf->tf_npc;
if (new)
tf->tf_pc = tf->tf_global[new & SYSCALL_G2RFLAG ? 2 : 7];
else
tf->tf_pc = tf->tf_npc;
tf->tf_npc = tf->tf_pc + 4;
/*
* The first six system call arguments are in the six %o registers.
* Any arguments beyond that are in the `argument extension' area
* of the user's stack frame (see <machine/frame.h>).
*
* Check for ``special'' codes that alter this, namely syscall and
* __syscall. The latter takes a quad syscall number, so that other
* arguments are at their natural alignments. Adjust the number
* of ``easy'' arguments as appropriate; we will copy the hard
* ones later as needed.
*/
ap = &tf->tf_out[0];
nap = 6;
switch (code) {
case SYS_syscall:
code = *ap++;
nap--;
break;
case SYS___syscall:
if (code < nsys &&
callp[code].sy_call != callp[p->p_emul->e_nosys].sy_call)
break; /* valid system call */
if (tf->tf_out[6] & 1L) {
/* longs *are* quadwords */
code = ap[0];
ap += 1;
nap -= 1;
} else {
code = ap[_QUAD_LOWWORD];
ap += 2;
nap -= 2;
}
break;
}
#ifdef DEBUG
if (trapdebug & (TDB_SYSCALL | TDB_FOLLOW))
printf("%d syscall(%d[%x]): tstate=%x:%x %s\n",
l ? p->p_pid : -1, (int)code, (u_int)code,
(int)(tf->tf_tstate>>32), (int)(tf->tf_tstate),
(p->p_emul->e_syscallnames) ?
((code < 0 || code >= nsys) ?
"illegal syscall" :
p->p_emul->e_syscallnames[code]) :
"unknown syscall");
if (p->p_emul->e_syscallnames)
l->l_addr->u_pcb.lastcall =
((code < 0 || code >= nsys) ?
"illegal syscall" :
p->p_emul->e_syscallnames[code]);
#endif
if (code < 0 || code >= nsys)
callp += p->p_emul->e_nosys;
else if (tf->tf_out[6] & 1L) {
register64_t *argp;
#ifdef DEBUG
#ifdef __arch64__
if ((curproc->p_flag & P_32) != 0) {
printf("syscall(): 64-bit stack but P_32 set\n");
Debugger();
}
#else
printf("syscall(): 64-bit stack on a 32-bit kernel????\n");
Debugger();
#endif
#endif
/* 64-bit stack -- not really supported on 32-bit kernels */
callp += code;
i = callp->sy_narg; /* Why divide? */
if (i > nap) { /* usually false */
if (i > 8)
panic("syscall nargs");
/* Read the whole block in */
error = copyin((caddr_t)(u_long)tf->tf_out[6] + BIAS +
offsetof(struct frame64, fr_argx),
&args.l[nap],
(i - nap) * sizeof(register64_t));
i = nap;
}
/* It should be faster to do <=6 longword copies than call memcpy */
for (argp = &args.l[0]; i--;)
*argp++ = *ap++;
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL))
ktrsyscall(p, code, code, NULL, args.r);
#endif
if (error)
goto bad;
#ifdef DEBUG
if (trapdebug & (TDB_SYSCALL | TDB_FOLLOW)) {
for (i = 0; i < callp->sy_narg; i++)
printf("arg[%d]=%lx ", i, (long)(args.l[i]));
printf("\n");
}
if (trapdebug & TDB_STOPCALL) {
printf("stop precall\n");
Debugger();
}
#endif
} else {
register32_t *argp;
int j;
/* 32-bit stack */
callp += code;
#ifdef DIAGNOSTIC
#if defined(__arch64__)
if ((curproc->p_flag & P_32) == 0)
printf("syscall(): 32-bit stack but no P_32\n");
#endif
#endif
i = (long)callp->sy_argsize / sizeof(register32_t);
if (i > nap) { /* usually false */
register32_t temp[6];
if (i > 8)
panic("syscall nargs");
/* Read the whole block in */
error = copyin((caddr_t)(u_long)(tf->tf_out[6] +
offsetof(struct frame32, fr_argx)),
&temp, (i - nap) * sizeof(register32_t));
/* Copy each to the argument array */
for (j = 0; nap + j < i; j++)
args.i[nap+j] = temp[j];
#ifdef DEBUG
if (trapdebug & (TDB_SYSCALL | TDB_FOLLOW)) {
int k;
printf("Copyin args of %d from %p:\n", j,
(caddr_t)(u_long)(tf->tf_out[6] +
offsetof(struct frame32, fr_argx)));
for (k = 0; k < j; k++)
printf("arg %d = %p at %d val %p\n",
k, (void *)(u_long)temp[k], nap + k,
(void *)(u_long)args.i[nap + k]);
}
#endif
i = nap;
}
/* Need to convert from int64 to int32 or we lose */
for (j = i, argp = &args.i[0]; i--;)
*argp++ = *ap++;
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSCALL)) {
#if defined(__arch64__)
union args args64;
for (i = 0; i < j; i++)
args64.l[i] = args.i[i];
ktrsyscall(p, code, code, NULL, args64.r);
#else
ktrsyscall(p, code, code, NULL, args.r);
#endif
}
#endif
if (error)
goto bad;
#ifdef DEBUG
if (trapdebug & (TDB_SYSCALL | TDB_FOLLOW)) {
for (i = 0; i < (long)callp->sy_argsize /
sizeof(register32_t); i++)
printf("arg[%d]=%x ", i, (int)(args.i[i]));
printf("\n");
}
if (trapdebug & TDB_STOPCALL) {
printf("stop precall\n");
Debugger();
}
#endif
}
rval[0] = 0;
rval[1] = tf->tf_out[1];
#ifdef DEBUG
if (callp->sy_call == sys_nosys) {
printf("trapdebug: emul %s UNIPL syscall %d:%s\n",
p->p_emul->e_name, (int)code,
p->p_emul->e_syscallnames ? (
(code < 0 || code >= nsys) ?
"illegal syscall" :
p->p_emul->e_syscallnames[code]) :
"unknown syscall");
}
#endif
/* Lock the kernel if the syscall isn't MP-safe. */
if ((callp->sy_flags & SYCALL_MPSAFE) == 0)
KERNEL_PROC_LOCK(l);
error = (*callp->sy_call)(l, &args, rval);
if ((callp->sy_flags & SYCALL_MPSAFE) == 0)
KERNEL_PROC_UNLOCK(l);
switch (error) {
case 0:
/* Note: fork() does not return here in the child */
tf->tf_out[0] = rval[0];
tf->tf_out[1] = rval[1];
if (!new)
/* old system call convention: clear C on success */
tf->tf_tstate &= ~(((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* success */
break;
case ERESTART:
tf->tf_pc = opc;
tf->tf_npc = onpc;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
bad:
if (p->p_emul->e_errno)
error = p->p_emul->e_errno[error];
tf->tf_out[0] = error;
tf->tf_tstate |= (((int64_t)(ICC_C | XCC_C)) <<
TSTATE_CCR_SHIFT); /* fail */
tf->tf_pc = onpc;
tf->tf_npc = tf->tf_pc + 4;
break;
}
userret(l, pc, sticks);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p, code, error, rval);
#endif
share_fpu(l, tf);
#ifdef DEBUG
if (trapdebug & (TDB_STOPCALL | TDB_SYSTOP)) {
Debugger();
}
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
#endif
}
/*
* Process the tail end of a fork() for the child.
*/
void
child_return(arg)
void *arg;
{
struct lwp *l = arg;
#ifdef KTRACE
struct proc *p = l->l_proc;
#endif
/*
* Return values in the frame set by cpu_lwp_fork().
*/
KERNEL_PROC_UNLOCK(l);
userret(l, l->l_md.md_tf->tf_pc, 0);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p,
(p->p_flag & P_PPWAIT) ? SYS_vfork : SYS_fork, 0, 0);
#endif
}
/*
* Start a new LWP
*/
void
startlwp(arg)
void *arg;
{
int err;
ucontext_t *uc = arg;
struct lwp *l = curlwp;
err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
#if DIAGNOSTIC
if (err) {
printf("Error %d from cpu_setmcontext.", err);
}
#endif
pool_put(&lwp_uc_pool, uc);
KERNEL_PROC_UNLOCK(l);
userret(l, 0, 0);
}
void
upcallret(struct lwp *l)
{
KERNEL_PROC_UNLOCK(l);
userret(l, 0, 0);
}