Module Name: src Committed By: matt Date: Sat Aug 22 00:28:42 UTC 2009
Modified Files: src/sys/arch/mips/mips [matt-nb5-mips64]: syscall.c Log Message: Rework O32 support on !O32 to just convert the 32bit argument list to a 64bit arguments using the info about 64bit args that's now in sysent. This avoid a special COMPAT for O32 and thus N32/O32 can share COMPAT_NETBSD32 Or on a N32 kernel, no COMPAT needed at all. To generate a diff of this commit: cvs rdiff -u -r1.37.12.2 -r1.37.12.3 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.2 src/sys/arch/mips/mips/syscall.c:1.37.12.3 --- src/sys/arch/mips/mips/syscall.c:1.37.12.2 Fri Aug 21 17:46:23 2009 +++ src/sys/arch/mips/mips/syscall.c Sat Aug 22 00:28:42 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: syscall.c,v 1.37.12.2 2009/08/21 17:46:23 matt Exp $ */ +/* $NetBSD: syscall.c,v 1.37.12.3 2009/08/22 00:28:42 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.2 2009/08/21 17:46:23 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.37.12.3 2009/08/22 00:28:42 matt Exp $"); #if defined(_KERNEL_OPT) #include "opt_sa.h" @@ -115,6 +115,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/endian.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/signal.h> @@ -167,12 +168,7 @@ struct proc *p = l->l_proc; 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 *args = NULL; register_t copyargs[2+SYS_MAXSYSARGS]; mips_reg_t saved_v0; vaddr_t usp; @@ -199,7 +195,9 @@ frame->f_regs[_R_PC] = opc + sizeof(uint32_t); callp = p->p_emul->e_sysent; - saved_v0 = code = frame->f_regs[_R_V0] - SYSCALL_SHIFT; + saved_v0 = code = frame->f_regs[_R_V0]; + + code -= SYSCALL_SHIFT; #ifdef KERN_SA if (__predict_false((l->l_savp) @@ -229,13 +227,12 @@ else callp += code; + nargs = callp->sy_argsize; + frame->f_regs[_R_V0] = 0; #if !defined(__mips_o32) if (abi != _MIPS_BSD_API_O32) { #endif 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) { /* @@ -260,51 +257,124 @@ goto bad; } #if !defined(__mips_o32) - } else { + } else do { + /* + * The only difference between O32 and N32 is the calling + * sequence. If you make O32 + */ + int32_t copy32args[SYS_MAXSYSARGS]; + int32_t *cargs = copy32args; + unsigned int arg64mask = SYCALL_ARG_64_MASK(callp); + bool doing_arg64; + size_t narg64 = SYCALL_NARGS64(callp); /* * All arguments are 32bits wide and 64bit arguments use - * two 32bit registers or stack slots. + * two 32bit registers or stack slots. We need to remarshall + * them into 64bit slots */ - nargs = callp->sy_argsize / sizeof(copy32args[0]); - rval = copy32rval; - args = copy32args; - copy32rval[0] = 0; - copy32rval[1] = frame->f_regs[_R_V1]; + args = copyargs; CTASSERT(sizeof(copy32args[0]) != sizeof(fargs[0])); + /* - * Copy the register passed arguments from the trapframe to - * the set of 32bit copies. + * If there are no 64bit arguments and all arguments were in + * registers, just use the frame for the source of arguments */ - for (i = 0; i < 4 && i < nargs; i++) - copy32args[i] = fargs[i]; - if (nargs > nregs) { + if (nargs <= nregs && narg64 == 0) { + args = fargs; + break; + } + + if (nregs <= nargs + narg64) { /* - * Copy the remainder of the arguments from the stack - * after skipped the slots for the 4 register passed + * Grab the non-register arguments from the stack + * after skipping 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])); + error = copyin((register32_t *)usp, copy32args, + (nargs + narg64 - nregs) * sizeof(copy32args[0])); if (error) goto bad; } - } + /* + * Copy all the arguments to copyargs, starting with the ones + * in registers. Using the hints in the 64bit argmask, + * we marshall the passed 32bit values into 64bit slots. If we + * encounter a 64 bit argument, we grab two adjacent 32bit + * values and synthesize the 64bit argument. + */ + for (i = 0, doing_arg64 = false; i < nargs + narg64;) { + register_t arg; + if (nregs > 0) { + arg = (int32_t) *fargs++; + nregs--; + } else { + arg = *cargs++; + } + if (__predict_true((arg64mask & 1) == 0)) { + /* + * Just copy it with sign extension on + */ + copyargs[i++] = (int32_t) arg; + arg64mask >>= 1; + continue; + } + /* + * 64bit arg. grab the low 32 bits, discard the high. + */ + arg = (uint32_t)arg; + if (!doing_arg64) { + /* + * Pick up the 1st word of a 64bit arg. + * If lowword == 1 then highword == 0, + * so this is the highword and thus + * shifted left by 32, otherwise + * lowword == 0 and highword == 1 so + * it isn't shifted at all. Remember + * we still need another word. + */ + doing_arg64 = true; + copyargs[i] = arg << (_QUAD_LOWWORD*32); + narg64--; /* one less 64bit arg */ + } else { + /* + * Pick up the 2nd word of a 64bit arg. + * if highword == 1, it's shifted left + * by 32, otherwise lowword == 1 and + * highword == 0 so it isn't shifted at + * all. And now head to the next argument. + */ + doing_arg64 = false; + copyargs[i++] |= arg << (_QUAD_HIGHWORD*32); + arg64mask >>= 1; + } + } + } while (/*CONSTCOND*/ 0); /* avoid a goto */ #endif if (__predict_false(p->p_trace_enabled) && (error = trace_enter(code, args, nargs)) != 0) goto out; - error = (*callp->sy_call)(l, args, rval); + error = (*callp->sy_call)(l, args, &frame->f_regs[_R_V0]); out: switch (error) { case 0: #if !defined(__mips_o32) - if (abi == _MIPS_BSD_API_O32) { - frame->f_regs[_R_V0] = copy32rval[0]; - frame->f_regs[_R_V1] = copy32rval[1]; + if (abi == _MIPS_BSD_API_O32 && SYCALL_RET_64_P(callp)) { + /* + * If this is from O32 and it's a 64bit quantity, + * split it into 2 32bit values in adjacent registers. + */ +#if BYTE_ORDER == BIG_ENDIAN + frame->f_regs[_R_V1] = (int32_t) frame->f_regs[_R_V0]; + frame->f_regs[_R_V0] >>= 32; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + frame->f_regs[_R_V1] = frame->f_regs[_R_V0] >> 32; + frame->f_regs[_R_V0] = (int32_t) frame->f_regs[_R_V0]; +#endif } #endif frame->f_regs[_R_A3] = 0;