All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: mark.cave-ayland@ilande.co.uk, laurent@vivier.eu
Subject: [RFC PATCH] linux-user/sparc: Implement v8plus signals
Date: Tue, 25 May 2021 18:13:40 -0700	[thread overview]
Message-ID: <20210526011340.440284-1-richard.henderson@linaro.org> (raw)

Sparc v8plus is a sparc64 running a 32-bit ABI.
The significant difference vs sparc32 is that all 64 bits of
the %g and %o registers, plus %xcc, are saved across interrupts,
context switches, and signals.

There's a special marker in the saved %psr value that's used to
indicate that %xcc and the high bits are present in the frame.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---

I have been unable to find an extant v8plus distribution with
which to test this beyond compilation.  Thus the RFC.  I know
debian used to have one, but they have moved to pure sparc64 now.

Thoughts?


r~

---
 target/sparc/cpu.h        |  2 -
 linux-user/sparc/signal.c | 96 ++++++++++++++++++++++++++++++++-------
 2 files changed, 80 insertions(+), 18 deletions(-)

diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ff8ae73002..d2c6e2e4ec 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -104,14 +104,12 @@ enum {
 #define PSR_CARRY_SHIFT 20
 #define PSR_CARRY (1 << PSR_CARRY_SHIFT)
 #define PSR_ICC   (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
-#if !defined(TARGET_SPARC64)
 #define PSR_EF    (1<<12)
 #define PSR_PIL   0xf00
 #define PSR_S     (1<<7)
 #define PSR_PS    (1<<6)
 #define PSR_ET    (1<<5)
 #define PSR_CWP   0x1f
-#endif
 
 #define CC_SRC (env->cc_src)
 #define CC_SRC2 (env->cc_src2)
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index 0cc3db5570..d3d699545b 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -61,6 +61,13 @@ struct target_siginfo_fpu {
 #endif
 };
 
+struct target_siginfo_v8plus {
+#if defined(TARGET_SPARC64) && defined(TARGET_ABI32)
+    uint32_t u_regs_upper[16];
+    uint32_t asi;
+#endif
+};
+
 #ifdef TARGET_ARCH_HAS_SETUP_FRAME
 struct target_signal_frame {
     struct target_stackf ss;
@@ -69,7 +76,8 @@ struct target_signal_frame {
     abi_ulong fpu_save;
     uint32_t insns[2] QEMU_ALIGNED(8);
     abi_ulong extramask[TARGET_NSIG_WORDS - 1];
-    abi_ulong extra_size; /* Should be 0 */
+    abi_ulong extra_size; /* Should be sizeof(v8plus) */
+    struct target_siginfo_v8plus v8plus;
     abi_ulong rwin_save;
 };
 #endif
@@ -87,8 +95,9 @@ struct target_rt_signal_frame {
     abi_ulong fpu_save;
     uint32_t insns[2];
     target_stack_t stack;
-    abi_ulong extra_size; /* Should be 0 */
+    abi_ulong extra_size; /* Should be sizeof(v8plus) */
 #endif
+    struct target_siginfo_v8plus v8plus;
     abi_ulong rwin_save;
 };
 
@@ -121,7 +130,34 @@ static abi_ulong get_sigframe(struct target_sigaction *sa,
     return sp;
 }
 
-static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+/* Fake PSR_IMPL | PSR_VER, meaning 64-bit cpu is present. */
+#define PSR_V8PLUS  0xff000000u
+/* If PSR_V8PLUS, this field contains %xcc. */
+#define PSR_XCC     0x000f0000u
+
+#if defined(TARGET_SPARC64) && defined(TARGET_ABI32)
+# define SAVE_REG(X, I)                                 \
+    do {                                                \
+        __put_user(X, &regs->u_regs[I]);                \
+        __put_user(X >> 32, &v8plus->u_regs_upper[I]);  \
+    } while (0)
+# define RESTORE_REG(X, I)                              \
+    do {                                                \
+        uint32_t l_, h_ = 0;                            \
+        __get_user(l_, &regs->u_regs[I]);               \
+        if ((psr & PSR_V8PLUS) == PSR_V8PLUS) {         \
+            __get_user(h_, &v8plus->u_regs_upper[I]);   \
+        }                                               \
+        X = deposit64(l_, 32, 32, h_);                  \
+    } while (0)
+#else
+# define SAVE_REG(X, I)     __put_user(X, &regs->u_regs[I])
+# define RESTORE_REG(X, I)  __get_user(X, &regs->u_regs[I])
+#endif
+
+static void save_pt_regs(struct target_pt_regs *regs,
+                         struct target_siginfo_v8plus *v8plus,
+                         CPUSPARCState *env)
 {
     int i;
 
@@ -130,7 +166,18 @@ static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
     /* TODO: magic should contain PT_REG_MAGIC + %tt. */
     __put_user(0, &regs->magic);
 #else
-    __put_user(cpu_get_psr(env), &regs->psr);
+    uint32_t psr;
+# ifdef TARGET_SPARC64
+    /* See linux/arch/sparc/include/uapi/asm/psrcompat.h, tstate_to_psr */
+    uint64_t tstate = sparc64_tstate(env);
+    psr = (tstate & 0x1f) /* TSTATE_CWP */
+        | ((tstate >> 12) & PSR_ICC)
+        | ((tstate >> 20) & PSR_XCC)
+        | PSR_S | PSR_V8PLUS;
+# else
+    psr = cpu_get_psr(env);
+# endif
+    __put_user(psr, &regs->psr);
 #endif
 
     __put_user(env->pc, &regs->pc);
@@ -138,14 +185,20 @@ static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
     __put_user(env->y, &regs->y);
 
     for (i = 0; i < 8; i++) {
-        __put_user(env->gregs[i], &regs->u_regs[i]);
+        SAVE_REG(env->gregs[i], i);
     }
     for (i = 0; i < 8; i++) {
-        __put_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+        SAVE_REG(env->regwptr[WREG_O0 + i], i + 8);
     }
+
+#if defined(TARGET_SPARC64) && defined(TARGET_ABI32)
+    __put_user(env->asi, &v8plus->asi);
+#endif
 }
 
-static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+static void restore_pt_regs(struct target_pt_regs *regs,
+                            struct target_siginfo_v8plus *v8plus,
+                            CPUSPARCState *env)
 {
     int i;
 
@@ -163,7 +216,15 @@ static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
      */
     uint32_t psr;
     __get_user(psr, &regs->psr);
-    env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC);
+# ifdef TARGET_SPARC64
+    /* Unconditionally restore %icc and %xcc; conditionally restore %asi. */
+    cpu_put_ccr(env, ((psr & PSR_ICC) >> 20) | ((psr & PSR_XCC) >> 12));
+    if ((psr & PSR_V8PLUS) == PSR_V8PLUS) {
+        env->asi = v8plus->asi & 0xff;
+    }
+# else
+    cpu_put_psr(env, (psr & PSR_ICC) | (env->psr & ~PSR_ICC));
+# endif
 #endif
 
     /* Note that pc and npc are handled in the caller. */
@@ -171,13 +232,16 @@ static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
     __get_user(env->y, &regs->y);
 
     for (i = 0; i < 8; i++) {
-        __get_user(env->gregs[i], &regs->u_regs[i]);
+        RESTORE_REG(env->gregs[i], i);
     }
     for (i = 0; i < 8; i++) {
-        __get_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+        RESTORE_REG(env->regwptr[WREG_O0 + i], i + 8);
     }
 }
 
+#undef SAVE_REG
+#undef RESTORE_REG
+
 static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env)
 {
     int i;
@@ -259,8 +323,8 @@ void setup_frame(int sig, struct target_sigaction *ka,
     }
 
     /* 2. Save the current process state */
-    save_pt_regs(&sf->regs, env);
-    __put_user(0, &sf->extra_size);
+    save_pt_regs(&sf->regs, &sf->v8plus, env);
+    __put_user(sizeof(sf->v8plus), &sf->extra_size);
 
     save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
     __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
@@ -321,7 +385,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
 
     /* 2. Save the current process state */
     save_reg_win(&sf->ss.win, env);
-    save_pt_regs(&sf->regs, env);
+    save_pt_regs(&sf->regs, &sf->v8plus, env);
 
     save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
     __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
@@ -333,7 +397,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     target_save_altstack(&sf->stack, env);
 
 #ifdef TARGET_ABI32
-    __put_user(0, &sf->extra_size);
+    __put_user(sizeof(sf->v8plus), &sf->extra_size);
 #endif
 
     /* 3. signal handler back-trampoline and parameters */
@@ -404,7 +468,7 @@ long do_sigreturn(CPUSPARCState *env)
     }
 
     /* 2. Restore the state */
-    restore_pt_regs(&sf->regs, env);
+    restore_pt_regs(&sf->regs, &sf->v8plus, env);
     env->pc = pc;
     env->npc = npc;
 
@@ -471,7 +535,7 @@ long do_rt_sigreturn(CPUSPARCState *env)
     }
 
     /* 2. Restore the state */
-    restore_pt_regs(&sf->regs, env);
+    restore_pt_regs(&sf->regs, &sf->v8plus, env);
 
     __get_user(ptr, &sf->fpu_save);
     if (ptr) {
-- 
2.25.1



             reply	other threads:[~2021-05-26  1:15 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-26  1:13 Richard Henderson [this message]
2021-06-15  6:48 ` [RFC PATCH] linux-user/sparc: Implement v8plus signals Laurent Vivier
2021-06-15 14:44   ` Richard Henderson
2021-06-16 18:43     ` Laurent Vivier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210526011340.440284-1-richard.henderson@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=laurent@vivier.eu \
    --cc=mark.cave-ayland@ilande.co.uk \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.