diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2018-07-18 13:06:48 -0700 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2018-07-22 21:33:45 +0200 |
commit | fa97e38eed3bbdbc322d94092ca49450e724fff1 (patch) | |
tree | 3bce29b6e2fdb36090534f8cd9f1848fef58f4db /linux-user | |
parent | 33143c446eb88de28ea3088b279feda8f693e398 (diff) |
linux-user/ppc: Implement swapcontext syscall
This allows the tests generated by debian-powerpc-user-cross
to function properly, especially tests/test-coroutine.
Technically this syscall is available to both ppc32 and ppc64,
but only ppc32 glibc actually uses it. Thus the ppc64 path is
untested.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20180718200648.22529-1-richard.henderson@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/ppc/signal.c | 56 | ||||
-rw-r--r-- | linux-user/qemu.h | 2 | ||||
-rw-r--r-- | linux-user/syscall.c | 6 |
3 files changed, 64 insertions, 0 deletions
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index ef4c518f11..2ae120a2bc 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -675,3 +675,59 @@ sigsegv: force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } + +/* This syscall implements {get,set,swap}context for userland. */ +abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, + abi_ulong unew_ctx, abi_long ctx_size) +{ + struct target_ucontext *uctx; + struct target_mcontext *mctx; + + /* For ppc32, ctx_size is "reserved for future use". + * For ppc64, we do not yet support the VSX extension. + */ + if (ctx_size < sizeof(struct target_ucontext)) { + return -TARGET_EINVAL; + } + + if (uold_ctx) { + TaskState *ts = (TaskState *)thread_cpu->opaque; + + if (!lock_user_struct(VERIFY_WRITE, uctx, uold_ctx, 1)) { + return -TARGET_EFAULT; + } + +#ifdef TARGET_PPC64 + mctx = &uctx->tuc_sigcontext.mcontext; +#else + /* ??? The kernel aligns the pointer down here into padding, but + * in setup_rt_frame we don't. Be self-compatible for now. + */ + mctx = &uctx->tuc_mcontext; + __put_user(h2g(mctx), &uctx->tuc_regs); +#endif + + save_user_regs(env, mctx); + host_to_target_sigset(&uctx->tuc_sigmask, &ts->signal_mask); + + unlock_user_struct(uctx, uold_ctx, 1); + } + + if (unew_ctx) { + int err; + + if (!lock_user_struct(VERIFY_READ, uctx, unew_ctx, 1)) { + return -TARGET_EFAULT; + } + err = do_setcontext(uctx, env, 0); + unlock_user_struct(uctx, unew_ctx, 1); + + if (err) { + /* We cannot return to a partially updated context. */ + force_sig(TARGET_SIGSEGV); + } + return -TARGET_QEMU_ESIGRETURN; + } + + return 0; +} diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7b16a1cdea..b4959e41c6 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -396,6 +396,8 @@ long do_sigreturn(CPUArchState *env); long do_rt_sigreturn(CPUArchState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, + abi_ulong unew_ctx, abi_long ctx_size); /** * block_signals: block all signals while handling this guest syscall * diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3df3bdffb2..dfc851cc35 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -12790,6 +12790,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5)); break; #endif +#ifdef TARGET_NR_swapcontext + case TARGET_NR_swapcontext: + /* PowerPC specific. */ + ret = do_swapcontext(cpu_env, arg1, arg2, arg3); + break; +#endif default: unimplemented: |