summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorthorpej <thorpej@NetBSD.org>2003-03-01 04:36:38 +0000
committerthorpej <thorpej@NetBSD.org>2003-03-01 04:36:38 +0000
commit5afa6838bf6bdc19b5e14c7e899a5a51a6caead3 (patch)
tree5281ee003978fca7279fb99d9bfb063f2ad0c7e5 /sys
parentb1a286afffb7ed6cc2e15dec3513d31e3ed60be7 (diff)
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm/arm/linux_syscall.c78
-rw-r--r--sys/arch/arm/arm/syscall.c150
-rw-r--r--sys/arch/arm/include/proc.h5
-rw-r--r--sys/arch/arm/include/types.h3
-rw-r--r--sys/compat/linux/arch/arm/linux_exec.h4
-rw-r--r--sys/compat/linux/arch/arm/linux_machdep.h4
-rw-r--r--sys/compat/linux/arch/powerpc/linux_exec.h5
-rw-r--r--sys/compat/linux/common/linux_exec.c9
8 files changed, 227 insertions, 31 deletions
diff --git a/sys/arch/arm/arm/linux_syscall.c b/sys/arch/arm/arm/linux_syscall.c
index b07b6873d20..070d8d13033 100644
--- a/sys/arch/arm/arm/linux_syscall.c
+++ b/sys/arch/arm/arm/linux_syscall.c
@@ -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;
diff --git a/sys/arch/arm/arm/syscall.c b/sys/arch/arm/arm/syscall.c
index 83faa3be745..f01371e5bbe 100644
--- a/sys/arch/arm/arm/syscall.c
+++ b/sys/arch/arm/arm/syscall.c
@@ -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 */
diff --git a/sys/arch/arm/include/proc.h b/sys/arch/arm/include/proc.h
index fbcf814c1ef..0ca9e99e2d9 100644
--- a/sys/arch/arm/include/proc.h
+++ b/sys/arch/arm/include/proc.h
@@ -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 */
};
diff --git a/sys/arch/arm/include/types.h b/sys/arch/arm/include/types.h
index aacb21124ce..7708f7cb9af 100644
--- a/sys/arch/arm/include/types.h
+++ b/sys/arch/arm/include/types.h
@@ -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
diff --git a/sys/compat/linux/arch/arm/linux_exec.h b/sys/compat/linux/arch/arm/linux_exec.h
index 6bcae0ba29e..7cb9ed84784 100644
--- a/sys/compat/linux/arch/arm/linux_exec.h
+++ b/sys/compat/linux/arch/arm/linux_exec.h
@@ -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 */
diff --git a/sys/compat/linux/arch/arm/linux_machdep.h b/sys/compat/linux/arch/arm/linux_machdep.h
index 26da9cb3ba8..659e449aadb 100644
--- a/sys/compat/linux/arch/arm/linux_machdep.h
+++ b/sys/compat/linux/arch/arm/linux_machdep.h
@@ -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
diff --git a/sys/compat/linux/arch/powerpc/linux_exec.h b/sys/compat/linux/arch/powerpc/linux_exec.h
index 5654e937288..48c8aa9c0eb 100644
--- a/sys/compat/linux/arch/powerpc/linux_exec.h
+++ b/sys/compat/linux/arch/powerpc/linux_exec.h
@@ -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 */
diff --git a/sys/compat/linux/common/linux_exec.c b/sys/compat/linux/common/linux_exec.c
index 36a402cd6a1..2e82bcf514a 100644
--- a/sys/compat/linux/common/linux_exec.c
+++ b/sys/compat/linux/common/linux_exec.c
@@ -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,