diff options
Diffstat (limited to 'bsd-user/main.c')
-rw-r--r-- | bsd-user/main.c | 116 |
1 files changed, 94 insertions, 22 deletions
diff --git a/bsd-user/main.c b/bsd-user/main.c index 1bba2b5055..19b7f3a1f7 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -46,6 +46,7 @@ int have_guest_base; static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; extern char **environ; +enum BSDType bsd_type; /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example @@ -168,7 +169,7 @@ static void set_idt(int n, unsigned int dpl) } #endif -void cpu_loop(CPUX86State *env, enum BSDType bsd_type) +void cpu_loop(CPUX86State *env) { int trapnr; abi_ulong pc; @@ -179,27 +180,90 @@ void cpu_loop(CPUX86State *env, enum BSDType bsd_type) switch(trapnr) { case 0x80: /* syscall from int $0x80 */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); + if (bsd_type == target_freebsd) { + abi_ulong params = (abi_ulong) env->regs[R_ESP] + + sizeof(int32_t); + int32_t syscall_nr = env->regs[R_EAX]; + int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; + + if (syscall_nr == TARGET_FREEBSD_NR_syscall) { + get_user_s32(syscall_nr, params); + params += sizeof(int32_t); + } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { + get_user_s32(syscall_nr, params); + params += sizeof(int64_t); + } + get_user_s32(arg1, params); + params += sizeof(int32_t); + get_user_s32(arg2, params); + params += sizeof(int32_t); + 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); + params += sizeof(int32_t); + get_user_s32(arg7, params); + params += sizeof(int32_t); + get_user_s32(arg8, params); + env->regs[R_EAX] = do_freebsd_syscall(env, + syscall_nr, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); + } else { //if (bsd_type == target_openbsd) + env->regs[R_EAX] = do_openbsd_syscall(env, + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); + } + if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { + env->regs[R_EAX] = -env->regs[R_EAX]; + env->eflags |= CC_C; + } else { + env->eflags &= ~CC_C; + } break; #ifndef TARGET_ABI32 case EXCP_SYSCALL: - /* linux syscall from syscall intruction */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EDI], - env->regs[R_ESI], - env->regs[R_EDX], - env->regs[10], - env->regs[8], - env->regs[9]); + /* syscall from syscall intruction */ + if (bsd_type == target_freebsd) + env->regs[R_EAX] = do_freebsd_syscall(env, + env->regs[R_EAX], + env->regs[R_EDI], + env->regs[R_ESI], + env->regs[R_EDX], + env->regs[R_ECX], + env->regs[8], + env->regs[9], 0, 0); + else { //if (bsd_type == target_openbsd) + env->regs[R_EAX] = do_openbsd_syscall(env, + env->regs[R_EAX], + env->regs[R_EDI], + env->regs[R_ESI], + env->regs[R_EDX], + env->regs[10], + env->regs[8], + env->regs[9]); + } env->eip = env->exception_next_eip; + if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { + env->regs[R_EAX] = -env->regs[R_EAX]; + env->eflags |= CC_C; + } else { + env->eflags &= ~CC_C; + } break; #endif #if 0 @@ -446,7 +510,7 @@ static void flush_windows(CPUSPARCState *env) #endif } -void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) +void cpu_loop(CPUSPARCState *env) { int trapnr, ret, syscall_nr; //target_siginfo_t info; @@ -458,6 +522,10 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) #ifndef TARGET_SPARC64 case 0x80: #else + /* FreeBSD uses 0x141 for syscalls too */ + case 0x141: + if (bsd_type != target_freebsd) + goto badtrap; case 0x100: #endif syscall_nr = env->gregs[1]; @@ -465,7 +533,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) ret = do_freebsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5]); + env->regwptr[4], env->regwptr[5], 0, 0); else if (bsd_type == target_netbsd) ret = do_netbsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], @@ -482,6 +550,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) env->regwptr[4], env->regwptr[5]); } if ((unsigned int)ret >= (unsigned int)(-515)) { + ret = -ret; #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) env->xcc |= PSR_CARRY; #else @@ -587,6 +656,9 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type) } break; default: +#ifdef TARGET_SPARC64 + badtrap: +#endif printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); exit (1); @@ -668,7 +740,7 @@ int main(int argc, char **argv) int gdbstub_port = 0; char **target_environ, **wrk; envlist_t *envlist = NULL; - enum BSDType bsd_type = target_openbsd; + bsd_type = target_openbsd; if (argc <= 1) usage(); @@ -1033,7 +1105,7 @@ int main(int argc, char **argv) gdbserver_start (gdbstub_port); gdb_handlesig(env, 0); } - cpu_loop(env, bsd_type); + cpu_loop(env); /* never exits */ return 0; } |