Module Name: src Committed By: matt Date: Fri Aug 21 17:46:23 UTC 2009
Modified Files: src/sys/arch/mips/mips [matt-nb5-mips64]: syscall.c Log Message: New simplier implentation that handles all 4 ABIs: O32/N32/O64/N64. To generate a diff of this commit: cvs rdiff -u -r1.37.12.1 -r1.37.12.2 src/sys/arch/mips/mips/syscall.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/mips/mips/syscall.c diff -u src/sys/arch/mips/mips/syscall.c:1.37.12.1 src/sys/arch/mips/mips/syscall.c:1.37.12.2 --- src/sys/arch/mips/mips/syscall.c:1.37.12.1 Thu Aug 20 04:22:54 2009 +++ src/sys/arch/mips/mips/syscall.c Fri Aug 21 17:46:23 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: syscall.c,v 1.37.12.1 2009/08/20 04:22:54 uebayasi Exp $ */ +/* $NetBSD: syscall.c,v 1.37.12.2 2009/08/21 17:46:23 matt Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -107,7 +107,7 @@ #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ -__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.37.12.1 2009/08/20 04:22:54 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.37.12.2 2009/08/21 17:46:23 matt Exp $"); #if defined(_KERNEL_OPT) #include "opt_sa.h" @@ -140,21 +140,16 @@ #endif void EMULNAME(syscall_intern)(struct proc *); -void EMULNAME(syscall_plain)(struct lwp *, u_int, u_int, u_int); -void EMULNAME(syscall_fancy)(struct lwp *, u_int, u_int, u_int); +static void EMULNAME(syscall)(struct lwp *, uint32_t, uint32_t, vaddr_t); -vaddr_t MachEmulateBranch(struct frame *, vaddr_t, u_int, int); +register_t MachEmulateBranch(struct frame *, register_t, u_int, int); #define DELAYBRANCH(x) ((int)(x)<0) void EMULNAME(syscall_intern)(struct proc *p) { - - if (trace_is_enabled(p)) - p->p_md.md_syscall = EMULNAME(syscall_fancy); - else - p->p_md.md_syscall = EMULNAME(syscall_plain); + p->p_md.md_syscall = EMULNAME(syscall); } /* @@ -164,25 +159,35 @@ * in v0, and the arguments in the registers (as normal). They return * an error flag in a3 (if a3 != 0 on return, the syscall had an error), * and the return value (if any) in v0 and possibly v1. - * - * XXX Needs to be heavily rototilled for N32 or LP64 support. */ void -EMULNAME(syscall_plain)(struct lwp *l, u_int status, u_int cause, u_int opc) +EMULNAME(syscall)(struct lwp *l, u_int status, u_int cause, vaddr_t opc) { struct proc *p = l->l_proc; - struct frame *frame = (struct frame *)l->l_md.md_regs; - register_t *args, copyargs[8]; - register_t *rval = NULL; /* XXX gcc */ -#if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - register_t copyrval[2]; -#endif - mips_reg_t ov0; - size_t nsaved, nargs; + struct frame *frame = l->l_md.md_regs; + mips_reg_t *fargs = &frame->f_regs[_R_A0]; + void *args = NULL; + void *rval = NULL; /* XXX gcc */ +#if !defined(__mips_o32) + register32_t copy32args[2+SYS_MAXSYSARGS]; + register_t copy32rval[2]; +#endif + register_t copyargs[2+SYS_MAXSYSARGS]; + mips_reg_t saved_v0; + vaddr_t usp; + size_t nargs; const struct sysent *callp; - int error; - u_int code; + int code, error; +#if defined(__mips_o32) + const int abi = _MIPS_BSD_API_O32; + KASSERTMSG(p->p_md.md_abi != abi, ("pid %d(%p): md_abi(%d) != abi(%d)", p->p_pid, p, p->p_md.md_abi, abi)); + size_t nregs = 4; +#else + const int abi = p->p_md.md_abi; + size_t nregs = _MIPS_SIM_NEWABI_P(abi) ? 8 : 4; + size_t i; +#endif LWP_CACHE_CREDS(l, p); @@ -191,10 +196,10 @@ if (DELAYBRANCH(cause)) frame->f_regs[_R_PC] = MachEmulateBranch(frame, opc, 0, 0); else - frame->f_regs[_R_PC] = opc + sizeof(int); + frame->f_regs[_R_PC] = opc + sizeof(uint32_t); callp = p->p_emul->e_sysent; - ov0 = code = frame->f_regs[_R_V0] - SYSCALL_SHIFT; + saved_v0 = code = frame->f_regs[_R_V0] - SYSCALL_SHIFT; #ifdef KERN_SA if (__predict_false((l->l_savp) @@ -202,255 +207,110 @@ l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; #endif - switch (code) { - case SYS_syscall: - case SYS___syscall: - args = copyargs; - if (code == SYS_syscall) { - /* - * Code is first argument, followed by actual args. - */ - code = frame->f_regs[_R_A0] - SYSCALL_SHIFT; - args[0] = frame->f_regs[_R_A1]; - args[1] = frame->f_regs[_R_A2]; - args[2] = frame->f_regs[_R_A3]; - nsaved = 3; - } else { - /* - * Like syscall, but code is a quad, so as to maintain - * quad alignment for the rest of the arguments. - */ - code = frame->f_regs[_R_A0 + _QUAD_LOWWORD] - - SYSCALL_SHIFT; - args[0] = frame->f_regs[_R_A2]; - args[1] = frame->f_regs[_R_A3]; - nsaved = 2; - } - - if (code >= p->p_emul->e_nsysent) - callp += p->p_emul->e_nosys; - else - callp += code; - nargs = callp->sy_argsize / sizeof(register_t); - - if (nargs > nsaved) { - error = copyin( - ((register_t *)(vaddr_t)frame->f_regs[_R_SP] + 4), - (args + nsaved), - (nargs - nsaved) * sizeof(register_t)); - if (error) - goto bad; - } - break; - - default: - if (code >= p->p_emul->e_nsysent) - callp += p->p_emul->e_nosys; - else - callp += code; - nargs = callp->sy_narg; - - if (nargs < 5) { -#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 - args = (register_t *)&frame->f_regs[_R_A0]; -#elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - args = copyargs; - args[0] = frame->f_regs[_R_A0]; - args[1] = frame->f_regs[_R_A1]; - args[2] = frame->f_regs[_R_A2]; - args[3] = frame->f_regs[_R_A3]; -#else - panic("syscall not implemented for current MIPS ABI\n"); -#endif - } else { - args = copyargs; - error = copyin( - ((register_t *)(vaddr_t)frame->f_regs[_R_SP] + 4), - (©args[4]), - (nargs - 4) * sizeof(register_t)); - if (error) - goto bad; - args[0] = frame->f_regs[_R_A0]; - args[1] = frame->f_regs[_R_A1]; - args[2] = frame->f_regs[_R_A2]; - args[3] = frame->f_regs[_R_A3]; - } - break; + if (code == SYS_syscall + || (code == SYS___syscall && abi != _MIPS_BSD_API_O32)) { + /* + * Code is first argument, followed by actual args. + */ + code = *fargs++ - SYSCALL_SHIFT; + nregs--; + } else if (code == SYS___syscall) { + /* + * Like syscall, but code is a quad, so as to maintain + * quad alignment for the rest of the arguments. + */ + code = fargs[_QUAD_LOWWORD] - SYSCALL_SHIFT; + fargs += 2; + nregs -= 2; } -#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 - rval = (register_t *)&frame->f_regs[_R_V0]; - rval[0] = 0; - /* rval[1] already has V1 */ -#elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - rval = copyrval; - rval[0] = 0; - rval[1] = frame->f_regs[_R_V1]; -#endif - - error = sy_call(callp, l, args, rval); - - switch (error) { - case 0: -#if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - frame->f_regs[_R_V0] = rval[0]; - frame->f_regs[_R_V1] = rval[1]; -#endif - frame->f_regs[_R_A3] = 0; - break; - case ERESTART: - frame->f_regs[_R_V0] = ov0; /* restore syscall code */ - frame->f_regs[_R_PC] = opc; - break; - case EJUSTRETURN: - break; /* nothing to do */ - default: - bad: - if (p->p_emul->e_errno) - error = p->p_emul->e_errno[error]; - frame->f_regs[_R_V0] = error; - frame->f_regs[_R_A3] = 1; - break; - } - - userret(l); -} - -void -EMULNAME(syscall_fancy)(struct lwp *l, u_int status, u_int cause, u_int opc) -{ - struct proc *p = l->l_proc; - struct frame *frame = (struct frame *)l->l_md.md_regs; - register_t *args, copyargs[8]; - register_t *rval = NULL; /* XXX gcc */ -#if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - register_t copyrval[2]; -#endif - mips_reg_t ov0; - size_t nsaved, nargs; - const struct sysent *callp; - int error; - u_int code; - - LWP_CACHE_CREDS(l, p); - - uvmexp.syscalls++; - - if (DELAYBRANCH(cause)) - frame->f_regs[_R_PC] = MachEmulateBranch(frame, opc, 0, 0); + if (code >= p->p_emul->e_nsysent) + callp += p->p_emul->e_nosys; else - frame->f_regs[_R_PC] = opc + sizeof(int); - - callp = p->p_emul->e_sysent; - ov0 = code = frame->f_regs[_R_V0] - SYSCALL_SHIFT; + callp += code; -#ifdef KERN_SA - if (__predict_false((l->l_savp) - && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) - l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; +#if !defined(__mips_o32) + if (abi != _MIPS_BSD_API_O32) { #endif - - switch (code) { - case SYS_syscall: - case SYS___syscall: - args = copyargs; - if (code == SYS_syscall) { + CTASSERT(sizeof(copyargs[0]) == sizeof(fargs[0])); + nargs = callp->sy_argsize / sizeof(copyargs[0]); + rval = &frame->f_regs[_R_V0]; + frame->f_regs[_R_V0] = 0; + /* rval[1] already is V1 */ + if (nargs <= nregs) { /* - * Code is first argument, followed by actual args. + * Just use the frame for the source of arguments */ - code = frame->f_regs[_R_A0] - SYSCALL_SHIFT; - args[0] = frame->f_regs[_R_A1]; - args[1] = frame->f_regs[_R_A2]; - args[2] = frame->f_regs[_R_A3]; - nsaved = 3; + args = fargs; } else { + const size_t nsaved = _MIPS_SIM_NEWABI_P(abi) ? 0 : 4; + args = copyargs; /* - * Like syscall, but code is a quad, so as to maintain - * quad alignment for the rest of the arguments. + * Copy the arguments passed via register from the * trap frame to our argument array */ - code = frame->f_regs[_R_A0 + _QUAD_LOWWORD] - - SYSCALL_SHIFT; - args[0] = frame->f_regs[_R_A2]; - args[1] = frame->f_regs[_R_A3]; - nsaved = 2; - } - - if (code >= p->p_emul->e_nsysent) - callp += p->p_emul->e_nosys; - else - callp += code; - nargs = callp->sy_argsize / sizeof(register_t); - - if (nargs > nsaved) { - error = copyin( - ((register_t *)(vaddr_t)frame->f_regs[_R_SP] + 4), - (args + nsaved), - (nargs - nsaved) * sizeof(register_t)); + memcpy(copyargs, fargs, nregs * sizeof(register_t)); + /* + * Start copying args skipping the register slots + * slots on the stack. + */ + usp = frame->f_regs[_R_SP] + nsaved*sizeof(register_t); + error = copyin((register_t *)usp, ©args[nregs], + (nargs - nregs) * sizeof(copyargs[0])); if (error) goto bad; } - break; - - default: - if (code >= p->p_emul->e_nsysent) - callp += p->p_emul->e_nosys; - else - callp += code; - nargs = callp->sy_narg; - - if (nargs < 5) { -#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 - args = (register_t *)&frame->f_regs[_R_A0]; -#elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - args = copyargs; - args[0] = frame->f_regs[_R_A0]; - args[1] = frame->f_regs[_R_A1]; - args[2] = frame->f_regs[_R_A2]; - args[3] = frame->f_regs[_R_A3]; -#else - panic("syscall not implemented for current MIPS ABI\n"); -#endif - } else { - args = copyargs; - error = copyin( - ((register_t *)(vaddr_t)frame->f_regs[_R_SP] + 4), - (©args[4]), - (nargs - 4) * sizeof(register_t)); +#if !defined(__mips_o32) + } else { + /* + * All arguments are 32bits wide and 64bit arguments use + * two 32bit registers or stack slots. + */ + nargs = callp->sy_argsize / sizeof(copy32args[0]); + rval = copy32rval; + args = copy32args; + copy32rval[0] = 0; + copy32rval[1] = frame->f_regs[_R_V1]; + CTASSERT(sizeof(copy32args[0]) != sizeof(fargs[0])); + /* + * Copy the register passed arguments from the trapframe to + * the set of 32bit copies. + */ + for (i = 0; i < 4 && i < nargs; i++) + copy32args[i] = fargs[i]; + if (nargs > nregs) { + /* + * Copy the remainder of the arguments from the stack + * after skipped the slots for the 4 register passed + * arguments. + */ + usp = frame->f_regs[_R_SP] + 4*sizeof(register32_t); + error = copyin((register32_t *)usp, ©32args[nregs], + (nargs - nregs) * sizeof(copy32args[0])); if (error) goto bad; - args[0] = frame->f_regs[_R_A0]; - args[1] = frame->f_regs[_R_A1]; - args[2] = frame->f_regs[_R_A2]; - args[3] = frame->f_regs[_R_A3]; } - break; } +#endif - if ((error = trace_enter(code, args, callp->sy_narg)) != 0) + if (__predict_false(p->p_trace_enabled) + && (error = trace_enter(code, args, nargs)) != 0) goto out; -#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 - rval = (register_t *)&frame->f_regs[_R_V0]; - rval[0] = 0; - /* rval[1] already has V1 */ -#elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - rval = copyrval; - rval[0] = 0; - rval[1] = frame->f_regs[_R_V1]; -#endif + error = (*callp->sy_call)(l, args, rval); - error = sy_call(callp, l, args, rval); -out: + out: switch (error) { case 0: -#if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN - frame->f_regs[_R_V0] = rval[0]; - frame->f_regs[_R_V1] = rval[1]; +#if !defined(__mips_o32) + if (abi == _MIPS_BSD_API_O32) { + frame->f_regs[_R_V0] = copy32rval[0]; + frame->f_regs[_R_V1] = copy32rval[1]; + } #endif frame->f_regs[_R_A3] = 0; break; case ERESTART: - frame->f_regs[_R_V0] = ov0; /* restore syscall code */ + frame->f_regs[_R_V0] = saved_v0; /* restore syscall code */ frame->f_regs[_R_PC] = opc; break; case EJUSTRETURN: @@ -464,7 +324,8 @@ break; } - trace_exit(code, rval, error); + if (__predict_false(p->p_trace_enabled)) + trace_exit(code, &frame->f_regs[_R_V0], error); userret(l); }