diff options
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/arm/trap.c | 37 | ||||
-rw-r--r-- | sys/arm/arm/vm_machdep.c | 53 |
2 files changed, 54 insertions, 36 deletions
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 |