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:
parent
b1a286afff
commit
5afa6838bf
@ -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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This code is derived from software contributed to The NetBSD Foundation
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#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/device.h>
|
||||||
#include <sys/errno.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_ARM_NR_BASE 0x9f0000
|
||||||
#define LINUX_SYS_ARMBASE 0x000100 /* Must agree with syscalls.master */
|
#define LINUX_SYS_ARMBASE 0x000100 /* Must agree with syscalls.master */
|
||||||
|
|
||||||
/* XXX */
|
void linux_syscall_intern(struct proc *);
|
||||||
void linux_syscall(struct trapframe *frame, struct lwp *l, u_int32_t insn);
|
void linux_syscall_plain(struct trapframe *, struct lwp *, u_int32_t);
|
||||||
|
void linux_syscall_fancy(struct trapframe *, struct lwp *, u_int32_t);
|
||||||
|
|
||||||
void
|
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;
|
const struct sysent *callp;
|
||||||
struct proc *p = l->l_proc;
|
struct proc *p = l->l_proc;
|
||||||
|
@ -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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This code is derived from software contributed to The NetBSD Foundation
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#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/device.h>
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
@ -171,16 +171,150 @@ swi_handler(trapframe_t *frame)
|
|||||||
uvmexp.syscalls++;
|
uvmexp.syscalls++;
|
||||||
|
|
||||||
(*(void(*)(struct trapframe *, struct lwp *, u_int32_t))
|
(*(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
|
#define MAXARGS 8
|
||||||
|
|
||||||
/* XXX */
|
void syscall_intern(struct proc *);
|
||||||
void syscall(struct trapframe *frame, struct lwp *l, u_int32_t insn);
|
void syscall_plain(struct trapframe *, struct lwp *, u_int32_t);
|
||||||
|
void syscall_fancy(struct trapframe *, struct lwp *, u_int32_t);
|
||||||
|
|
||||||
void
|
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;
|
struct proc *p = l->l_proc;
|
||||||
const struct sysent *callp;
|
const struct sysent *callp;
|
||||||
@ -325,5 +459,3 @@ child_return(arg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of syscall.c */
|
|
||||||
|
@ -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.
|
* Copyright (c) 1994 Mark Brinicombe.
|
||||||
@ -39,11 +39,14 @@
|
|||||||
* Machine-dependent part of the proc structure for arm.
|
* Machine-dependent part of the proc structure for arm.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct trapframe;
|
||||||
|
|
||||||
struct mdlwp {
|
struct mdlwp {
|
||||||
int md_dummy; /* must have at least one member */
|
int md_dummy; /* must have at least one member */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mdproc {
|
struct mdproc {
|
||||||
|
void (*md_syscall)(struct trapframe *, struct lwp *, u_int32_t);
|
||||||
int pmc_enabled; /* bitfield of enabled counters */
|
int pmc_enabled; /* bitfield of enabled counters */
|
||||||
void *pmc_state; /* port-specific pmc state */
|
void *pmc_state; /* port-specific pmc state */
|
||||||
};
|
};
|
||||||
|
@ -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.
|
* Copyright (c) 1990 The Regents of the University of California.
|
||||||
@ -64,6 +64,7 @@ typedef unsigned long pmc_ctr_t;
|
|||||||
|
|
||||||
typedef int register_t;
|
typedef int register_t;
|
||||||
|
|
||||||
|
#define __HAVE_SYSCALL_INTERN
|
||||||
#define __HAVE_MINIMAL_EMUL
|
#define __HAVE_MINIMAL_EMUL
|
||||||
#define __HAVE_RAS
|
#define __HAVE_RAS
|
||||||
|
|
||||||
|
@ -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.
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||||
@ -45,6 +45,4 @@
|
|||||||
#define LINUX_ELF_AUX_ARGSIZ \
|
#define LINUX_ELF_AUX_ARGSIZ \
|
||||||
(howmany(LINUX_ELF_AUX_ENTRIES * sizeof(Aux32Info), sizeof(Elf32_Addr)))
|
(howmany(LINUX_ELF_AUX_ENTRIES * sizeof(Aux32Info), sizeof(Elf32_Addr)))
|
||||||
|
|
||||||
#define LINUX_SYSCALL_FUNCTION linux_syscall
|
|
||||||
|
|
||||||
#endif /* !_I386_LINUX_EXEC_H */
|
#endif /* !_I386_LINUX_EXEC_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.
|
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
|
||||||
@ -77,4 +77,6 @@ struct linux_sigframe {
|
|||||||
unsigned long sf_extramask[LINUX__NSIG_WORDS - 1];
|
unsigned long sf_extramask[LINUX__NSIG_WORDS - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void linux_syscall_intern __P((struct proc *));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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.
|
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
|
||||||
@ -103,7 +103,4 @@
|
|||||||
/* we have special powerpc ELF copyargs */
|
/* we have special powerpc ELF copyargs */
|
||||||
#define LINUX_MACHDEP_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 */
|
#endif /* !_POWERPC_LINUX_EXEC_H */
|
||||||
|
@ -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.
|
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
|
||||||
@ -38,7 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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/param.h>
|
||||||
#include <sys/systm.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 struct sysent linux_sysent[];
|
||||||
extern const char * const linux_syscallnames[];
|
extern const char * const linux_syscallnames[];
|
||||||
extern char linux_sigcode[], linux_esigcode[];
|
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_exec __P((struct proc *, struct exec_package *));
|
||||||
static void linux_e_proc_fork __P((struct proc *, struct proc *));
|
static void linux_e_proc_fork __P((struct proc *, struct proc *));
|
||||||
@ -136,7 +133,7 @@ const struct emul emul_linux = {
|
|||||||
#ifdef __HAVE_SYSCALL_INTERN
|
#ifdef __HAVE_SYSCALL_INTERN
|
||||||
linux_syscall_intern,
|
linux_syscall_intern,
|
||||||
#else
|
#else
|
||||||
LINUX_SYSCALL_FUNCTION,
|
#error Implement __HAVE_SYSCALL_INTERN for this platform
|
||||||
#endif
|
#endif
|
||||||
linux_sysctl,
|
linux_sysctl,
|
||||||
NULL,
|
NULL,
|
||||||
|
Loading…
Reference in New Issue
Block a user