Implement the system call dispatch. This implements all three kinds of system call: direct and the two indirect variants. It handles all the special cases for thumb as well.
Signed-off-by: Stacey Son <s...@freebsd.org> Signed-off-by: Klye Evans <kev...@freebsd.org> Signed-off-by: Warner Losh <i...@bsdimp.com> --- bsd-user/arm/target_arch_cpu.h | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h index 62d6ee89b6..bc2eb05cfe 100644 --- a/bsd-user/arm/target_arch_cpu.h +++ b/bsd-user/arm/target_arch_cpu.h @@ -39,6 +39,7 @@ static inline void target_cpu_loop(CPUARMState *env) { int trapnr; target_siginfo_t info; + unsigned int n; CPUState *cs = env_cpu(env); for (;;) { @@ -57,6 +58,100 @@ static inline void target_cpu_loop(CPUARMState *env) queue_signal(env, info.si_signo, &info); } break; + case EXCP_SWI: + case EXCP_BKPT: + { + env->eabi = 1; /* FreeBSD is eabi only now */ + /* + * system call + * See arm/arm/trap.c cpu_fetch_syscall_args() + */ + if (trapnr == EXCP_BKPT) { + if (env->thumb) { + env->regs[15] += 2; + } else { + env->regs[15] += 4; + } + } + n = env->regs[7]; + if (bsd_type == target_freebsd) { + int ret; + abi_ulong params = get_sp_from_cpustate(env); + int32_t syscall_nr = n; + int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; + + /* See arm/arm/trap.c cpu_fetch_syscall_args() */ + if (syscall_nr == TARGET_FREEBSD_NR_syscall) { + syscall_nr = env->regs[0]; + arg1 = env->regs[1]; + arg2 = env->regs[2]; + arg3 = env->regs[3]; + get_user_s32(arg4, params); + params += sizeof(int32_t); + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + params += sizeof(int32_t); + get_user_s32(arg7, params); + arg8 = 0; + } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { + syscall_nr = env->regs[0]; + arg1 = env->regs[2]; + arg2 = env->regs[3]; + get_user_s32(arg3, params); + params += sizeof(int32_t); + get_user_s32(arg4, params); + params += sizeof(int32_t); + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + arg7 = 0; + arg8 = 0; + } else { + arg1 = env->regs[0]; + arg2 = env->regs[1]; + arg3 = env->regs[2]; + arg4 = env->regs[3]; + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + params += sizeof(int32_t); + get_user_s32(arg7, params); + params += sizeof(int32_t); + get_user_s32(arg8, params); + } + ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + /* + * Compare to arm/arm/vm_machdep.c + * cpu_set_syscall_retval() + */ + if (-TARGET_EJUSTRETURN == ret) { + /* + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. + */ + break; + } + if (-TARGET_ERESTART == ret) { + env->regs[15] -= env->thumb ? 2 : 4; + break; + } + if ((unsigned int)ret >= (unsigned int)(-515)) { + ret = -ret; + cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); + env->regs[0] = ret; + } else { + cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); + env->regs[0] = ret; /* XXX need to handle lseek()? */ + /* env->regs[1] = 0; */ + } + } else { + fprintf(stderr, "qemu: bsd_type (= %d) syscall " + "not supported\n", bsd_type); + } + } + break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -- 2.32.0