diff options
| author | thorpej <thorpej@NetBSD.org> | 2003-03-01 04:36:38 +0000 |
|---|---|---|
| committer | thorpej <thorpej@NetBSD.org> | 2003-03-01 04:36:38 +0000 |
| commit | 5afa6838bf6bdc19b5e14c7e899a5a51a6caead3 (patch) | |
| tree | 5281ee003978fca7279fb99d9bfb063f2ad0c7e5 /sys | |
| parent | b1a286afffb7ed6cc2e15dec3513d31e3ed60be7 (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.c | 78 | ||||
| -rw-r--r-- | sys/arch/arm/arm/syscall.c | 150 | ||||
| -rw-r--r-- | sys/arch/arm/include/proc.h | 5 | ||||
| -rw-r--r-- | sys/arch/arm/include/types.h | 3 | ||||
| -rw-r--r-- | sys/compat/linux/arch/arm/linux_exec.h | 4 | ||||
| -rw-r--r-- | sys/compat/linux/arch/arm/linux_machdep.h | 4 | ||||
| -rw-r--r-- | sys/compat/linux/arch/powerpc/linux_exec.h | 5 | ||||
| -rw-r--r-- | sys/compat/linux/common/linux_exec.c | 9 |
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, |
