aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c137
1 files changed, 117 insertions, 20 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 3d60f7750fa8..299f956e4db3 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -30,6 +30,7 @@
30#include <asm/sim.h> 30#include <asm/sim.h>
31#include <asm/ucontext.h> 31#include <asm/ucontext.h>
32#include <asm/fpu.h> 32#include <asm/fpu.h>
33#include <asm/msa.h>
33#include <asm/war.h> 34#include <asm/war.h>
34#include <asm/vdso.h> 35#include <asm/vdso.h>
35#include <asm/dsp.h> 36#include <asm/dsp.h>
@@ -42,8 +43,8 @@ static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
42extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); 43extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
43extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); 44extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
44 45
45extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); 46extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc);
46extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); 47extern asmlinkage int _restore_msa_context32(struct sigcontext32 __user *sc);
47 48
48/* 49/*
49 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 50 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
@@ -78,17 +79,96 @@ struct rt_sigframe32 {
78}; 79};
79 80
80/* 81/*
82 * Thread saved context copy to/from a signal context presumed to be on the
83 * user stack, and therefore accessed with appropriate macros from uaccess.h.
84 */
85static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc)
86{
87 int i;
88 int err = 0;
89 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
90
91 for (i = 0; i < NUM_FPU_REGS; i += inc) {
92 err |=
93 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
94 &sc->sc_fpregs[i]);
95 }
96 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
97
98 return err;
99}
100
101static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
102{
103 int i;
104 int err = 0;
105 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
106 u64 fpr_val;
107
108 for (i = 0; i < NUM_FPU_REGS; i += inc) {
109 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
110 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
111 }
112 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
113
114 return err;
115}
116
117/*
118 * These functions will save only the upper 64 bits of the vector registers,
119 * since the lower 64 bits have already been saved as the scalar FP context.
120 */
121static int copy_msa_to_sigcontext32(struct sigcontext32 __user *sc)
122{
123 int i;
124 int err = 0;
125
126 for (i = 0; i < NUM_FPU_REGS; i++) {
127 err |=
128 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
129 &sc->sc_msaregs[i]);
130 }
131 err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
132
133 return err;
134}
135
136static int copy_msa_from_sigcontext32(struct sigcontext32 __user *sc)
137{
138 int i;
139 int err = 0;
140 u64 val;
141
142 for (i = 0; i < NUM_FPU_REGS; i++) {
143 err |= __get_user(val, &sc->sc_msaregs[i]);
144 set_fpr64(&current->thread.fpu.fpr[i], 1, val);
145 }
146 err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
147
148 return err;
149}
150
151/*
81 * sigcontext handlers 152 * sigcontext handlers
82 */ 153 */
83static int protected_save_fp_context32(struct sigcontext32 __user *sc) 154static int protected_save_fp_context32(struct sigcontext32 __user *sc,
155 unsigned used_math)
84{ 156{
85 int err; 157 int err;
158 bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
86 while (1) { 159 while (1) {
87 lock_fpu_owner(); 160 lock_fpu_owner();
88 err = own_fpu_inatomic(1); 161 if (is_fpu_owner()) {
89 if (!err) 162 err = save_fp_context32(sc);
90 err = save_fp_context32(sc); /* this might fail */ 163 if (save_msa && !err)
91 unlock_fpu_owner(); 164 err = _save_msa_context32(sc);
165 unlock_fpu_owner();
166 } else {
167 unlock_fpu_owner();
168 err = copy_fp_to_sigcontext32(sc);
169 if (save_msa && !err)
170 err = copy_msa_to_sigcontext32(sc);
171 }
92 if (likely(!err)) 172 if (likely(!err))
93 break; 173 break;
94 /* touch the sigcontext and try again */ 174 /* touch the sigcontext and try again */
@@ -101,15 +181,29 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
101 return err; 181 return err;
102} 182}
103 183
104static int protected_restore_fp_context32(struct sigcontext32 __user *sc) 184static int protected_restore_fp_context32(struct sigcontext32 __user *sc,
185 unsigned used_math)
105{ 186{
106 int err, tmp __maybe_unused; 187 int err, tmp __maybe_unused;
188 bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
107 while (1) { 189 while (1) {
108 lock_fpu_owner(); 190 lock_fpu_owner();
109 err = own_fpu_inatomic(0); 191 if (is_fpu_owner()) {
110 if (!err) 192 err = restore_fp_context32(sc);
111 err = restore_fp_context32(sc); /* this might fail */ 193 if (restore_msa && !err) {
112 unlock_fpu_owner(); 194 enable_msa();
195 err = _restore_msa_context32(sc);
196 } else {
197 /* signal handler may have used MSA */
198 disable_msa();
199 }
200 unlock_fpu_owner();
201 } else {
202 unlock_fpu_owner();
203 err = copy_fp_from_sigcontext32(sc);
204 if (restore_msa && !err)
205 err = copy_msa_from_sigcontext32(sc);
206 }
113 if (likely(!err)) 207 if (likely(!err))
114 break; 208 break;
115 /* touch the sigcontext and try again */ 209 /* touch the sigcontext and try again */
@@ -147,7 +241,8 @@ static int setup_sigcontext32(struct pt_regs *regs,
147 err |= __put_user(mflo3(), &sc->sc_lo3); 241 err |= __put_user(mflo3(), &sc->sc_lo3);
148 } 242 }
149 243
150 used_math = !!used_math(); 244 used_math = used_math() ? USEDMATH_FP : 0;
245 used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
151 err |= __put_user(used_math, &sc->sc_used_math); 246 err |= __put_user(used_math, &sc->sc_used_math);
152 247
153 if (used_math) { 248 if (used_math) {
@@ -155,20 +250,21 @@ static int setup_sigcontext32(struct pt_regs *regs,
155 * Save FPU state to signal context. Signal handler 250 * Save FPU state to signal context. Signal handler
156 * will "inherit" current FPU state. 251 * will "inherit" current FPU state.
157 */ 252 */
158 err |= protected_save_fp_context32(sc); 253 err |= protected_save_fp_context32(sc, used_math);
159 } 254 }
160 return err; 255 return err;
161} 256}
162 257
163static int 258static int
164check_and_restore_fp_context32(struct sigcontext32 __user *sc) 259check_and_restore_fp_context32(struct sigcontext32 __user *sc,
260 unsigned used_math)
165{ 261{
166 int err, sig; 262 int err, sig;
167 263
168 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 264 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
169 if (err > 0) 265 if (err > 0)
170 err = 0; 266 err = 0;
171 err |= protected_restore_fp_context32(sc); 267 err |= protected_restore_fp_context32(sc, used_math);
172 return err ?: sig; 268 return err ?: sig;
173} 269}
174 270
@@ -205,9 +301,10 @@ static int restore_sigcontext32(struct pt_regs *regs,
205 if (used_math) { 301 if (used_math) {
206 /* restore fpu context if we have used it before */ 302 /* restore fpu context if we have used it before */
207 if (!err) 303 if (!err)
208 err = check_and_restore_fp_context32(sc); 304 err = check_and_restore_fp_context32(sc, used_math);
209 } else { 305 } else {
210 /* signal handler may have used FPU. Give it up. */ 306 /* signal handler may have used FPU or MSA. Disable them. */
307 disable_msa();
211 lose_fpu(0); 308 lose_fpu(0);
212 } 309 }
213 310
@@ -566,8 +663,8 @@ static int signal32_init(void)
566 save_fp_context32 = _save_fp_context32; 663 save_fp_context32 = _save_fp_context32;
567 restore_fp_context32 = _restore_fp_context32; 664 restore_fp_context32 = _restore_fp_context32;
568 } else { 665 } else {
569 save_fp_context32 = fpu_emulator_save_context32; 666 save_fp_context32 = copy_fp_to_sigcontext32;
570 restore_fp_context32 = fpu_emulator_restore_context32; 667 restore_fp_context32 = copy_fp_from_sigcontext32;
571 } 668 }
572 669
573 return 0; 670 return 0;