diff options
Diffstat (limited to 'linux-user')
| -rw-r--r-- | linux-user/main.c | 24 | ||||
| -rw-r--r-- | linux-user/syscall.c | 99 | ||||
| -rw-r--r-- | linux-user/syscall_defs.h | 10 |
3 files changed, 107 insertions, 26 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 99a7cde559..b240f290f7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -31,7 +31,7 @@ #include "cache-utils.h" /* For tb_lock */ #include "exec-all.h" - +#include "tcg.h" #include "qemu-timer.h" #include "envlist.h" @@ -2434,7 +2434,7 @@ void cpu_loop (CPUState *env) info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = 0; /* ??? SEGV_MAPERR vs SEGV_ACCERR. */ - info._sifields._sigfault._addr = env->pc; + info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR]; queue_signal(env, info.si_signo, &info); break; case EXCP_DTB_MISS_PAL: @@ -2458,7 +2458,7 @@ void cpu_loop (CPUState *env) info.si_signo = TARGET_SIGBUS; info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; - info._sifields._sigfault._addr = env->pc; + info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR]; queue_signal(env, info.si_signo, &info); break; case EXCP_OPCDEC: @@ -2499,8 +2499,15 @@ void cpu_loop (CPUState *env) env->ir[IR_A0], env->ir[IR_A1], env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], env->ir[IR_A5]); - if (trapnr != TARGET_NR_sigreturn - && trapnr != TARGET_NR_rt_sigreturn) { + if (trapnr == TARGET_NR_sigreturn + || trapnr == TARGET_NR_rt_sigreturn) { + break; + } + /* Syscall writes 0 to V0 to bypass error check, similar + to how this is handled internal to Linux kernel. */ + if (env->ir[IR_V0] == 0) { + env->ir[IR_V0] = sysret; + } else { env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret); env->ir[IR_A3] = (sysret < 0); } @@ -2977,6 +2984,13 @@ int main(int argc, char **argv, char **envp) syscall_init(); signal_init(); +#if defined(CONFIG_USE_GUEST_BASE) + /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay + generating the prologue until now so that the prologue can take + the real value of GUEST_BASE into account. */ + tcg_prologue_init(&tcg_ctx); +#endif + #if defined(TARGET_I386) cpu_x86_set_cpl(env, 3); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ce728faa4d..8222cb92f1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -718,9 +718,17 @@ abi_long do_brk(abi_ulong new_brk) PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); - if (!is_error(mapped_addr)) +#if defined(TARGET_ALPHA) + /* We (partially) emulate OSF/1 on Alpha, which requires we + return a proper errno, not an unchanged brk value. */ + if (is_error(mapped_addr)) { + return -TARGET_ENOMEM; + } +#endif + + if (!is_error(mapped_addr)) { target_brk = new_brk; - + } return target_brk; } @@ -987,7 +995,8 @@ static abi_long do_pipe2(int host_pipe[], int flags) #endif } -static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, int flags) +static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, + int flags, int is_pipe2) { int host_pipe[2]; abi_long ret; @@ -995,20 +1004,25 @@ static abi_long do_pipe(void *cpu_env, abi_ulong pipedes, int flags) if (is_error(ret)) return get_errno(ret); -#if defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; - ret = host_pipe[0]; -#else -#if defined(TARGET_SH4) - if (!flags) { + + /* Several targets have special calling conventions for the original + pipe syscall, but didn't replicate this into the pipe2 syscall. */ + if (!is_pipe2) { +#if defined(TARGET_ALPHA) + ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1]; + return host_pipe[0]; +#elif defined(TARGET_MIPS) + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; + return host_pipe[0]; +#elif defined(TARGET_SH4) ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; - ret = host_pipe[0]; - } else + return host_pipe[0]; #endif + } + if (put_user_s32(host_pipe[0], pipedes) || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0]))) return -TARGET_EFAULT; -#endif return get_errno(ret); } @@ -4483,13 +4497,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_lseek: ret = get_errno(lseek(arg1, arg2, arg3)); break; -#ifdef TARGET_NR_getxpid +#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA) + /* Alpha specific */ case TARGET_NR_getxpid: -#else - case TARGET_NR_getpid: + ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid(); + ret = get_errno(getpid()); + break; #endif +#ifdef TARGET_NR_getpid + case TARGET_NR_getpid: ret = get_errno(getpid()); break; +#endif case TARGET_NR_mount: { /* need to look at the data field */ @@ -4698,11 +4717,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(dup(arg1)); break; case TARGET_NR_pipe: - ret = do_pipe(cpu_env, arg1, 0); + ret = do_pipe(cpu_env, arg1, 0, 0); break; #ifdef TARGET_NR_pipe2 case TARGET_NR_pipe2: - ret = do_pipe(cpu_env, arg1, arg2); + ret = do_pipe(cpu_env, arg1, arg2, 1); break; #endif case TARGET_NR_times: @@ -4964,11 +4983,41 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_sigprocmask case TARGET_NR_sigprocmask: { - int how = arg1; +#if defined(TARGET_ALPHA) + sigset_t set, oldset; + abi_ulong mask; + int how; + + switch (arg1) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -TARGET_EINVAL; + goto fail; + } + mask = arg2; + target_to_host_old_sigset(&set, &mask); + + ret = get_errno(sigprocmask(how, &set, &oldset)); + + if (!is_error(ret)) { + host_to_target_old_sigset(&mask, &oldset); + ret = mask; + ((CPUAlphaState *)cpu_env)->[IR_V0] = 0; /* force no error */ + } +#else sigset_t set, oldset, *set_ptr; + int how; if (arg2) { - switch(how) { + switch (arg1) { case TARGET_SIG_BLOCK: how = SIG_BLOCK; break; @@ -4991,13 +5040,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, how = 0; set_ptr = NULL; } - ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); + ret = get_errno(sigprocmask(how, set_ptr, &oldset)); if (!is_error(ret) && arg3) { if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) goto efault; host_to_target_old_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } +#endif } break; #endif @@ -5069,10 +5119,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigsuspend: { sigset_t set; +#if defined(TARGET_ALPHA) + abi_ulong mask = arg1; + target_to_host_old_sigset(&set, &mask); +#else if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg1, 0); +#endif ret = get_errno(sigsuspend(&set)); } break; @@ -5213,6 +5268,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#ifdef TARGET_NR_pselect6 + case TARGET_NR_pselect6: + goto unimplemented_nowarn; +#endif case TARGET_NR_symlink: { void *p2; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 255e89cbd8..681021ca0e 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -336,6 +336,14 @@ int do_sigaction(int sig, const struct target_sigaction *act, #if !defined(TARGET_ABI_MIPSN32) && !defined(TARGET_ABI_MIPSN64) #define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */ #endif +#elif defined(TARGET_ALPHA) +#define TARGET_SA_ONSTACK 0x00000001 +#define TARGET_SA_RESTART 0x00000002 +#define TARGET_SA_NOCLDSTOP 0x00000004 +#define TARGET_SA_NODEFER 0x00000008 +#define TARGET_SA_RESETHAND 0x00000010 +#define TARGET_SA_NOCLDWAIT 0x00000020 /* not supported yet */ +#define TARGET_SA_SIGINFO 0x00000040 #else #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ @@ -670,7 +678,7 @@ struct target_rlimit { }; #if defined(TARGET_ALPHA) -#define TARGET_RLIM_INFINITY 0x7ffffffffffffffful +#define TARGET_RLIM_INFINITY 0x7fffffffffffffffull #elif defined(TARGET_MIPS) || defined(TARGET_SPARC) #define TARGET_RLIM_INFINITY 0x7fffffffUL #else |