Do the syscall_plain/syscall_fancy dance on ARM. Shaves a fair number

of cycles off the syscall overhead.

Since all COMPAT_LINUX platforms now support __HAVE_SYSCALL_INTERN,
garbage-collect the LINUX_SYSCALL_FUNCTION stuff.
This commit is contained in:
thorpej 2003-03-01 04:36:38 +00:00
parent b1a286afff
commit 5afa6838bf
8 changed files with 227 additions and 31 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: linux_syscall.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */
/* $NetBSD: linux_syscall.c,v 1.9 2003/03/01 04:36:38 thorpej Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -80,7 +80,7 @@
#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: linux_syscall.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_syscall.c,v 1.9 2003/03/01 04:36:38 thorpej Exp $");
#include <sys/device.h>
#include <sys/errno.h>
@ -110,11 +110,77 @@ __KERNEL_RCSID(0, "$NetBSD: linux_syscall.c,v 1.8 2003/01/17 22:28:48 thorpej Ex
#define LINUX_ARM_NR_BASE 0x9f0000
#define LINUX_SYS_ARMBASE 0x000100 /* Must agree with syscalls.master */
/* XXX */
void linux_syscall(struct trapframe *frame, struct lwp *l, u_int32_t insn);
void linux_syscall_intern(struct proc *);
void linux_syscall_plain(struct trapframe *, struct lwp *, u_int32_t);
void linux_syscall_fancy(struct trapframe *, struct lwp *, u_int32_t);
void
linux_syscall(trapframe_t *frame, struct lwp *l, u_int32_t insn)
linux_syscall_intern(struct proc *p)
{
#ifdef KTRACE
if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
p->p_md.md_syscall = linux_syscall_fancy;
return;
}
#endif
#ifdef SYSTRACE
if (p->p_flag & P_SYSTRACE) {
p->p_md.md_syscall = linux_syscall_fancy;
return;
}
#endif
p->p_md.md_syscall = linux_syscall_plain;
}
void
linux_syscall_plain(trapframe_t *frame, struct lwp *l, u_int32_t insn)
{
const struct sysent *callp;
struct proc *p = l->l_proc;
int code, error;
u_int nargs;
register_t *args, rval[2];
code = insn & 0x00ffffff;
/* Remap ARM-specific syscalls onto the end of the standard range. */
if (code > LINUX_ARM_NR_BASE)
code = code - LINUX_ARM_NR_BASE + LINUX_SYS_ARMBASE;
code &= LINUX_SYS_NSYSENT - 1;
/* Linux passes all arguments in order in registers, which is nice. */
args = &frame->tf_r0;
callp = p->p_emul->e_sysent + code;
nargs = callp->sy_argsize / sizeof(register_t);
rval[0] = 0;
rval[1] = 0;
error = (*callp->sy_call)(l, args, rval);
switch (error) {
case 0:
frame->tf_r0 = rval[0];
break;
case ERESTART:
/* Reconstruct the pc to point at the swi. */
frame->tf_pc -= INSN_SIZE;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
error = native_to_linux_errno[error];
frame->tf_r0 = error;
break;
}
userret(l);
}
void
linux_syscall_fancy(trapframe_t *frame, struct lwp *l, u_int32_t insn)
{
const struct sysent *callp;
struct proc *p = l->l_proc;

View File

@ -1,7 +1,7 @@
/* $NetBSD: syscall.c,v 1.15 2003/01/17 22:28:49 thorpej Exp $ */
/* $NetBSD: syscall.c,v 1.16 2003/03/01 04:36:38 thorpej Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -82,7 +82,7 @@
#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.15 2003/01/17 22:28:49 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.16 2003/03/01 04:36:38 thorpej Exp $");
#include <sys/device.h>
#include <sys/errno.h>
@ -171,16 +171,150 @@ swi_handler(trapframe_t *frame)
uvmexp.syscalls++;
(*(void(*)(struct trapframe *, struct lwp *, u_int32_t))
(p->p_emul->e_syscall))(frame, l, insn);
(p->p_md.md_syscall))(frame, l, insn);
}
#define MAXARGS 8
/* XXX */
void syscall(struct trapframe *frame, struct lwp *l, u_int32_t insn);
void syscall_intern(struct proc *);
void syscall_plain(struct trapframe *, struct lwp *, u_int32_t);
void syscall_fancy(struct trapframe *, struct lwp *, u_int32_t);
void
syscall(struct trapframe *frame, struct lwp *l, u_int32_t insn)
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 (p->p_flag & P_SYSTRACE) {
p->p_md.md_syscall = syscall_fancy;
return;
}
#endif
p->p_md.md_syscall = syscall_plain;
}
void
syscall_plain(struct trapframe *frame, struct lwp *l, u_int32_t insn)
{
struct proc *p = l->l_proc;
const struct sysent *callp;
int code, error;
u_int nap, nargs;
register_t *ap, *args, copyargs[MAXARGS], rval[2];
KERNEL_PROC_LOCK(p);
switch (insn & SWI_OS_MASK) { /* Which OS is the SWI from? */
case SWI_OS_ARM: /* ARM-defined SWIs */
code = insn & 0x00ffffff;
switch (code) {
case SWI_IMB:
case SWI_IMBrange:
/*
* Do nothing as there is no prefetch unit that needs
* flushing
*/
break;
default:
/* Undefined so illegal instruction */
trapsignal(l, SIGILL, insn);
break;
}
userret(l);
return;
case 0x000000: /* Old unofficial NetBSD range. */
case SWI_OS_NETBSD: /* New official NetBSD range. */
nap = 4;
break;
default:
/* Undefined so illegal instruction */
trapsignal(l, SIGILL, insn);
userret(l);
return;
}
code = insn & 0x000fffff;
ap = &frame->tf_r0;
callp = p->p_emul->e_sysent;
switch (code) {
case SYS_syscall:
code = *ap++;
nap--;
break;
case SYS___syscall:
code = ap[_QUAD_LOWWORD];
ap += 2;
nap -= 2;
break;
}
code &= (SYS_NSYSENT - 1);
callp += code;
nargs = callp->sy_argsize / sizeof(register_t);
if (nargs <= nap)
args = ap;
else {
KASSERT(nargs <= MAXARGS);
memcpy(copyargs, ap, nap * sizeof(register_t));
error = copyin((void *)frame->tf_usr_sp, copyargs + nap,
(nargs - nap) * sizeof(register_t));
if (error)
goto bad;
args = copyargs;
}
rval[0] = 0;
rval[1] = 0;
error = (*callp->sy_call)(l, args, rval);
switch (error) {
case 0:
frame->tf_r0 = rval[0];
frame->tf_r1 = rval[1];
#ifdef __PROG32
frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
#else
frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
#endif
break;
case ERESTART:
/*
* Reconstruct the pc to point at the swi.
*/
frame->tf_pc -= INSN_SIZE;
break;
case EJUSTRETURN:
/* nothing to do */
break;
default:
bad:
frame->tf_r0 = error;
#ifdef __PROG32
frame->tf_spsr |= PSR_C_bit; /* carry bit */
#else
frame->tf_r15 |= R15_FLAG_C; /* carry bit */
#endif
break;
}
KERNEL_PROC_UNLOCK(l);
userret(l);
}
void
syscall_fancy(struct trapframe *frame, struct lwp *l, u_int32_t insn)
{
struct proc *p = l->l_proc;
const struct sysent *callp;
@ -325,5 +459,3 @@ child_return(arg)
}
#endif
}
/* End of syscall.c */

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.4 2003/01/17 22:28:48 thorpej Exp $ */
/* $NetBSD: proc.h,v 1.5 2003/03/01 04:36:39 thorpej Exp $ */
/*
* Copyright (c) 1994 Mark Brinicombe.
@ -39,11 +39,14 @@
* Machine-dependent part of the proc structure for arm.
*/
struct trapframe;
struct mdlwp {
int md_dummy; /* must have at least one member */
};
struct mdproc {
void (*md_syscall)(struct trapframe *, struct lwp *, u_int32_t);
int pmc_enabled; /* bitfield of enabled counters */
void *pmc_state; /* port-specific pmc state */
};

View File

@ -1,4 +1,4 @@
/* $NetBSD: types.h,v 1.6 2002/10/07 02:48:38 thorpej Exp $ */
/* $NetBSD: types.h,v 1.7 2003/03/01 04:36:39 thorpej Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@ -64,6 +64,7 @@ typedef unsigned long pmc_ctr_t;
typedef int register_t;
#define __HAVE_SYSCALL_INTERN
#define __HAVE_MINIMAL_EMUL
#define __HAVE_RAS

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_exec.h,v 1.3 2002/11/13 15:16:30 jdolecek Exp $ */
/* $NetBSD: linux_exec.h,v 1.4 2003/03/01 04:36:39 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -45,6 +45,4 @@
#define LINUX_ELF_AUX_ARGSIZ \
(howmany(LINUX_ELF_AUX_ENTRIES * sizeof(Aux32Info), sizeof(Elf32_Addr)))
#define LINUX_SYSCALL_FUNCTION linux_syscall
#endif /* !_I386_LINUX_EXEC_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.h,v 1.3 2002/02/15 16:47:59 christos Exp $ */
/* $NetBSD: linux_machdep.h,v 1.4 2003/03/01 04:36:39 thorpej Exp $ */
/*-
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
@ -77,4 +77,6 @@ struct linux_sigframe {
unsigned long sf_extramask[LINUX__NSIG_WORDS - 1];
};
void linux_syscall_intern __P((struct proc *));
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_exec.h,v 1.13 2002/11/13 15:16:31 jdolecek Exp $ */
/* $NetBSD: linux_exec.h,v 1.14 2003/03/01 04:36:39 thorpej Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@ -103,7 +103,4 @@
/* we have special powerpc ELF copyargs */
#define LINUX_MACHDEP_ELF_COPYARGS
/* NetBSD/powerpc doesn't use e_syscall, so use the default. */
#define LINUX_SYSCALL_FUNCTION syscall
#endif /* !_POWERPC_LINUX_EXEC_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_exec.c,v 1.61 2003/01/18 08:02:51 thorpej Exp $ */
/* $NetBSD: linux_exec.c,v 1.62 2003/03/01 04:36:39 thorpej Exp $ */
/*-
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.61 2003/01/18 08:02:51 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.62 2003/03/01 04:36:39 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -73,9 +73,6 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.61 2003/01/18 08:02:51 thorpej Exp
extern struct sysent linux_sysent[];
extern const char * const linux_syscallnames[];
extern char linux_sigcode[], linux_esigcode[];
#ifndef __HAVE_SYSCALL_INTERN
void LINUX_SYSCALL_FUNCTION __P((void));
#endif
static void linux_e_proc_exec __P((struct proc *, struct exec_package *));
static void linux_e_proc_fork __P((struct proc *, struct proc *));
@ -136,7 +133,7 @@ const struct emul emul_linux = {
#ifdef __HAVE_SYSCALL_INTERN
linux_syscall_intern,
#else
LINUX_SYSCALL_FUNCTION,
#error Implement __HAVE_SYSCALL_INTERN for this platform
#endif
linux_sysctl,
NULL,