On 28/09/2021 03:00, Richard Henderson wrote:
> Create and record the two signal trampolines.
> Use them when the guest does not use SA_RESTORER.
>
> Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/sparc/target_signal.h | 4 ++++
> linux-user/sparc/signal.c | 40 +++++++++++++++++++++-----------
> 2 files changed, 30 insertions(+), 14 deletions(-)
>
> diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
> index 34f9a12519..e661ddd6ab 100644
> --- a/linux-user/sparc/target_signal.h
> +++ b/linux-user/sparc/target_signal.h
> @@ -69,6 +69,10 @@ typedef struct target_sigaltstack {
>
> #ifdef TARGET_ABI32
> #define TARGET_ARCH_HAS_SETUP_FRAME
> +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
> +#else
> +/* For sparc64, use of KA_RESTORER is mandatory. */
> +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
> #endif
>
> /* bit-flags */
> diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
> index 3bc023d281..23e1e761de 100644
> --- a/linux-user/sparc/signal.c
> +++ b/linux-user/sparc/signal.c
> @@ -242,6 +242,12 @@ static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
> }
>
> #ifdef TARGET_ARCH_HAS_SETUP_FRAME
> +static void install_sigtramp(uint32_t *tramp, int syscall)
> +{
> + __put_user(0x82102000u + syscall, &tramp[0]); /* mov syscall, %g1 */
> + __put_user(0x91d02010u, &tramp[1]); /* t 0x10 */
> +}
> +
> void setup_frame(int sig, struct target_sigaction *ka,
> target_sigset_t *set, CPUSPARCState *env)
> {
> @@ -291,13 +297,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
> if (ka->ka_restorer) {
> env->regwptr[WREG_O7] = ka->ka_restorer;
> } else {
> - env->regwptr[WREG_O7] = sf_addr +
> - offsetof(struct target_signal_frame, insns) - 2 * 4;
> -
> - /* mov __NR_sigreturn, %g1 */
> - __put_user(0x821020d8u, &sf->insns[0]);
> - /* t 0x10 */
> - __put_user(0x91d02010u, &sf->insns[1]);
> + /* Not used, but retain for ABI compatibility. */
> + install_sigtramp(sf->insns, TARGET_NR_sigreturn);
> + env->regwptr[WREG_O7] = default_sigreturn;
> }
> unlock_user(sf, sf_addr, sf_size);
> }
> @@ -358,13 +360,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> if (ka->ka_restorer) {
> env->regwptr[WREG_O7] = ka->ka_restorer;
> } else {
> - env->regwptr[WREG_O7] =
> - sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4;
> -
> - /* mov __NR_rt_sigreturn, %g1 */
> - __put_user(0x82102065u, &sf->insns[0]);
> - /* t 0x10 */
> - __put_user(0x91d02010u, &sf->insns[1]);
> + /* Not used, but retain for ABI compatibility. */
> + install_sigtramp(sf->insns, TARGET_NR_rt_sigreturn);
> + env->regwptr[WREG_O7] = default_rt_sigreturn;
> }
> #else
> env->regwptr[WREG_O7] = ka->ka_restorer;
> @@ -775,4 +773,18 @@ do_sigsegv:
> unlock_user_struct(ucp, ucp_addr, 1);
> force_sig(TARGET_SIGSEGV);
> }
> +#else
> +void setup_sigtramp(abi_ulong sigtramp_page)
> +{
> + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
> + assert(tramp != NULL);
> +
> + default_sigreturn = sigtramp_page;
> + install_sigtramp(tramp, TARGET_NR_sigreturn);
> +
> + default_rt_sigreturn = sigtramp_page + 8;
> + install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
> +
> + unlock_user(tramp, sigtramp_page, 2 * 8);
> +}
> #endif
This is certainly outside of my knowledge domain, however if it works in your tests
then happy to give:
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
ATB,
Mark.