summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/trap.c34
-rw-r--r--sys/amd64/amd64/vm_machdep.c39
-rw-r--r--sys/arm/arm/trap.c37
-rw-r--r--sys/arm/arm/vm_machdep.c53
-rw-r--r--sys/i386/i386/trap.c30
-rw-r--r--sys/i386/i386/vm_machdep.c36
-rw-r--r--sys/ia64/ia64/trap.c21
-rw-r--r--sys/ia64/ia64/vm_machdep.c31
-rw-r--r--sys/mips/include/pcb.h1
-rw-r--r--sys/mips/mips/trap.c42
-rw-r--r--sys/mips/mips/vm_machdep.c57
-rw-r--r--sys/powerpc/aim/trap.c39
-rw-r--r--sys/powerpc/aim/vm_machdep.c55
-rw-r--r--sys/powerpc/booke/trap.c37
-rw-r--r--sys/powerpc/booke/vm_machdep.c55
-rw-r--r--sys/sparc64/include/pcb.h3
-rw-r--r--sys/sparc64/sparc64/trap.c37
-rw-r--r--sys/sparc64/sparc64/vm_machdep.c37
-rw-r--r--sys/sun4v/sun4v/trap.c40
-rw-r--r--sys/sun4v/sun4v/vm_machdep.c37
-rw-r--r--sys/sys/proc.h2
21 files changed, 419 insertions, 304 deletions
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index c97985d..3f7ea81 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -1007,39 +1007,7 @@ syscall(struct trapframe *frame)
#endif
}
- switch (error) {
- case 0:
- frame->tf_rax = td->td_retval[0];
- frame->tf_rdx = td->td_retval[1];
- frame->tf_rflags &= ~PSL_C;
- break;
-
- case ERESTART:
- /*
- * Reconstruct pc, we know that 'syscall' is 2 bytes.
- * We have to do a full context restore so that %r10
- * (which was holding the value of %rcx) is restored for
- * the next iteration.
- */
- frame->tf_rip -= frame->tf_err;
- frame->tf_r10 = frame->tf_rcx;
- td->td_pcb->pcb_flags |= PCB_FULLCTX;
- break;
-
- case EJUSTRETURN:
- break;
-
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- frame->tf_rax = error;
- frame->tf_rflags |= PSL_C;
- break;
- }
+ cpu_set_syscall_retval(td, error);
/*
* Traced syscall.
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 51d1d62..6e56740 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -317,6 +317,45 @@ cpu_thread_free(struct thread *td)
cpu_thread_clean(td);
}
+void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+
+ switch (error) {
+ case 0:
+ td->td_frame->tf_rax = td->td_retval[0];
+ td->td_frame->tf_rdx = td->td_retval[1];
+ td->td_frame->tf_rflags &= ~PSL_C;
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct pc, we know that 'syscall' is 2 bytes.
+ * We have to do a full context restore so that %r10
+ * (which was holding the value of %rcx) is restored
+ * for the next iteration.
+ */
+ td->td_frame->tf_rip -= td->td_frame->tf_err;
+ td->td_frame->tf_r10 = td->td_frame->tf_rcx;
+ td->td_pcb->pcb_flags |= PCB_FULLCTX;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (td->td_proc->p_sysent->sv_errsize) {
+ if (error >= td->td_proc->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = td->td_proc->p_sysent->sv_errtbl[error];
+ }
+ td->td_frame->tf_rax = error;
+ td->td_frame->tf_rflags |= PSL_C;
+ break;
+ }
+}
+
/*
* Initialize machine state (pcb and trap frame) for a new thread about to
* upcall. Put enough state in the new thread's PCB to get it to go back
diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c
index e6150c0..348ec5a 100644
--- a/sys/arm/arm/trap.c
+++ b/sys/arm/arm/trap.c
@@ -932,43 +932,8 @@ syscall(struct thread *td, trapframe_t *frame, u_int32_t insn)
KASSERT(td->td_ar == NULL,
("returning from syscall with td_ar set!"));
}
- switch (error) {
- case 0:
-#ifdef __ARMEB__
- if ((insn & 0x000fffff) == SYS___syscall &&
- code != SYS_freebsd6_lseek && code != SYS_lseek) {
- /*
- * 64-bit return, 32-bit syscall. Fixup byte order
- */
- frame->tf_r0 = 0;
- frame->tf_r1 = td->td_retval[0];
- } else {
- frame->tf_r0 = td->td_retval[0];
- frame->tf_r1 = td->td_retval[1];
- }
-#else
- frame->tf_r0 = td->td_retval[0];
- frame->tf_r1 = td->td_retval[1];
-#endif
-
- frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
- 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;
- frame->tf_spsr |= PSR_C_bit; /* carry bit */
- break;
- }
+ cpu_set_syscall_retval(td, error);
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c
index 6bd5799..95b9ca8 100644
--- a/sys/arm/arm/vm_machdep.c
+++ b/sys/arm/arm/vm_machdep.c
@@ -51,6 +51,8 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/socketvar.h>
#include <sys/sf_buf.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
#include <sys/unistd.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
@@ -261,6 +263,57 @@ done:
#endif
}
+void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ trapframe_t *frame;
+ int fixup;
+#ifdef __ARMEB__
+ uint32_t insn;
+#endif
+
+ frame = td->td_frame;
+ fixup = 0;
+
+#ifdef __ARMEB__
+ insn = *(u_int32_t *)(frame->tf_pc - INSN_SIZE);
+ if ((insn & 0x000fffff) == SYS___syscall) {
+ register_t *ap = &frame->tf_r0;
+ register_t code = ap[_QUAD_LOWWORD];
+ if (td->td_proc->p_sysent->sv_mask)
+ code &= td->td_proc->p_sysent->sv_mask;
+ fixup = (code != SYS_freebsd6_lseek && code != SYS_lseek)
+ ? 1 : 0;
+ }
+#endif
+
+ switch (error) {
+ case 0:
+ if (fixup) {
+ frame->tf_r0 = 0;
+ frame->tf_r1 = td->td_retval[0];
+ } else {
+ frame->tf_r0 = td->td_retval[0];
+ frame->tf_r1 = td->td_retval[1];
+ }
+ frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
+ break;
+ case ERESTART:
+ /*
+ * Reconstruct the pc to point at the swi.
+ */
+ frame->tf_pc -= INSN_SIZE;
+ break;
+ case EJUSTRETURN:
+ /* nothing to do */
+ break;
+ default:
+ frame->tf_r0 = error;
+ frame->tf_spsr |= PSR_C_bit; /* carry bit */
+ break;
+ }
+}
+
/*
* Initialize machine state (pcb and trap frame) for a new thread about to
* upcall. Put enough state in the new thread's PCB to get it to go back
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index f4df668..f8d0ea0 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -1093,35 +1093,7 @@ syscall(struct trapframe *frame)
#endif
}
- switch (error) {
- case 0:
- frame->tf_eax = td->td_retval[0];
- frame->tf_edx = td->td_retval[1];
- frame->tf_eflags &= ~PSL_C;
- break;
-
- case ERESTART:
- /*
- * Reconstruct pc, assuming lcall $X,y is 7 bytes,
- * int 0x80 is 2 bytes. We saved this in tf_err.
- */
- frame->tf_eip -= frame->tf_err;
- break;
-
- case EJUSTRETURN:
- break;
-
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- frame->tf_eax = error;
- frame->tf_eflags |= PSL_C;
- break;
- }
+ cpu_set_syscall_retval(td, error);
/*
* Traced syscall.
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index e7f55a1..2948eb7 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/pioctl.h>
#include <sys/proc.h>
+#include <sys/sysent.h>
#include <sys/sf_buf.h>
#include <sys/smp.h>
#include <sys/sched.h>
@@ -380,6 +381,41 @@ cpu_thread_free(struct thread *td)
cpu_thread_clean(td);
}
+void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+
+ switch (error) {
+ case 0:
+ td->td_frame->tf_eax = td->td_retval[0];
+ td->td_frame->tf_edx = td->td_retval[1];
+ td->td_frame->tf_eflags &= ~PSL_C;
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, int
+ * 0x80 is 2 bytes. We saved this in tf_err.
+ */
+ td->td_frame->tf_eip -= td->td_frame->tf_err;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (td->td_proc->p_sysent->sv_errsize) {
+ if (error >= td->td_proc->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = td->td_proc->p_sysent->sv_errtbl[error];
+ }
+ td->td_frame->tf_eax = error;
+ td->td_frame->tf_eflags |= PSL_C;
+ break;
+ }
+}
+
/*
* Initialize machine state (pcb and trap frame) for a new thread about to
* upcall. Put enough state in the new thread's PCB to get it to go back
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c
index 2633ad2..2a4dca8 100644
--- a/sys/ia64/ia64/trap.c
+++ b/sys/ia64/ia64/trap.c
@@ -976,26 +976,7 @@ syscall(struct trapframe *tf)
error = (*callp->sy_call)(td, args);
AUDIT_SYSCALL_EXIT(error, td);
- if (error != EJUSTRETURN) {
- /*
- * Save the "raw" error code in r10. We use this to handle
- * syscall restarts (see do_ast()).
- */
- tf->tf_scratch.gr10 = error;
- if (error == 0) {
- tf->tf_scratch.gr8 = td->td_retval[0];
- tf->tf_scratch.gr9 = td->td_retval[1];
- } else if (error != ERESTART) {
- if (error < p->p_sysent->sv_errsize)
- error = p->p_sysent->sv_errtbl[error];
- /*
- * Translated error codes are returned in r8. User
- * processes use the translated error code.
- */
- tf->tf_scratch.gr8 = error;
- }
- }
-
+ cpu_set_syscall_retval(td, error);
td->td_syscalls++;
/*
diff --git a/sys/ia64/ia64/vm_machdep.c b/sys/ia64/ia64/vm_machdep.c
index e5088a5..37af94b 100644
--- a/sys/ia64/ia64/vm_machdep.c
+++ b/sys/ia64/ia64/vm_machdep.c
@@ -73,6 +73,7 @@
#include <sys/malloc.h>
#include <sys/bio.h>
#include <sys/buf.h>
+#include <sys/sysent.h>
#include <sys/vnode.h>
#include <sys/vmmeter.h>
#include <sys/kernel.h>
@@ -140,6 +141,36 @@ cpu_thread_swapout(struct thread *td)
}
void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ struct proc *p;
+ struct trapframe *tf;
+
+ if (error == EJUSTRETURN)
+ return;
+
+ tf = td->td_frame;
+
+ /*
+ * Save the "raw" error code in r10. We use this to handle
+ * syscall restarts (see do_ast()).
+ */
+ tf->tf_scratch.gr10 = error;
+ if (error == 0) {
+ tf->tf_scratch.gr8 = td->td_retval[0];
+ tf->tf_scratch.gr9 = td->td_retval[1];
+ } else if (error != ERESTART) {
+ p = td->td_proc;
+ if (error < p->p_sysent->sv_errsize)
+ error = p->p_sysent->sv_errtbl[error];
+ /*
+ * Translated error codes are returned in r8. User
+ */
+ tf->tf_scratch.gr8 = error;
+ }
+}
+
+void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
struct pcb *pcb;
diff --git a/sys/mips/include/pcb.h b/sys/mips/include/pcb.h
index 16d274d..f54f2d7 100644
--- a/sys/mips/include/pcb.h
+++ b/sys/mips/include/pcb.h
@@ -52,6 +52,7 @@ struct pcb
struct trapframe pcb_regs; /* saved CPU and registers */
label_t pcb_context; /* kernel context for resume */
int pcb_onfault; /* for copyin/copyout faults */
+ register_t pcb_tpc;
};
/* these match the regnum's in regnum.h
diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c
index 6d047cc..1124b1c 100644
--- a/sys/mips/mips/trap.c
+++ b/sys/mips/mips/trap.c
@@ -644,7 +644,6 @@ dofault:
struct trapframe *locr0 = td->td_frame;
struct sysent *callp;
unsigned int code;
- unsigned int tpc;
int nargs, nsaved;
register_t args[8];
@@ -660,7 +659,7 @@ dofault:
thread_user_enter(td);
#endif
/* compute next PC after syscall instruction */
- tpc = trapframe->pc; /* Remember if restart */
+ td->td_pcb->pcb_tpc = trapframe->pc; /* Remember if restart */
if (DELAYBRANCH(trapframe->cause)) { /* Check BD bit */
locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0,
0);
@@ -761,44 +760,7 @@ dofault:
locr0 = td->td_frame;
#endif
trapdebug_enter(locr0, -code);
- switch (i) {
- case 0:
- if (quad_syscall && code != SYS_lseek) {
- /*
- * System call invoked through the
- * SYS___syscall interface but the
- * return value is really just 32
- * bits.
- */
- locr0->v0 = td->td_retval[0];
- if (_QUAD_LOWWORD)
- locr0->v1 = td->td_retval[0];
- locr0->a3 = 0;
- } else {
- locr0->v0 = td->td_retval[0];
- locr0->v1 = td->td_retval[1];
- locr0->a3 = 0;
- }
- break;
-
- case ERESTART:
- locr0->pc = tpc;
- break;
-
- case EJUSTRETURN:
- break; /* nothing to do */
-
- default:
- if (quad_syscall && code != SYS_lseek) {
- locr0->v0 = i;
- if (_QUAD_LOWWORD)
- locr0->v1 = i;
- locr0->a3 = 1;
- } else {
- locr0->v0 = i;
- locr0->a3 = 1;
- }
- }
+ cpu_set_syscall_retval(td, i);
/*
* The sync'ing of I & D caches for SYS_ptrace() is
diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c
index 26b6477..918c5f0 100644
--- a/sys/mips/mips/vm_machdep.c
+++ b/sys/mips/mips/vm_machdep.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/syscall.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/vmmeter.h>
@@ -256,6 +257,62 @@ cpu_thread_alloc(struct thread *td)
}
}
+void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ struct trapframe *locr0 = td->td_frame;
+ unsigned int code;
+ int quad_syscall;
+
+ code = locr0->v0;
+ quad_syscall = 0;
+ if (code == SYS_syscall)
+ code = locr0->a0;
+ else if (code == SYS___syscall) {
+ code = _QUAD_LOWWORD ? locr0->a1 : locr0->a0;
+ quad_syscall = 1;
+ }
+
+ switch (error) {
+ case 0:
+ if (quad_syscall && code != SYS_lseek) {
+ /*
+ * System call invoked through the
+ * SYS___syscall interface but the
+ * return value is really just 32
+ * bits.
+ */
+ locr0->v0 = td->td_retval[0];
+ if (_QUAD_LOWWORD)
+ locr0->v1 = td->td_retval[0];
+ locr0->a3 = 0;
+ } else {
+ locr0->v0 = td->td_retval[0];
+ locr0->v1 = td->td_retval[1];
+ locr0->a3 = 0;
+ }
+ break;
+
+ case ERESTART:
+ locr0->pc = td->td_pcb->pcb_tpc;
+ break;
+
+ case EJUSTRETURN:
+ break; /* nothing to do */
+
+ default:
+ if (quad_syscall && code != SYS_lseek) {
+ locr0->v0 = error;
+ if (_QUAD_LOWWORD)
+ locr0->v1 = error;
+ locr0->a3 = 1;
+ } else {
+ locr0->v0 = error;
+ locr0->a3 = 1;
+ }
+ }
+}
+
/*
* Initialize machine state (pcb and trap frame) for a new thread about to
* upcall. Put enough state in the new thread's PCB to get it to go back
diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c
index ee9c7d3..60c6bb0 100644
--- a/sys/powerpc/aim/trap.c
+++ b/sys/powerpc/aim/trap.c
@@ -415,43 +415,8 @@ syscall(struct trapframe *frame)
CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", td->td_name,
syscallnames[code], td->td_retval[0]);
}
- switch (error) {
- case 0:
- if (frame->fixreg[0] == SYS___syscall &&
- code != SYS_freebsd6_lseek && code != SYS_lseek) {
- /*
- * 64-bit return, 32-bit syscall. Fixup byte order
- */
- frame->fixreg[FIRSTARG] = 0;
- frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
- } else {
- frame->fixreg[FIRSTARG] = td->td_retval[0];
- frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
- }
- /* XXX: Magic number */
- frame->cr &= ~0x10000000;
- break;
- case ERESTART:
- /*
- * Set user's pc back to redo the system call.
- */
- frame->srr0 -= 4;
- break;
- case EJUSTRETURN:
- /* nothing to do */
- break;
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- frame->fixreg[FIRSTARG] = error;
- /* XXX: Magic number: Carry Flag Equivalent? */
- frame->cr |= 0x10000000;
- break;
- }
+
+ cpu_set_syscall_retval(td, error);
/*
* Check for misbehavior.
diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c
index af83854..3967176 100644
--- a/sys/powerpc/aim/vm_machdep.c
+++ b/sys/powerpc/aim/vm_machdep.c
@@ -81,7 +81,9 @@
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/sf_buf.h>
+#include <sys/syscall.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/unistd.h>
#include <machine/cpu.h>
@@ -422,6 +424,59 @@ cpu_thread_swapout(struct thread *td)
}
void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ struct proc *p;
+ struct trapframe *tf;
+ int fixup;
+
+ if (error == EJUSTRETURN)
+ return;
+
+ p = td->td_proc;
+ tf = td->td_frame;
+
+ if (tf->fixreg[0] == SYS___syscall) {
+ int code = tf->fixreg[FIRSTARG + 1];
+ if (p->p_sysent->sv_mask)
+ code &= p->p_sysent->sv_mask;
+ fixup = (code != SYS_freebsd6_lseek && code != SYS_lseek) ?
+ 1 : 0;
+ } else
+ fixup = 0;
+
+ switch (error) {
+ case 0:
+ if (fixup) {
+ /*
+ * 64-bit return, 32-bit syscall. Fixup byte order
+ */
+ tf->fixreg[FIRSTARG] = 0;
+ tf->fixreg[FIRSTARG + 1] = td->td_retval[0];
+ } else {
+ tf->fixreg[FIRSTARG] = td->td_retval[0];
+ tf->fixreg[FIRSTARG + 1] = td->td_retval[1];
+ }
+ tf->cr &= ~0x10000000; /* XXX: Magic number */
+ break;
+ case ERESTART:
+ /*
+ * Set user's pc back to redo the system call.
+ */
+ tf->srr0 -= 4;
+ break;
+ default:
+ if (p->p_sysent->sv_errsize) {
+ error = (error < p->p_sysent->sv_errsize) ?
+ p->p_sysent->sv_errtbl[error] : -1;
+ }
+ tf->fixreg[FIRSTARG] = error;
+ tf->cr |= 0x10000000; /* XXX: Magic number */
+ break;
+ }
+}
+
+void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
struct pcb *pcb2;
diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c
index 0e746f4..d98efb9 100644
--- a/sys/powerpc/booke/trap.c
+++ b/sys/powerpc/booke/trap.c
@@ -417,42 +417,7 @@ syscall(struct trapframe *frame)
syscallnames[code], td->td_retval[0]);
}
- switch (error) {
- case 0:
- if (frame->fixreg[0] == SYS___syscall && SYS_lseek) {
- /*
- * 64-bit return, 32-bit syscall. Fixup byte order
- */
- frame->fixreg[FIRSTARG] = 0;
- frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
- } else {
- frame->fixreg[FIRSTARG] = td->td_retval[0];
- frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
- }
- /* XXX: Magic number */
- frame->cr &= ~0x10000000;
- break;
- case ERESTART:
- /*
- * Set user's pc back to redo the system call.
- */
- frame->srr0 -= 4;
- break;
- case EJUSTRETURN:
- /* nothing to do */
- break;
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- frame->fixreg[FIRSTARG] = error;
- /* XXX: Magic number: Carry Flag Equivalent? */
- frame->cr |= 0x10000000;
- break;
- }
+ cpu_set_syscall_retval(td, error);
/*
* Check for misbehavior.
diff --git a/sys/powerpc/booke/vm_machdep.c b/sys/powerpc/booke/vm_machdep.c
index 178b863..7d2b88b 100644
--- a/sys/powerpc/booke/vm_machdep.c
+++ b/sys/powerpc/booke/vm_machdep.c
@@ -113,7 +113,9 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/sf_buf.h>
+#include <sys/syscall.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/unistd.h>
#include <machine/clock.h>
@@ -423,6 +425,59 @@ cpu_thread_swapout(struct thread *td)
}
void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+ struct proc *p;
+ struct trapframe *tf;
+ int fixup;
+
+ p = td->td_proc;
+ tf = td->td_frame;
+
+ if (tf->fixreg[0] == SYS___syscall) {
+ int code = tf->fixreg[FIRSTARG + 1];
+ if (p->p_sysent->sv_mask)
+ code &= p->p_sysent->sv_mask;
+ fixup = (code != SYS_freebsd6_lseek && code != SYS_lseek) ?
+ 1 : 0;
+ } else
+ fixup = 0;
+
+ switch (error) {
+ case 0:
+ if (fixup) {
+ /*
+ * 64-bit return, 32-bit syscall. Fixup byte order
+ */
+ tf->fixreg[FIRSTARG] = 0;
+ tf->fixreg[FIRSTARG + 1] = td->td_retval[0];
+ } else {
+ tf->fixreg[FIRSTARG] = td->td_retval[0];
+ tf->fixreg[FIRSTARG + 1] = td->td_retval[1];
+ }
+ tf->cr &= ~0x10000000; /* XXX: Magic number */
+ break;
+ case ERESTART:
+ /*
+ * Set user's pc back to redo the system call.
+ */
+ tf->srr0 -= 4;
+ break;
+ case EJUSTRETURN:
+ /* nothing to do */
+ break;
+ default:
+ if (p->p_sysent->sv_errsize) {
+ error = (error < p->p_sysent->sv_errsize) ?
+ p->p_sysent->sv_errtbl[error] : -1;
+ }
+ tf->fixreg[FIRSTARG] = error;
+ tf->cr |= 0x10000000; /* XXX: Magic number */
+ break;
+ }
+}
+
+void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
struct pcb *pcb2;
diff --git a/sys/sparc64/include/pcb.h b/sys/sparc64/include/pcb.h
index 7e8294a..f23c1f2 100644
--- a/sys/sparc64/include/pcb.h
+++ b/sys/sparc64/include/pcb.h
@@ -49,7 +49,8 @@ struct pcb {
uint64_t pcb_nsaved;
uint64_t pcb_pc;
uint64_t pcb_sp;
- uint64_t pcb_pad[4];
+ uint64_t pcb_tpc;
+ uint64_t pcb_pad[3];
} __aligned(64);
#ifdef _KERNEL
diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c
index 702e4f1..0c07eaf 100644
--- a/sys/sparc64/sparc64/trap.c
+++ b/sys/sparc64/sparc64/trap.c
@@ -538,7 +538,6 @@ syscall(struct trapframe *tf)
register_t *argp;
struct proc *p;
u_long code;
- u_long tpc;
int reg;
int regcnt;
int narg;
@@ -562,7 +561,7 @@ syscall(struct trapframe *tf)
* For syscalls, we don't want to retry the faulting instruction
* (usually), instead we need to advance one instruction.
*/
- tpc = tf->tf_tpc;
+ td->td_pcb->pcb_tpc = tf->tf_tpc;
TF_DONE(tf);
reg = 0;
@@ -626,39 +625,7 @@ syscall(struct trapframe *tf)
td->td_retval[1]);
}
- /*
- * MP SAFE (we may or may not have the MP lock at this point)
- */
- switch (error) {
- case 0:
- tf->tf_out[0] = td->td_retval[0];
- tf->tf_out[1] = td->td_retval[1];
- tf->tf_tstate &= ~TSTATE_XCC_C;
- break;
-
- case ERESTART:
- /*
- * Undo the tpc advancement we have done above, we want to
- * reexecute the system call.
- */
- tf->tf_tpc = tpc;
- tf->tf_tnpc -= 4;
- break;
-
- case EJUSTRETURN:
- break;
-
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- tf->tf_out[0] = error;
- tf->tf_tstate |= TSTATE_XCC_C;
- break;
- }
+ cpu_set_syscall_retval(td, error);
/*
* Check for misbehavior.
diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c
index 76521a6..009f45d 100644
--- a/sys/sparc64/sparc64/vm_machdep.c
+++ b/sys/sparc64/sparc64/vm_machdep.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/proc.h>
+#include <sys/sysent.h>
#include <sys/sf_buf.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
@@ -166,6 +167,42 @@ cpu_thread_swapout(struct thread *td)
}
void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+
+ switch (error) {
+ case 0:
+ td->td_frame->tf_out[0] = td->td_retval[0];
+ td->td_frame->tf_out[1] = td->td_retval[1];
+ td->td_frame->tf_tstate &= ~TSTATE_XCC_C;
+ break;
+
+ case ERESTART:
+ /*
+ * Undo the tpc advancement we have done on syscall
+ * enter, we want to reexecute the system call.
+ */
+ td->td_frame->tf_tpc = td->td_pcb->pcb_tpc;
+ td->td_frame->tf_tnpc -= 4;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (td->td_proc->p_sysent->sv_errsize) {
+ if (error >= td->td_proc->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = td->td_proc->p_sysent->sv_errtbl[error];
+ }
+ td->td_frame->tf_out[0] = error;
+ td->td_frame->tf_tstate |= TSTATE_XCC_C;
+ break;
+ }
+}
+
+void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
struct trapframe *tf;
diff --git a/sys/sun4v/sun4v/trap.c b/sys/sun4v/sun4v/trap.c
index ffa0e8c..353462d 100644
--- a/sys/sun4v/sun4v/trap.c
+++ b/sys/sun4v/sun4v/trap.c
@@ -81,6 +81,7 @@
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
+#include <machine/pcb.h>
#include <machine/smp.h>
#include <machine/trap.h>
#include <machine/tstate.h>
@@ -582,7 +583,6 @@ syscall(struct trapframe *tf)
register_t *argp;
struct proc *p;
u_long code;
- u_long tpc;
int reg;
int regcnt;
int narg;
@@ -606,7 +606,7 @@ syscall(struct trapframe *tf)
* For syscalls, we don't want to retry the faulting instruction
* (usually), instead we need to advance one instruction.
*/
- tpc = tf->tf_tpc;
+ td->td_pcb->pcb_tpc = tf->tf_tpc;
TF_DONE(tf);
reg = 0;
@@ -673,40 +673,8 @@ syscall(struct trapframe *tf)
error, syscallnames[code], td->td_retval[0],
td->td_retval[1]);
}
-
- /*
- * MP SAFE (we may or may not have the MP lock at this point)
- */
- switch (error) {
- case 0:
- tf->tf_out[0] = td->td_retval[0];
- tf->tf_out[1] = td->td_retval[1];
- tf->tf_tstate &= ~TSTATE_XCC_C;
- break;
-
- case ERESTART:
- /*
- * Undo the tpc advancement we have done above, we want to
- * reexecute the system call.
- */
- tf->tf_tpc = tpc;
- tf->tf_tnpc -= 4;
- break;
-
- case EJUSTRETURN:
- break;
-
- default:
- if (p->p_sysent->sv_errsize) {
- if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
- else
- error = p->p_sysent->sv_errtbl[error];
- }
- tf->tf_out[0] = error;
- tf->tf_tstate |= TSTATE_XCC_C;
- break;
- }
+
+ cpu_set_syscall_retval(td, error);
/*
* Handle reschedule and other end-of-syscall issues
diff --git a/sys/sun4v/sun4v/vm_machdep.c b/sys/sun4v/sun4v/vm_machdep.c
index 63a002f..5e02aec 100644
--- a/sys/sun4v/sun4v/vm_machdep.c
+++ b/sys/sun4v/sun4v/vm_machdep.c
@@ -57,6 +57,7 @@
#include <sys/mutex.h>
#include <sys/sf_buf.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/unistd.h>
#include <sys/vmmeter.h>
@@ -142,6 +143,42 @@ cpu_thread_swapout(struct thread *td)
}
void
+cpu_set_syscall_retval(struct thread *td, int error)
+{
+
+ switch (error) {
+ case 0:
+ td->td_frame->tf_out[0] = td->td_retval[0];
+ td->td_frame->tf_out[1] = td->td_retval[1];
+ td->td_frame->tf_tstate &= ~TSTATE_XCC_C;
+ break;
+
+ case ERESTART:
+ /*
+ * Undo the tpc advancement we have done on syscall
+ * enter, we want to reexecute the system call.
+ */
+ td->td_frame->tf_tpc = td->td_pcb->pcb_tpc;
+ td->td_frame->tf_tnpc -= 4;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (td->td_proc->p_sysent->sv_errsize) {
+ if (error >= td->td_proc->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = td->td_proc->p_sysent->sv_errtbl[error];
+ }
+ td->td_frame->tf_out[0] = error;
+ td->td_frame->tf_tstate |= TSTATE_XCC_C;
+ break;
+ }
+}
+
+void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
struct trapframe *tf;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 384f280..3eb6ea6 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -836,7 +836,7 @@ void cpu_exit(struct thread *);
void exit1(struct thread *, int) __dead2;
void cpu_fork(struct thread *, struct proc *, struct thread *, int);
void cpu_set_fork_handler(struct thread *, void (*)(void *), void *);
-
+void cpu_set_syscall_retval(struct thread *, int);
void cpu_set_upcall(struct thread *td, struct thread *td0);
void cpu_set_upcall_kse(struct thread *, void (*)(void *), void *,
stack_t *);
OpenPOWER on IntegriCloud