diff options
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r-- | arch/mips/kernel/signal32.c | 137 |
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); | |||
42 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); | 43 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); |
43 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); | 44 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); |
44 | 45 | ||
45 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); | 46 | extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc); |
46 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); | 47 | extern 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 | */ | ||
85 | static 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(¤t->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 | |||
101 | static 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(¤t->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 | */ | ||
121 | static 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(¤t->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 | |||
136 | static 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(¤t->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 | */ |
83 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) | 154 | static 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 | ||
104 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | 184 | static 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 | ||
163 | static int | 258 | static int |
164 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | 259 | check_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; |