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;