]> git.proxmox.com Git - mirror_qemu.git/commitdiff
linux-user/sparc: Add 64-bit support to fpu save/restore
authorRichard Henderson <richard.henderson@linaro.org>
Mon, 26 Apr 2021 02:53:31 +0000 (19:53 -0700)
committerLaurent Vivier <laurent@vivier.eu>
Sat, 15 May 2021 19:43:23 +0000 (21:43 +0200)
The shape of the kernel's __siginfo_fpu_t is dependent on
the cpu type, not the abi.  Which is weird, but there ya go.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20210426025334.1168495-23-richard.henderson@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
linux-user/sparc/signal.c

index 0ff57af43d1ef6dd0d6a85e2274affd5787401fd..41a8b33bac3c174a0f3f15ae80389e9628328464 100644 (file)
@@ -44,6 +44,12 @@ struct target_stackf {
 };
 
 struct target_siginfo_fpu {
+#ifdef TARGET_SPARC64
+    uint64_t si_double_regs[32];
+    uint64_t si_fsr;
+    uint64_t si_gsr;
+    uint64_t si_fprs;
+#else
     /* It is more convenient for qemu to move doubles, not singles. */
     uint64_t si_double_regs[16];
     uint32_t si_fsr;
@@ -52,6 +58,7 @@ struct target_siginfo_fpu {
         uint32_t insn_addr;
         uint32_t insn;
     } si_fpqueue [16];
+#endif
 };
 
 struct target_signal_frame {
@@ -167,21 +174,50 @@ static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
 {
     int i;
 
+#ifdef TARGET_SPARC64
+    for (i = 0; i < 32; ++i) {
+        __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+    }
+    __put_user(env->fsr, &fpu->si_fsr);
+    __put_user(env->gsr, &fpu->si_gsr);
+    __put_user(env->fprs, &fpu->si_fprs);
+#else
     for (i = 0; i < 16; ++i) {
         __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
     }
     __put_user(env->fsr, &fpu->si_fsr);
     __put_user(0, &fpu->si_fpqdepth);
+#endif
 }
 
 static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
 {
     int i;
 
+#ifdef TARGET_SPARC64
+    uint64_t fprs;
+    __get_user(fprs, &fpu->si_fprs);
+
+    /* In case the user mucks about with FPRS, restore as directed. */
+    if (fprs & FPRS_DL) {
+        for (i = 0; i < 16; ++i) {
+            __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+        }
+    }
+    if (fprs & FPRS_DU) {
+        for (i = 16; i < 32; ++i) {
+            __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+        }
+    }
+    __get_user(env->fsr, &fpu->si_fsr);
+    __get_user(env->gsr, &fpu->si_gsr);
+    env->fprs |= fprs;
+#else
     for (i = 0; i < 16; ++i) {
         __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
     }
     __get_user(env->fsr, &fpu->si_fsr);
+#endif
 }
 
 void setup_frame(int sig, struct target_sigaction *ka,