qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] linux-user/sparc64: Implement signals
@ 2021-04-25 15:57 Richard Henderson
  2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

We were re-using sparc32 signal handling for sparc64.
In the process, clean up the altstack handling in do_*_sigreturn.


r~


Richard Henderson (8):
  linux-user: Split out target_restore_altstack
  linux-user: Use target_restore_altstack in all sigreturn
  linux-user: Pass CPUArchState to do_sigaltstack
  linux-user: Pass CPUArchState to target_restore_altstack
  linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
  linux-user/sparc: Clean up init_thread
  linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate
  linux-user/sparc64: Implement signals

 linux-user/qemu.h                   |   3 +-
 linux-user/signal-common.h          |   1 +
 linux-user/sparc/target_cpu.h       |   9 +-
 linux-user/sparc/target_signal.h    |   2 +
 linux-user/sparc64/target_syscall.h |  14 +-
 linux-user/aarch64/signal.c         |   6 +-
 linux-user/alpha/signal.c           |   6 +-
 linux-user/arm/signal.c             |   9 +-
 linux-user/elfload.c                |  33 +-
 linux-user/hexagon/signal.c         |   6 +-
 linux-user/hppa/signal.c            |   8 +-
 linux-user/i386/signal.c            |   5 +-
 linux-user/m68k/signal.c            |   5 +-
 linux-user/microblaze/signal.c      |   6 +-
 linux-user/mips/signal.c            |   6 +-
 linux-user/nios2/signal.c           |   8 +-
 linux-user/openrisc/signal.c        |   5 +-
 linux-user/ppc/signal.c             |   4 +-
 linux-user/riscv/signal.c           |   6 +-
 linux-user/s390x/signal.c           |   6 +-
 linux-user/sh4/signal.c             |   7 +-
 linux-user/signal.c                 | 120 ++++---
 linux-user/sparc/signal.c           | 280 ---------------
 linux-user/sparc64/signal.c         | 523 +++++++++++++++++++++++++++-
 linux-user/syscall.c                |   3 +-
 linux-user/xtensa/signal.c          |   6 +-
 26 files changed, 633 insertions(+), 454 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/8] linux-user: Split out target_restore_altstack
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

Create a function to match target_save_altstack.
Fix some style and unlock issues in do_sigaltstack.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/signal-common.h |   1 +
 linux-user/signal.c        | 115 +++++++++++++++++++++----------------
 2 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 1df1068552..34b963af9a 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -24,6 +24,7 @@ int on_sig_stack(unsigned long sp);
 int sas_ss_flags(unsigned long sp);
 abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
 void target_save_altstack(target_stack_t *uss, CPUArchState *env);
+abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp);
 
 static inline void target_sigemptyset(target_sigset_t *set)
 {
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 44a5012930..306f3edec5 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -297,6 +297,50 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
     __put_user(ts->sigaltstack_used.ss_size, &uss->ss_size);
 }
 
+abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
+{
+    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    size_t minstacksize = TARGET_MINSIGSTKSZ;
+    target_stack_t ss;
+
+#if defined(TARGET_PPC64)
+    /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
+    struct image_info *image = ts->info;
+    if (get_ppc64_abi(image) > 1) {
+        minstacksize = 4096;
+    }
+#endif
+
+    __get_user(ss.ss_sp, &uss->ss_sp);
+    __get_user(ss.ss_size, &uss->ss_size);
+    __get_user(ss.ss_flags, &uss->ss_flags);
+
+    if (on_sig_stack(sp)) {
+        return -TARGET_EPERM;
+    }
+
+    switch (ss.ss_flags) {
+    default:
+        return -TARGET_EINVAL;
+
+    case TARGET_SS_DISABLE:
+        ss.ss_size = 0;
+        ss.ss_sp = 0;
+        break;
+
+    case TARGET_SS_ONSTACK:
+    case 0:
+        if (ss.ss_size < minstacksize) {
+            return -TARGET_ENOMEM;
+        }
+        break;
+    }
+
+    ts->sigaltstack_used.ss_sp = ss.ss_sp;
+    ts->sigaltstack_used.ss_size = ss.ss_size;
+    return 0;
+}
+
 /* siginfo conversion */
 
 static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -758,73 +802,44 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
 /* compare linux/kernel/signal.c:do_sigaltstack() */
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
 {
-    int ret;
-    struct target_sigaltstack oss;
-    TaskState *ts = (TaskState *)thread_cpu->opaque;
+    target_stack_t oss, *uoss = NULL;
+    abi_long ret = -TARGET_EFAULT;
 
-    /* XXX: test errors */
-    if(uoss_addr)
-    {
+    if (uoss_addr) {
+        TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+        /* Verify writability now, but do not alter user memory yet. */
+        if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) {
+            goto out;
+        }
         __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp);
         __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size);
         __put_user(sas_ss_flags(sp), &oss.ss_flags);
     }
 
-    if(uss_addr)
-    {
-        struct target_sigaltstack *uss;
-        struct target_sigaltstack ss;
-        size_t minstacksize = TARGET_MINSIGSTKSZ;
+    if (uss_addr) {
+        target_stack_t *uss;
 
-#if defined(TARGET_PPC64)
-        /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
-        struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
-        if (get_ppc64_abi(image) > 1) {
-            minstacksize = 4096;
-        }
-#endif
-
-        ret = -TARGET_EFAULT;
         if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
             goto out;
         }
-        __get_user(ss.ss_sp, &uss->ss_sp);
-        __get_user(ss.ss_size, &uss->ss_size);
-        __get_user(ss.ss_flags, &uss->ss_flags);
-        unlock_user_struct(uss, uss_addr, 0);
-
-        ret = -TARGET_EPERM;
-        if (on_sig_stack(sp))
+        ret = target_restore_altstack(uss, sp);
+        if (ret) {
             goto out;
-
-        ret = -TARGET_EINVAL;
-        if (ss.ss_flags != TARGET_SS_DISABLE
-            && ss.ss_flags != TARGET_SS_ONSTACK
-            && ss.ss_flags != 0)
-            goto out;
-
-        if (ss.ss_flags == TARGET_SS_DISABLE) {
-            ss.ss_size = 0;
-            ss.ss_sp = 0;
-        } else {
-            ret = -TARGET_ENOMEM;
-            if (ss.ss_size < minstacksize) {
-                goto out;
-            }
         }
-
-        ts->sigaltstack_used.ss_sp = ss.ss_sp;
-        ts->sigaltstack_used.ss_size = ss.ss_size;
     }
 
     if (uoss_addr) {
-        ret = -TARGET_EFAULT;
-        if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
-            goto out;
+        memcpy(uoss, &oss, sizeof(oss));
+        unlock_user_struct(uoss, uoss_addr, 1);
+        uoss = NULL;
     }
-
     ret = 0;
-out:
+
+ out:
+    if (uoss) {
+        unlock_user_struct(uoss, uoss_addr, 0);
+    }
     return ret;
 }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
  2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

Note that target_restore_altstack uses the host memory
pointer that we have already verified, so TARGET_EFAULT
is not a possible return value.

Note that using -EFAULT was a bug.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/aarch64/signal.c    | 6 +-----
 linux-user/alpha/signal.c      | 6 +-----
 linux-user/arm/signal.c        | 9 ++-------
 linux-user/hexagon/signal.c    | 6 +-----
 linux-user/hppa/signal.c       | 8 +-------
 linux-user/i386/signal.c       | 5 +----
 linux-user/m68k/signal.c       | 5 +----
 linux-user/microblaze/signal.c | 6 +-----
 linux-user/mips/signal.c       | 6 +-----
 linux-user/nios2/signal.c      | 8 +-------
 linux-user/openrisc/signal.c   | 5 +----
 linux-user/ppc/signal.c        | 4 +---
 linux-user/riscv/signal.c      | 6 +-----
 linux-user/s390x/signal.c      | 6 ++----
 linux-user/sh4/signal.c        | 7 +------
 linux-user/xtensa/signal.c     | 6 +-----
 16 files changed, 18 insertions(+), 81 deletions(-)

diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index b591790c22..2a1b7dbcdc 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -561,11 +561,7 @@ long do_rt_sigreturn(CPUARMState *env)
         goto badframe;
     }
 
-    if (do_sigaltstack(frame_addr +
-            offsetof(struct target_rt_sigframe, uc.tuc_stack),
-            0, get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
index 3aa4b339a4..011da0a53b 100644
--- a/linux-user/alpha/signal.c
+++ b/linux-user/alpha/signal.c
@@ -257,11 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
-                                             uc.tuc_stack),
-                       0, env->ir[IR_SP]) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index f21d1535e4..b7a772302f 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -685,11 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
         }
     }
 
-    if (do_sigaltstack(context_addr
-                       + offsetof(struct target_ucontext_v2, tuc_stack),
-                       0, get_sp_from_cpustate(env)) == -EFAULT) {
-        return 1;
-    }
+    target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
 
 #if 0
     /* Send SIGTRAP if we're single-stepping */
@@ -773,8 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
         goto badframe;
     }
 
-    if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
-        goto badframe;
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
 #if 0
     /* Send SIGTRAP if we're single-stepping */
diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index fde8dc93b7..3854eb4709 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -260,11 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
     }
 
     restore_ucontext(env, &frame->uc);
-
-    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
-            uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index d1a58feeb3..578874cf27 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -187,13 +187,7 @@ long do_rt_sigreturn(CPUArchState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    unlock_user_struct(frame, frame_addr, 0);
-
-    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
-                                             uc.tuc_stack),
-                       0, env->gr[30]) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 9320e1d472..3a0a1546a6 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -581,10 +581,7 @@ long do_rt_sigreturn(CPUX86State *env)
         goto badframe;
     }
 
-    if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
-                       get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
index 49ff87c77b..004b59fb61 100644
--- a/linux-user/m68k/signal.c
+++ b/linux-user/m68k/signal.c
@@ -400,10 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env)
     if (target_rt_restore_ucontext(env, &frame->uc))
         goto badframe;
 
-    if (do_sigaltstack(frame_addr +
-                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
-                       0, get_sp_from_cpustate(env)) == -EFAULT)
-        goto badframe;
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index cf0707b556..f59a1faf47 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -209,11 +209,7 @@ long do_rt_sigreturn(CPUMBState *env)
 
     restore_sigcontext(&frame->uc.tuc_mcontext, env);
 
-    if (do_sigaltstack(frame_addr +
-                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
-                       0, get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 455a8a229a..456fa64f41 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -368,11 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
     set_sigmask(&blocked);
 
     restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
-    if (do_sigaltstack(frame_addr +
-                       offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
-                       0, get_sp_from_cpustate(env)) == -EFAULT)
-        goto badframe;
+    target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env));
 
     env->active_tc.PC = env->CP0_EPC;
     mips_set_hflags_isa_mode_from_pc(env);
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 7d535065ed..751ea88811 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -82,9 +82,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
                                int *pr2)
 {
     int temp;
-    abi_ulong off, frame_addr = env->regs[R_SP];
     unsigned long *gregs = uc->tuc_mcontext.gregs;
-    int err;
 
     /* Always make any pending restarted system calls return -EINTR */
     /* current->restart_block.fn = do_no_restart_syscall; */
@@ -130,11 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
     __get_user(env->regs[R_RA], &gregs[23]);
     __get_user(env->regs[R_SP], &gregs[28]);
 
-    off = offsetof(struct target_rt_sigframe, uc.tuc_stack);
-    err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env));
-    if (err == -EFAULT) {
-        return 1;
-    }
+    target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
 
     *pr2 = env->regs[2];
     return 0;
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 232ad82b98..86f94d7f76 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -158,10 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack),
-                       0, frame_addr) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, frame_addr);
 
     unlock_user_struct(frame, frame_addr, 0);
     return cpu_get_gpr(env, 11);
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index b78613f7c8..79f265f82e 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -656,9 +656,7 @@ long do_rt_sigreturn(CPUPPCState *env)
     if (do_setcontext(&rt_sf->uc, env, 1))
         goto sigsegv;
 
-    do_sigaltstack(rt_sf_addr
-                   + offsetof(struct target_rt_sigframe, uc.tuc_stack),
-                   0, env->gpr[1]);
+    target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]);
 
     unlock_user_struct(rt_sf, rt_sf_addr, 1);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 67a95dbc7b..81d1129da3 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -192,11 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env)
     }
 
     restore_ucontext(env, &frame->uc);
-
-    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
-            uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 7107c5fb53..73806f5472 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -307,10 +307,8 @@ long do_rt_sigreturn(CPUS390XState *env)
         goto badframe;
     }
 
-    if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
-                       get_sp_from_cpustate(env)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
 
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 29c1ee30e6..684f18da58 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -323,12 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
     set_sigmask(&blocked);
 
     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
-
-    if (do_sigaltstack(frame_addr +
-                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
-                       0, get_sp_from_cpustate(regs)) == -EFAULT) {
-        goto badframe;
-    }
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs));
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 590f0313ff..22ec6cdeb9 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -253,12 +253,8 @@ long do_rt_sigreturn(CPUXtensaState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, frame);
+    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
 
-    if (do_sigaltstack(frame_addr +
-                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
-                       0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
-        goto badframe;
-    }
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
  2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
  2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

Now that we have exactly one call, it's easy to pass
in env instead of passing in the sp value.
Use target_save_altstack, which required env.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/qemu.h    |  3 ++-
 linux-user/signal.c  | 11 ++++-------
 linux-user/syscall.c |  3 +--
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 74e06e7121..3b0b6b75fe 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -432,7 +432,8 @@ int target_to_host_signal(int sig);
 int host_to_target_signal(int sig);
 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);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+                        CPUArchState *env);
 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);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 306f3edec5..83891f7c47 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -800,21 +800,18 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
 
 /* do_sigaltstack() returns target values and errnos. */
 /* compare linux/kernel/signal.c:do_sigaltstack() */
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+                        CPUArchState *env)
 {
     target_stack_t oss, *uoss = NULL;
     abi_long ret = -TARGET_EFAULT;
 
     if (uoss_addr) {
-        TaskState *ts = (TaskState *)thread_cpu->opaque;
-
         /* Verify writability now, but do not alter user memory yet. */
         if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) {
             goto out;
         }
-        __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp);
-        __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size);
-        __put_user(sas_ss_flags(sp), &oss.ss_flags);
+        target_save_altstack(&oss, env);
     }
 
     if (uss_addr) {
@@ -823,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
         if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
             goto out;
         }
-        ret = target_restore_altstack(uss, sp);
+        ret = target_restore_altstack(uss, get_sp_from_cpustate(env));
         if (ret) {
             goto out;
         }
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c7c3257f40..32a41c1387 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -11140,8 +11140,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return ret;
     }
     case TARGET_NR_sigaltstack:
-        return do_sigaltstack(arg1, arg2,
-                              get_sp_from_cpustate((CPUArchState *)cpu_env));
+        return do_sigaltstack(arg1, arg2, cpu_env);
 
 #ifdef CONFIG_SENDFILE
 #ifdef TARGET_NR_sendfile
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
                   ` (2 preceding siblings ...)
  2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 18:12   ` Warner Losh
  2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

In most cases we were already passing get_sp_from_cpustate
directly to the function.  In other cases, we were passing
a local variable which already contained the same value.
In the rest of the cases, we were passing the stack pointer
out of env directly.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/signal-common.h     | 2 +-
 linux-user/aarch64/signal.c    | 2 +-
 linux-user/alpha/signal.c      | 2 +-
 linux-user/arm/signal.c        | 4 ++--
 linux-user/hexagon/signal.c    | 2 +-
 linux-user/hppa/signal.c       | 2 +-
 linux-user/i386/signal.c       | 2 +-
 linux-user/m68k/signal.c       | 2 +-
 linux-user/microblaze/signal.c | 2 +-
 linux-user/mips/signal.c       | 2 +-
 linux-user/nios2/signal.c      | 2 +-
 linux-user/openrisc/signal.c   | 2 +-
 linux-user/ppc/signal.c        | 2 +-
 linux-user/riscv/signal.c      | 2 +-
 linux-user/s390x/signal.c      | 2 +-
 linux-user/sh4/signal.c        | 2 +-
 linux-user/signal.c            | 6 +++---
 linux-user/xtensa/signal.c     | 2 +-
 18 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 34b963af9a..ea86328b28 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -24,7 +24,7 @@ int on_sig_stack(unsigned long sp);
 int sas_ss_flags(unsigned long sp);
 abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
 void target_save_altstack(target_stack_t *uss, CPUArchState *env);
-abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp);
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env);
 
 static inline void target_sigemptyset(target_sigset_t *set)
 {
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index 2a1b7dbcdc..662bcd1c4e 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -561,7 +561,7 @@ long do_rt_sigreturn(CPUARMState *env)
         goto badframe;
     }
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
index 011da0a53b..1129ffeea1 100644
--- a/linux-user/alpha/signal.c
+++ b/linux-user/alpha/signal.c
@@ -257,7 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]);
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index b7a772302f..32b68ee302 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -685,7 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
         }
     }
 
-    target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&uc->tuc_stack, env);
 
 #if 0
     /* Send SIGTRAP if we're single-stepping */
@@ -769,7 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
         goto badframe;
     }
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
 #if 0
     /* Send SIGTRAP if we're single-stepping */
diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index 3854eb4709..85eab5e943 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -260,7 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
     }
 
     restore_ucontext(env, &frame->uc);
-    target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.uc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index 578874cf27..0e266f472d 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -187,7 +187,7 @@ long do_rt_sigreturn(CPUArchState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]);
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 3a0a1546a6..8701774e37 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -581,7 +581,7 @@ long do_rt_sigreturn(CPUX86State *env)
         goto badframe;
     }
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
index 004b59fb61..d06230655e 100644
--- a/linux-user/m68k/signal.c
+++ b/linux-user/m68k/signal.c
@@ -400,7 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env)
     if (target_rt_restore_ucontext(env, &frame->uc))
         goto badframe;
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index f59a1faf47..4c483bd8c6 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -209,7 +209,7 @@ long do_rt_sigreturn(CPUMBState *env)
 
     restore_sigcontext(&frame->uc.tuc_mcontext, env);
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 456fa64f41..e6be807a81 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -368,7 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
     set_sigmask(&blocked);
 
     restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-    target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->rs_uc.tuc_stack, env);
 
     env->active_tc.PC = env->CP0_EPC;
     mips_set_hflags_isa_mode_from_pc(env);
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 751ea88811..cc3872f11d 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -128,7 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
     __get_user(env->regs[R_RA], &gregs[23]);
     __get_user(env->regs[R_SP], &gregs[28]);
 
-    target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&uc->tuc_stack, env);
 
     *pr2 = env->regs[2];
     return 0;
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 86f94d7f76..5c5640a284 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -158,7 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, &frame->uc.tuc_mcontext);
-    target_restore_altstack(&frame->uc.tuc_stack, frame_addr);
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return cpu_get_gpr(env, 11);
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 79f265f82e..8e1e642807 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -656,7 +656,7 @@ long do_rt_sigreturn(CPUPPCState *env)
     if (do_setcontext(&rt_sf->uc, env, 1))
         goto sigsegv;
 
-    target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]);
+    target_restore_altstack(&rt_sf->uc.tuc_stack, env);
 
     unlock_user_struct(rt_sf, rt_sf_addr, 1);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 81d1129da3..9405c7fd9a 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -192,7 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env)
     }
 
     restore_ucontext(env, &frame->uc);
-    target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.uc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 73806f5472..b68b44ae7e 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -307,7 +307,7 @@ long do_rt_sigreturn(CPUS390XState *env)
         goto badframe;
     }
 
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 684f18da58..0451e65806 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -323,7 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
     set_sigmask(&blocked);
 
     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs));
+    target_restore_altstack(&frame->uc.tuc_stack, regs);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 83891f7c47..9016896dcd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -297,7 +297,7 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
     __put_user(ts->sigaltstack_used.ss_size, &uss->ss_size);
 }
 
-abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env)
 {
     TaskState *ts = (TaskState *)thread_cpu->opaque;
     size_t minstacksize = TARGET_MINSIGSTKSZ;
@@ -315,7 +315,7 @@ abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
     __get_user(ss.ss_size, &uss->ss_size);
     __get_user(ss.ss_flags, &uss->ss_flags);
 
-    if (on_sig_stack(sp)) {
+    if (on_sig_stack(get_sp_from_cpustate(env))) {
         return -TARGET_EPERM;
     }
 
@@ -820,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
         if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
             goto out;
         }
-        ret = target_restore_altstack(uss, get_sp_from_cpustate(env));
+        ret = target_restore_altstack(uss, env);
         if (ret) {
             goto out;
         }
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 22ec6cdeb9..72771e1294 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -253,7 +253,7 @@ long do_rt_sigreturn(CPUXtensaState *env)
     set_sigmask(&set);
 
     restore_sigcontext(env, frame);
-    target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+    target_restore_altstack(&frame->uc.tuc_stack, env);
 
     unlock_user_struct(frame, frame_addr, 0);
     return -TARGET_QEMU_ESIGRETURN;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
                   ` (3 preceding siblings ...)
  2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 18:10   ` Warner Losh
  2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

The bulk of the code goes to sparc64/signal.c, with
TARGET_SPARC_BIAS going to target_cpu.h, as we will
shortly need this define beyond signal.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/sparc/target_cpu.h |   6 +
 linux-user/sparc/signal.c     | 280 ----------------------------------
 linux-user/sparc64/signal.c   | 278 +++++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+), 280 deletions(-)

diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 1fa1011775..37f6a1d62b 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -20,6 +20,12 @@
 #ifndef SPARC_TARGET_CPU_H
 #define SPARC_TARGET_CPU_H
 
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+# define TARGET_STACK_BIAS 2047
+#else
+# define TARGET_STACK_BIAS 0
+#endif
+
 static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
                                         unsigned flags)
 {
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index d27b7a3af7..756d983af2 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -322,283 +322,3 @@ long do_rt_sigreturn(CPUSPARCState *env)
     qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
     return -TARGET_ENOSYS;
 }
-
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-#define SPARC_MC_TSTATE 0
-#define SPARC_MC_PC 1
-#define SPARC_MC_NPC 2
-#define SPARC_MC_Y 3
-#define SPARC_MC_G1 4
-#define SPARC_MC_G2 5
-#define SPARC_MC_G3 6
-#define SPARC_MC_G4 7
-#define SPARC_MC_G5 8
-#define SPARC_MC_G6 9
-#define SPARC_MC_G7 10
-#define SPARC_MC_O0 11
-#define SPARC_MC_O1 12
-#define SPARC_MC_O2 13
-#define SPARC_MC_O3 14
-#define SPARC_MC_O4 15
-#define SPARC_MC_O5 16
-#define SPARC_MC_O6 17
-#define SPARC_MC_O7 18
-#define SPARC_MC_NGREG 19
-
-typedef abi_ulong target_mc_greg_t;
-typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
-
-struct target_mc_fq {
-    abi_ulong mcfq_addr;
-    uint32_t mcfq_insn;
-};
-
-/*
- * Note the manual 16-alignment; the kernel gets this because it
- * includes a "long double qregs[16]" in the mcpu_fregs union,
- * which we can't do.
- */
-struct target_mc_fpu {
-    union {
-        uint32_t sregs[32];
-        uint64_t dregs[32];
-        //uint128_t qregs[16];
-    } mcfpu_fregs;
-    abi_ulong mcfpu_fsr;
-    abi_ulong mcfpu_fprs;
-    abi_ulong mcfpu_gsr;
-    abi_ulong mcfpu_fq;
-    unsigned char mcfpu_qcnt;
-    unsigned char mcfpu_qentsz;
-    unsigned char mcfpu_enab;
-} __attribute__((aligned(16)));
-typedef struct target_mc_fpu target_mc_fpu_t;
-
-typedef struct {
-    target_mc_gregset_t mc_gregs;
-    target_mc_greg_t mc_fp;
-    target_mc_greg_t mc_i7;
-    target_mc_fpu_t mc_fpregs;
-} target_mcontext_t;
-
-struct target_ucontext {
-    abi_ulong tuc_link;
-    abi_ulong tuc_flags;
-    target_sigset_t tuc_sigmask;
-    target_mcontext_t tuc_mcontext;
-};
-
-/* A V9 register window */
-struct target_reg_window {
-    abi_ulong locals[8];
-    abi_ulong ins[8];
-};
-
-#define TARGET_STACK_BIAS 2047
-
-/* {set, get}context() needed for 64-bit SparcLinux userland. */
-void sparc64_set_context(CPUSPARCState *env)
-{
-    abi_ulong ucp_addr;
-    struct target_ucontext *ucp;
-    target_mc_gregset_t *grp;
-    target_mc_fpu_t *fpup;
-    abi_ulong pc, npc, tstate;
-    unsigned int i;
-    unsigned char fenab;
-
-    ucp_addr = env->regwptr[WREG_O0];
-    if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
-        goto do_sigsegv;
-    }
-    grp  = &ucp->tuc_mcontext.mc_gregs;
-    __get_user(pc, &((*grp)[SPARC_MC_PC]));
-    __get_user(npc, &((*grp)[SPARC_MC_NPC]));
-    if ((pc | npc) & 3) {
-        goto do_sigsegv;
-    }
-    if (env->regwptr[WREG_O1]) {
-        target_sigset_t target_set;
-        sigset_t set;
-
-        if (TARGET_NSIG_WORDS == 1) {
-            __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
-        } else {
-            abi_ulong *src, *dst;
-            src = ucp->tuc_sigmask.sig;
-            dst = target_set.sig;
-            for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
-                __get_user(*dst, src);
-            }
-        }
-        target_to_host_sigset_internal(&set, &target_set);
-        set_sigmask(&set);
-    }
-    env->pc = pc;
-    env->npc = npc;
-    __get_user(env->y, &((*grp)[SPARC_MC_Y]));
-    __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
-    /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
-    env->asi = (tstate >> 24) & 0xff;
-    cpu_put_ccr(env, (tstate >> 32) & 0xff);
-    __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
-    __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
-    __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
-    __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
-    __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
-    __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
-    /* Skip g7 as that's the thread register in userspace */
-
-    /*
-     * Note that unlike the kernel, we didn't need to mess with the
-     * guest register window state to save it into a pt_regs to run
-     * the kernel. So for us the guest's O regs are still in WREG_O*
-     * (unlike the kernel which has put them in UREG_I* in a pt_regs)
-     * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
-     * need to be written back to userspace memory.
-     */
-    __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
-    __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
-    __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
-    __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3]));
-    __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4]));
-    __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5]));
-    __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
-    __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
-
-    __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
-    __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
-
-    fpup = &ucp->tuc_mcontext.mc_fpregs;
-
-    __get_user(fenab, &(fpup->mcfpu_enab));
-    if (fenab) {
-        abi_ulong fprs;
-
-        /*
-         * We use the FPRS from the guest only in deciding whether
-         * to restore the upper, lower, or both banks of the FPU regs.
-         * The kernel here writes the FPU register data into the
-         * process's current_thread_info state and unconditionally
-         * clears FPRS and TSTATE_PEF: this disables the FPU so that the
-         * next FPU-disabled trap will copy the data out of
-         * current_thread_info and into the real FPU registers.
-         * QEMU doesn't need to handle lazy-FPU-state-restoring like that,
-         * so we always load the data directly into the FPU registers
-         * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled).
-         * Note that because we (and the kernel) always write zeroes for
-         * the fenab and fprs in sparc64_get_context() none of this code
-         * will execute unless the guest manually constructed or changed
-         * the context structure.
-         */
-        __get_user(fprs, &(fpup->mcfpu_fprs));
-        if (fprs & FPRS_DL) {
-            for (i = 0; i < 16; i++) {
-                __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
-            }
-        }
-        if (fprs & FPRS_DU) {
-            for (i = 16; i < 32; i++) {
-                __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
-            }
-        }
-        __get_user(env->fsr, &(fpup->mcfpu_fsr));
-        __get_user(env->gsr, &(fpup->mcfpu_gsr));
-    }
-    unlock_user_struct(ucp, ucp_addr, 0);
-    return;
-do_sigsegv:
-    unlock_user_struct(ucp, ucp_addr, 0);
-    force_sig(TARGET_SIGSEGV);
-}
-
-void sparc64_get_context(CPUSPARCState *env)
-{
-    abi_ulong ucp_addr;
-    struct target_ucontext *ucp;
-    target_mc_gregset_t *grp;
-    target_mcontext_t *mcp;
-    int err;
-    unsigned int i;
-    target_sigset_t target_set;
-    sigset_t set;
-
-    ucp_addr = env->regwptr[WREG_O0];
-    if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
-        goto do_sigsegv;
-    }
-
-    memset(ucp, 0, sizeof(*ucp));
-
-    mcp = &ucp->tuc_mcontext;
-    grp = &mcp->mc_gregs;
-
-    /* Skip over the trap instruction, first. */
-    env->pc = env->npc;
-    env->npc += 4;
-
-    /* If we're only reading the signal mask then do_sigprocmask()
-     * is guaranteed not to fail, which is important because we don't
-     * have any way to signal a failure or restart this operation since
-     * this is not a normal syscall.
-     */
-    err = do_sigprocmask(0, NULL, &set);
-    assert(err == 0);
-    host_to_target_sigset_internal(&target_set, &set);
-    if (TARGET_NSIG_WORDS == 1) {
-        __put_user(target_set.sig[0],
-                   (abi_ulong *)&ucp->tuc_sigmask);
-    } else {
-        abi_ulong *src, *dst;
-        src = target_set.sig;
-        dst = ucp->tuc_sigmask.sig;
-        for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
-            __put_user(*src, dst);
-        }
-    }
-
-    __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
-    __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
-    __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
-    __put_user(env->y, &((*grp)[SPARC_MC_Y]));
-    __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
-    __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
-    __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
-    __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
-    __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
-    __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
-    __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
-
-    /*
-     * Note that unlike the kernel, we didn't need to mess with the
-     * guest register window state to save it into a pt_regs to run
-     * the kernel. So for us the guest's O regs are still in WREG_O*
-     * (unlike the kernel which has put them in UREG_I* in a pt_regs)
-     * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
-     * need to be fished out of userspace memory.
-     */
-    __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
-    __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
-    __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
-    __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3]));
-    __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4]));
-    __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5]));
-    __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
-    __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
-
-    __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
-    __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
-
-    /*
-     * We don't write out the FPU state. This matches the kernel's
-     * implementation (which has the code for doing this but
-     * hidden behind an "if (fenab)" where fenab is always 0).
-     */
-
-    unlock_user_struct(ucp, ucp_addr, 1);
-    return;
-do_sigsegv:
-    unlock_user_struct(ucp, ucp_addr, 1);
-    force_sig(TARGET_SIGSEGV);
-}
-#endif
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
index 170ebac232..d27e049c2a 100644
--- a/linux-user/sparc64/signal.c
+++ b/linux-user/sparc64/signal.c
@@ -16,4 +16,282 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+
 #include "../sparc/signal.c"
+
+#define SPARC_MC_TSTATE 0
+#define SPARC_MC_PC 1
+#define SPARC_MC_NPC 2
+#define SPARC_MC_Y 3
+#define SPARC_MC_G1 4
+#define SPARC_MC_G2 5
+#define SPARC_MC_G3 6
+#define SPARC_MC_G4 7
+#define SPARC_MC_G5 8
+#define SPARC_MC_G6 9
+#define SPARC_MC_G7 10
+#define SPARC_MC_O0 11
+#define SPARC_MC_O1 12
+#define SPARC_MC_O2 13
+#define SPARC_MC_O3 14
+#define SPARC_MC_O4 15
+#define SPARC_MC_O5 16
+#define SPARC_MC_O6 17
+#define SPARC_MC_O7 18
+#define SPARC_MC_NGREG 19
+
+typedef abi_ulong target_mc_greg_t;
+typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
+
+struct target_mc_fq {
+    abi_ulong mcfq_addr;
+    uint32_t mcfq_insn;
+};
+
+/*
+ * Note the manual 16-alignment; the kernel gets this because it
+ * includes a "long double qregs[16]" in the mcpu_fregs union,
+ * which we can't do.
+ */
+struct target_mc_fpu {
+    union {
+        uint32_t sregs[32];
+        uint64_t dregs[32];
+    } mcfpu_fregs;
+    abi_ulong mcfpu_fsr;
+    abi_ulong mcfpu_fprs;
+    abi_ulong mcfpu_gsr;
+    abi_ulong mcfpu_fq;
+    unsigned char mcfpu_qcnt;
+    unsigned char mcfpu_qentsz;
+    unsigned char mcfpu_enab;
+} __attribute__((aligned(16)));
+typedef struct target_mc_fpu target_mc_fpu_t;
+
+typedef struct {
+    target_mc_gregset_t mc_gregs;
+    target_mc_greg_t mc_fp;
+    target_mc_greg_t mc_i7;
+    target_mc_fpu_t mc_fpregs;
+} target_mcontext_t;
+
+struct target_ucontext {
+    abi_ulong tuc_link;
+    abi_ulong tuc_flags;
+    target_sigset_t tuc_sigmask;
+    target_mcontext_t tuc_mcontext;
+};
+
+/* A V9 register window */
+struct target_reg_window {
+    abi_ulong locals[8];
+    abi_ulong ins[8];
+};
+
+/* {set, get}context() needed for 64-bit SparcLinux userland. */
+void sparc64_set_context(CPUSPARCState *env)
+{
+    abi_ulong ucp_addr;
+    struct target_ucontext *ucp;
+    target_mc_gregset_t *grp;
+    target_mc_fpu_t *fpup;
+    abi_ulong pc, npc, tstate;
+    unsigned int i;
+    unsigned char fenab;
+
+    ucp_addr = env->regwptr[WREG_O0];
+    if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
+        goto do_sigsegv;
+    }
+    grp  = &ucp->tuc_mcontext.mc_gregs;
+    __get_user(pc, &((*grp)[SPARC_MC_PC]));
+    __get_user(npc, &((*grp)[SPARC_MC_NPC]));
+    if ((pc | npc) & 3) {
+        goto do_sigsegv;
+    }
+    if (env->regwptr[WREG_O1]) {
+        target_sigset_t target_set;
+        sigset_t set;
+
+        if (TARGET_NSIG_WORDS == 1) {
+            __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
+        } else {
+            abi_ulong *src, *dst;
+            src = ucp->tuc_sigmask.sig;
+            dst = target_set.sig;
+            for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+                __get_user(*dst, src);
+            }
+        }
+        target_to_host_sigset_internal(&set, &target_set);
+        set_sigmask(&set);
+    }
+    env->pc = pc;
+    env->npc = npc;
+    __get_user(env->y, &((*grp)[SPARC_MC_Y]));
+    __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
+    /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
+    env->asi = (tstate >> 24) & 0xff;
+    cpu_put_ccr(env, (tstate >> 32) & 0xff);
+    __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
+    __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
+    __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
+    __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
+    __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
+    __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
+    /* Skip g7 as that's the thread register in userspace */
+
+    /*
+     * Note that unlike the kernel, we didn't need to mess with the
+     * guest register window state to save it into a pt_regs to run
+     * the kernel. So for us the guest's O regs are still in WREG_O*
+     * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+     * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+     * need to be written back to userspace memory.
+     */
+    __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
+    __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
+    __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
+    __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3]));
+    __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4]));
+    __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5]));
+    __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
+    __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
+
+    __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
+    __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
+
+    fpup = &ucp->tuc_mcontext.mc_fpregs;
+
+    __get_user(fenab, &(fpup->mcfpu_enab));
+    if (fenab) {
+        abi_ulong fprs;
+
+        /*
+         * We use the FPRS from the guest only in deciding whether
+         * to restore the upper, lower, or both banks of the FPU regs.
+         * The kernel here writes the FPU register data into the
+         * process's current_thread_info state and unconditionally
+         * clears FPRS and TSTATE_PEF: this disables the FPU so that the
+         * next FPU-disabled trap will copy the data out of
+         * current_thread_info and into the real FPU registers.
+         * QEMU doesn't need to handle lazy-FPU-state-restoring like that,
+         * so we always load the data directly into the FPU registers
+         * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled).
+         * Note that because we (and the kernel) always write zeroes for
+         * the fenab and fprs in sparc64_get_context() none of this code
+         * will execute unless the guest manually constructed or changed
+         * the context structure.
+         */
+        __get_user(fprs, &(fpup->mcfpu_fprs));
+        if (fprs & FPRS_DL) {
+            for (i = 0; i < 16; i++) {
+                __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
+            }
+        }
+        if (fprs & FPRS_DU) {
+            for (i = 16; i < 32; i++) {
+                __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
+            }
+        }
+        __get_user(env->fsr, &(fpup->mcfpu_fsr));
+        __get_user(env->gsr, &(fpup->mcfpu_gsr));
+    }
+    unlock_user_struct(ucp, ucp_addr, 0);
+    return;
+
+ do_sigsegv:
+    unlock_user_struct(ucp, ucp_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+}
+
+void sparc64_get_context(CPUSPARCState *env)
+{
+    abi_ulong ucp_addr;
+    struct target_ucontext *ucp;
+    target_mc_gregset_t *grp;
+    target_mcontext_t *mcp;
+    int err;
+    unsigned int i;
+    target_sigset_t target_set;
+    sigset_t set;
+
+    ucp_addr = env->regwptr[WREG_O0];
+    if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
+        goto do_sigsegv;
+    }
+
+    memset(ucp, 0, sizeof(*ucp));
+
+    mcp = &ucp->tuc_mcontext;
+    grp = &mcp->mc_gregs;
+
+    /* Skip over the trap instruction, first. */
+    env->pc = env->npc;
+    env->npc += 4;
+
+    /*
+     * If we're only reading the signal mask then do_sigprocmask()
+     * is guaranteed not to fail, which is important because we don't
+     * have any way to signal a failure or restart this operation since
+     * this is not a normal syscall.
+     */
+    err = do_sigprocmask(0, NULL, &set);
+    assert(err == 0);
+    host_to_target_sigset_internal(&target_set, &set);
+    if (TARGET_NSIG_WORDS == 1) {
+        __put_user(target_set.sig[0], (abi_ulong *)&ucp->tuc_sigmask);
+    } else {
+        abi_ulong *src, *dst;
+        src = target_set.sig;
+        dst = ucp->tuc_sigmask.sig;
+        for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+            __put_user(*src, dst);
+        }
+    }
+
+    __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
+    __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
+    __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
+    __put_user(env->y, &((*grp)[SPARC_MC_Y]));
+    __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
+    __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
+    __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
+    __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
+    __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
+    __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
+    __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
+
+    /*
+     * Note that unlike the kernel, we didn't need to mess with the
+     * guest register window state to save it into a pt_regs to run
+     * the kernel. So for us the guest's O regs are still in WREG_O*
+     * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+     * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+     * need to be fished out of userspace memory.
+     */
+    __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
+    __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
+    __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
+    __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3]));
+    __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4]));
+    __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5]));
+    __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
+    __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
+
+    __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
+    __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
+
+    /*
+     * We don't write out the FPU state. This matches the kernel's
+     * implementation (which has the code for doing this but
+     * hidden behind an "if (fenab)" where fenab is always 0).
+     */
+
+    unlock_user_struct(ucp, ucp_addr, 1);
+    return;
+
+ do_sigsegv:
+    unlock_user_struct(ucp, ucp_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/8] linux-user/sparc: Clean up init_thread
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
                   ` (4 preceding siblings ...)
  2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
  2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
  7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

Share code between sparc32 and sparc64, removing a bit of pointless
difference wrt psr/tstate.  Use sizeof(abi_ulong) for allocating
initial register window.  Use TARGET_STACK_BIAS.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/elfload.c | 33 +++++----------------------------
 1 file changed, 5 insertions(+), 28 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c6731013fd..cd8b81103f 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -663,48 +663,25 @@ static uint32_t get_elf_hwcap2(void)
 
 #define ELF_CLASS   ELFCLASS64
 #define ELF_ARCH    EM_SPARCV9
-
-#define STACK_BIAS              2047
-
-static inline void init_thread(struct target_pt_regs *regs,
-                               struct image_info *infop)
-{
-#ifndef TARGET_ABI32
-    regs->tstate = 0;
-#endif
-    regs->pc = infop->entry;
-    regs->npc = regs->pc + 4;
-    regs->y = 0;
-#ifdef TARGET_ABI32
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
-    if (personality(infop->personality) == PER_LINUX32)
-        regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else
-        regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-#endif
-}
-
 #else
 #define ELF_START_MMAP 0x80000000
 #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
                     | HWCAP_SPARC_MULDIV)
-
 #define ELF_CLASS   ELFCLASS32
 #define ELF_ARCH    EM_SPARC
+#endif /* TARGET_SPARC64 */
 
 static inline void init_thread(struct target_pt_regs *regs,
                                struct image_info *infop)
 {
-    regs->psr = 0;
+    /* Note that target_cpu_copy_regs does not read psr/tstate. */
     regs->pc = infop->entry;
     regs->npc = regs->pc + 4;
     regs->y = 0;
-    regs->u_regs[14] = infop->start_stack - 16 * 4;
+    regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
+                        - TARGET_STACK_BIAS);
 }
-
-#endif
-#endif
+#endif /* TARGET_SPARC */
 
 #ifdef TARGET_PPC
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
                   ` (5 preceding siblings ...)
  2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
  7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

Generic code cares about the logical stack pointer, not the
physical one that has a bias applied for sparc64.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/sparc/target_cpu.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 37f6a1d62b..1f4bed50f4 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -46,6 +46,7 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
 #endif
         /* ??? The kernel appears to copy one stack frame to the new stack. */
         /* ??? The kernel force aligns the new stack. */
+        /* Userspace provides a biased stack pointer value. */
         env->regwptr[WREG_SP] = newsp;
     }
 
@@ -83,7 +84,7 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls)
 
 static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
 {
-    return state->regwptr[WREG_SP];
+    return state->regwptr[WREG_SP] + TARGET_STACK_BIAS;
 }
 
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 8/8] linux-user/sparc64: Implement signals
  2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
                   ` (6 preceding siblings ...)
  2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
  2021-04-25 16:08   ` Richard Henderson
  7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
  To: qemu-devel

We've been using the 32-bit sparc abi for 64-bit signals.
There's a surprising amount of difference, beginning with
the fact that 64-bit always uses rt signal frames.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/sparc/target_signal.h    |   2 +
 linux-user/sparc64/target_syscall.h |  14 +-
 linux-user/sparc64/signal.c         | 245 +++++++++++++++++++++++++++-
 3 files changed, 254 insertions(+), 7 deletions(-)

diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
index 911a3f5af5..651320ab8d 100644
--- a/linux-user/sparc/target_signal.h
+++ b/linux-user/sparc/target_signal.h
@@ -67,7 +67,9 @@ typedef struct target_sigaltstack {
 #define TARGET_MINSIGSTKSZ	4096
 #define TARGET_SIGSTKSZ		16384
 
+#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
 #define TARGET_ARCH_HAS_SETUP_FRAME
+#endif
 
 /* bit-flags */
 #define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
diff --git a/linux-user/sparc64/target_syscall.h b/linux-user/sparc64/target_syscall.h
index 696a68b1ed..fcc71db16e 100644
--- a/linux-user/sparc64/target_syscall.h
+++ b/linux-user/sparc64/target_syscall.h
@@ -4,14 +4,16 @@
 #include "../sparc/target_errno.h"
 
 struct target_pt_regs {
-	abi_ulong u_regs[16];
-	abi_ulong tstate;
-	abi_ulong pc;
-	abi_ulong npc;
-	abi_ulong y;
-	abi_ulong fprs;
+    abi_ulong u_regs[16];
+    abi_ulong tstate;
+    abi_ulong pc;
+    abi_ulong npc;
+    uint32_t y;
+    uint32_t magic;
 };
 
+#define TARGET_PT_REGS_MAGIC 0x57ac6c00
+
 #define UNAME_MACHINE "sparc64"
 #define UNAME_MINIMUM_RELEASE "2.6.32"
 
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
index d27e049c2a..7ba811d342 100644
--- a/linux-user/sparc64/signal.c
+++ b/linux-user/sparc64/signal.c
@@ -17,7 +17,10 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "../sparc/signal.c"
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
 
 #define SPARC_MC_TSTATE 0
 #define SPARC_MC_PC 1
@@ -295,3 +298,243 @@ void sparc64_get_context(CPUSPARCState *env)
     unlock_user_struct(ucp, ucp_addr, 1);
     force_sig(TARGET_SIGSEGV);
 }
+
+struct target_sparc_stackf {
+    struct target_reg_window win;
+    uint64_t xargs[8];
+};
+
+struct target_siginfo_fpu_t {
+    uint64_t dregs[32];
+    uint64_t fsr;
+    uint64_t gsr;
+    uint64_t fprs;
+};
+
+struct target_sigcontext {
+    target_siginfo_t info;
+    struct target_pt_regs regs;
+    uint64_t fpu_save;
+    target_stack_t stack;
+    target_sigset_t mask;
+    uint64_t rwin_save;
+};
+
+struct target_rt_sigframe {
+    struct target_sparc_stackf ss;
+    struct target_sigcontext sc;
+    struct target_siginfo_fpu_t fpu;
+};
+
+static abi_ulong get_sigframe(struct target_sigaction *sa,
+                              CPUSPARCState *env, int framesize)
+{
+    abi_ulong sp = target_sigsp(get_sp_from_cpustate(env), sa);
+    return (sp - framesize) & -16;
+}
+
+static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        __put_user(env->gregs[i], &regs->u_regs[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        __put_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+    }
+    __put_user(sparc64_tstate(env), &regs->tstate);
+    __put_user(env->pc, &regs->pc);
+    __put_user(env->npc, &regs->npc);
+    __put_user(env->y, &regs->y);
+    __put_user(TARGET_PT_REGS_MAGIC, &regs->magic);
+}
+
+static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+    uint64_t tstate;
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        __get_user(env->gregs[i], &regs->u_regs[i]);
+    }
+    for (i = 0; i < 8; i++) {
+        __get_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+    }
+
+    __get_user(env->y, &regs->y);
+    __get_user(tstate, &regs->tstate);
+
+    /* User can only change condition codes and %asi in tstate. */
+    cpu_put_ccr(env, tstate >> 32);
+    env->asi = extract64(tstate, 24, 8);
+}
+
+static void save_fpu_state(struct target_siginfo_fpu_t *regs,
+                           CPUSPARCState *env)
+{
+    int i;
+
+    /* QEMU does not lazy fpu saving.  Save the entire fp register bank. */
+    for (i = 0; i < 32; ++i) {
+        __put_user(env->fpr[i].ll, &regs->dregs[i]);
+    }
+    __put_user(env->fsr, &regs->fsr);
+    __put_user(env->gsr, &regs->gsr);
+    __put_user(env->fprs, &regs->fprs);
+}
+
+static void restore_fpu_state(struct target_siginfo_fpu_t *regs,
+                              CPUSPARCState *env)
+{
+    uint64_t fprs;
+    int i;
+
+    /* In case the user mucks about with FPRS, restore as directed. */
+    __get_user(fprs, &regs->fprs);
+    if (fprs & FPRS_DL) {
+        for (i = 0; i < 16; ++i) {
+            __get_user(env->fpr[i].ll, &regs->dregs[i]);
+        }
+    }
+    if (fprs & FPRS_DU) {
+        for (i = 16; i < 32; ++i) {
+            __get_user(env->fpr[i].ll, &regs->dregs[i]);
+        }
+    }
+    __get_user(env->fsr, &regs->fsr);
+    __get_user(env->gsr, &regs->gsr);
+    env->fprs |= fprs;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+                    target_siginfo_t *info,
+                    target_sigset_t *set, CPUSPARCState *env)
+{
+    abi_ulong sf_addr, sp;
+    struct target_rt_sigframe *sf = NULL;
+    void *window;
+
+    sf_addr = get_sigframe(ka, env, sizeof(*sf));
+    trace_user_setup_rt_frame(env, sf_addr);
+    if (!lock_user_struct(VERIFY_WRITE, sf, sf_addr, 0)) {
+        goto do_sigsegv;
+    }
+
+    /* 2. Save the current process state */
+    save_pt_regs(&sf->sc.regs, env);
+    save_fpu_state(&sf->fpu, env);
+    __put_user(sf_addr + offsetof(struct target_rt_sigframe, fpu),
+               &sf->sc.fpu_save);
+    __put_user(0, &sf->sc.rwin_save);  /* TODO: save_rwin_state */
+
+    /*
+     * Copy one register window from the top-of-stack into the signal frame.
+     * The balance of the sparc_stackf struct is for the callee --- the call
+     * abi requires the space for spilling argument registers.
+     */
+    sp = get_sp_from_cpustate(env);
+    window = lock_user(VERIFY_READ, sp, sizeof(struct target_reg_window), 1);
+    if (!window) {
+        goto do_sigsegv;
+    }
+    memcpy(sf, window, sizeof(struct target_reg_window));
+    unlock_user(window, sp, 0);
+
+    target_save_altstack(&sf->sc.stack, env);
+    for (int i = 0; i < TARGET_NSIG_WORDS; ++i) {
+        __put_user(set->sig[i], &sf->sc.mask.sig[i]);
+    }
+
+    unlock_user(sf, sf_addr, sizeof(*sf));
+
+    /* 3. signal handler back-trampoline and parameters */
+    env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS;
+    env->regwptr[WREG_O0] = sig;
+    env->regwptr[WREG_O1] = sf_addr + offsetof(struct target_rt_sigframe, sc);
+    env->regwptr[WREG_O2] = sf_addr + offsetof(struct target_rt_sigframe, sc);
+
+    /* 4. return to kernel instructions */
+    env->regwptr[WREG_O7] = ka->ka_restorer;
+
+    /* 5. signal handler */
+    env->pc = ka->_sa_handler;
+    env->npc = env->pc + 4;
+    return;
+
+ do_sigsegv:
+    unlock_user(sf, sf_addr, 0);
+    force_sigsegv(sig);
+}
+
+/*
+ * __NR_sigreturn still exists for backward compatiblity,
+ * but it is set to sys_nis_syscall for sparc64.
+ */
+long do_sigreturn(CPUSPARCState *env)
+{
+    return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUSPARCState *env)
+{
+    abi_ulong sf_addr, sc_addr, tpc, tnpc, ptr;
+    struct target_sigcontext *sc = NULL;
+    sigset_t set;
+
+    sf_addr = get_sp_from_cpustate(env);
+    trace_user_do_rt_sigreturn(env, sf_addr);
+
+    if (sf_addr & 15) {
+        goto do_sigsegv;
+    }
+    sc_addr = sf_addr + offsetof(struct target_rt_sigframe, sc);
+    if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
+        goto do_sigsegv;
+    }
+
+    /* Validate SP alignment.  */
+    __get_user(ptr, &sc->regs.u_regs[8 + WREG_SP]);
+    if ((ptr + TARGET_STACK_BIAS) & 7) {
+        goto do_sigsegv;
+    }
+
+    /* Validate PC and NPC alignment.  */
+    __get_user(tpc, &sc->regs.pc);
+    __get_user(tnpc, &sc->regs.npc);
+    if ((tpc | tnpc) & 3) {
+        goto do_sigsegv;
+    }
+
+    restore_pt_regs(&sc->regs, env);
+
+    __get_user(ptr, &sc->fpu_save);
+    if (ptr) {
+        struct target_siginfo_fpu_t *fpu;
+        if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
+            goto do_sigsegv;
+        }
+        restore_fpu_state(fpu, env);
+        unlock_user_struct(fpu, ptr, 0);
+    }
+
+    __get_user(ptr, &sc->rwin_save);
+    if (ptr) {
+        goto do_sigsegv;  /* TODO: restore_rwin_state */
+    }
+
+    target_to_host_sigset(&set, &sc->mask);
+    set_sigmask(&set);
+    target_restore_altstack(&sc->stack, env);
+
+    env->pc = tpc;
+    env->npc = tnpc;
+
+    unlock_user_struct(sc, sc_addr, 0);
+    return -TARGET_QEMU_ESIGRETURN;
+
+ do_sigsegv:
+    unlock_user_struct(sc, sc_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_QEMU_ESIGRETURN;
+}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 8/8] linux-user/sparc64: Implement signals
  2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
@ 2021-04-25 16:08   ` Richard Henderson
  0 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 16:08 UTC (permalink / raw)
  To: qemu-devel

On 4/25/21 8:57 AM, Richard Henderson wrote:
> We've been using the 32-bit sparc abi for 64-bit signals.
> There's a surprising amount of difference, beginning with
> the fact that 64-bit always uses rt signal frames.
> 
> Signed-off-by: Richard Henderson<richard.henderson@linaro.org>
> ---
>   linux-user/sparc/target_signal.h    |   2 +
>   linux-user/sparc64/target_syscall.h |  14 +-
>   linux-user/sparc64/signal.c         | 245 +++++++++++++++++++++++++++-
>   3 files changed, 254 insertions(+), 7 deletions(-)

Ho hum.  I just realized I've broken sparc32plus.
I'll have to reorg the ifdefs.


r~


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
  2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
@ 2021-04-25 18:10   ` Warner Losh
  0 siblings, 0 replies; 12+ messages in thread
From: Warner Losh @ 2021-04-25 18:10 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 606 bytes --]

On Sun, Apr 25, 2021 at 10:03 AM Richard Henderson <
richard.henderson@linaro.org> wrote:

> The bulk of the code goes to sparc64/signal.c, with
> TARGET_SPARC_BIAS going to target_cpu.h, as we will
> shortly need this define beyond signal.c.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/sparc/target_cpu.h |   6 +
>  linux-user/sparc/signal.c     | 280 ----------------------------------
>  linux-user/sparc64/signal.c   | 278 +++++++++++++++++++++++++++++++++
>  3 files changed, 284 insertions(+), 280 deletions(-)
>

Reviewed-by: Warner Losh <imp@bsdimp.com>

[-- Attachment #2: Type: text/html, Size: 1113 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack
  2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
@ 2021-04-25 18:12   ` Warner Losh
  0 siblings, 0 replies; 12+ messages in thread
From: Warner Losh @ 2021-04-25 18:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 1275 bytes --]

On Sun, Apr 25, 2021 at 10:08 AM Richard Henderson <
richard.henderson@linaro.org> wrote:

> In most cases we were already passing get_sp_from_cpustate
> directly to the function.  In other cases, we were passing
> a local variable which already contained the same value.
> In the rest of the cases, we were passing the stack pointer
> out of env directly.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/signal-common.h     | 2 +-
>  linux-user/aarch64/signal.c    | 2 +-
>  linux-user/alpha/signal.c      | 2 +-
>  linux-user/arm/signal.c        | 4 ++--
>  linux-user/hexagon/signal.c    | 2 +-
>  linux-user/hppa/signal.c       | 2 +-
>  linux-user/i386/signal.c       | 2 +-
>  linux-user/m68k/signal.c       | 2 +-
>  linux-user/microblaze/signal.c | 2 +-
>  linux-user/mips/signal.c       | 2 +-
>  linux-user/nios2/signal.c      | 2 +-
>  linux-user/openrisc/signal.c   | 2 +-
>  linux-user/ppc/signal.c        | 2 +-
>  linux-user/riscv/signal.c      | 2 +-
>  linux-user/s390x/signal.c      | 2 +-
>  linux-user/sh4/signal.c        | 2 +-
>  linux-user/signal.c            | 6 +++---
>  linux-user/xtensa/signal.c     | 2 +-
>  18 files changed, 21 insertions(+), 21 deletions(-)
>

Reviewed by: Warner Losh <imp@bsdimp.com>

[-- Attachment #2: Type: text/html, Size: 1896 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-04-25 18:15 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
2021-04-25 18:12   ` Warner Losh
2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
2021-04-25 18:10   ` Warner Losh
2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 16:08   ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).