aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r--arch/mips/kernel/signal.c170
1 files changed, 148 insertions, 22 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 5199563c4403..33133d3df3e5 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 1991, 1992 Linus Torvalds 6 * Copyright (C) 1991, 1992 Linus Torvalds
7 * Copyright (C) 1994 - 2000 Ralf Baechle 7 * Copyright (C) 1994 - 2000 Ralf Baechle
8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 * Copyright (C) 2014, Imagination Technologies Ltd.
9 */ 10 */
10#include <linux/cache.h> 11#include <linux/cache.h>
11#include <linux/context_tracking.h> 12#include <linux/context_tracking.h>
@@ -30,6 +31,7 @@
30#include <linux/bitops.h> 31#include <linux/bitops.h>
31#include <asm/cacheflush.h> 32#include <asm/cacheflush.h>
32#include <asm/fpu.h> 33#include <asm/fpu.h>
34#include <asm/msa.h>
33#include <asm/sim.h> 35#include <asm/sim.h>
34#include <asm/ucontext.h> 36#include <asm/ucontext.h>
35#include <asm/cpu-features.h> 37#include <asm/cpu-features.h>
@@ -46,8 +48,8 @@ static int (*restore_fp_context)(struct sigcontext __user *sc);
46extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); 48extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
47extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); 49extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
48 50
49extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); 51extern asmlinkage int _save_msa_context(struct sigcontext __user *sc);
50extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); 52extern asmlinkage int _restore_msa_context(struct sigcontext __user *sc);
51 53
52struct sigframe { 54struct sigframe {
53 u32 sf_ass[4]; /* argument save space for o32 */ 55 u32 sf_ass[4]; /* argument save space for o32 */
@@ -64,17 +66,95 @@ struct rt_sigframe {
64}; 66};
65 67
66/* 68/*
69 * Thread saved context copy to/from a signal context presumed to be on the
70 * user stack, and therefore accessed with appropriate macros from uaccess.h.
71 */
72static int copy_fp_to_sigcontext(struct sigcontext __user *sc)
73{
74 int i;
75 int err = 0;
76
77 for (i = 0; i < NUM_FPU_REGS; i++) {
78 err |=
79 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
80 &sc->sc_fpregs[i]);
81 }
82 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
83
84 return err;
85}
86
87static int copy_fp_from_sigcontext(struct sigcontext __user *sc)
88{
89 int i;
90 int err = 0;
91 u64 fpr_val;
92
93 for (i = 0; i < NUM_FPU_REGS; i++) {
94 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
95 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
96 }
97 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
98
99 return err;
100}
101
102/*
103 * These functions will save only the upper 64 bits of the vector registers,
104 * since the lower 64 bits have already been saved as the scalar FP context.
105 */
106static int copy_msa_to_sigcontext(struct sigcontext __user *sc)
107{
108 int i;
109 int err = 0;
110
111 for (i = 0; i < NUM_FPU_REGS; i++) {
112 err |=
113 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
114 &sc->sc_msaregs[i]);
115 }
116 err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
117
118 return err;
119}
120
121static int copy_msa_from_sigcontext(struct sigcontext __user *sc)
122{
123 int i;
124 int err = 0;
125 u64 val;
126
127 for (i = 0; i < NUM_FPU_REGS; i++) {
128 err |= __get_user(val, &sc->sc_msaregs[i]);
129 set_fpr64(&current->thread.fpu.fpr[i], 1, val);
130 }
131 err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
132
133 return err;
134}
135
136/*
67 * Helper routines 137 * Helper routines
68 */ 138 */
69static int protected_save_fp_context(struct sigcontext __user *sc) 139static int protected_save_fp_context(struct sigcontext __user *sc,
140 unsigned used_math)
70{ 141{
71 int err; 142 int err;
143 bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
144#ifndef CONFIG_EVA
72 while (1) { 145 while (1) {
73 lock_fpu_owner(); 146 lock_fpu_owner();
74 err = own_fpu_inatomic(1); 147 if (is_fpu_owner()) {
75 if (!err) 148 err = save_fp_context(sc);
76 err = save_fp_context(sc); /* this might fail */ 149 if (save_msa && !err)
77 unlock_fpu_owner(); 150 err = _save_msa_context(sc);
151 unlock_fpu_owner();
152 } else {
153 unlock_fpu_owner();
154 err = copy_fp_to_sigcontext(sc);
155 if (save_msa && !err)
156 err = copy_msa_to_sigcontext(sc);
157 }
78 if (likely(!err)) 158 if (likely(!err))
79 break; 159 break;
80 /* touch the sigcontext and try again */ 160 /* touch the sigcontext and try again */
@@ -84,18 +164,44 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
84 if (err) 164 if (err)
85 break; /* really bad sigcontext */ 165 break; /* really bad sigcontext */
86 } 166 }
167#else
168 /*
169 * EVA does not have FPU EVA instructions so saving fpu context directly
170 * does not work.
171 */
172 disable_msa();
173 lose_fpu(1);
174 err = save_fp_context(sc); /* this might fail */
175 if (save_msa && !err)
176 err = copy_msa_to_sigcontext(sc);
177#endif
87 return err; 178 return err;
88} 179}
89 180
90static int protected_restore_fp_context(struct sigcontext __user *sc) 181static int protected_restore_fp_context(struct sigcontext __user *sc,
182 unsigned used_math)
91{ 183{
92 int err, tmp __maybe_unused; 184 int err, tmp __maybe_unused;
185 bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
186#ifndef CONFIG_EVA
93 while (1) { 187 while (1) {
94 lock_fpu_owner(); 188 lock_fpu_owner();
95 err = own_fpu_inatomic(0); 189 if (is_fpu_owner()) {
96 if (!err) 190 err = restore_fp_context(sc);
97 err = restore_fp_context(sc); /* this might fail */ 191 if (restore_msa && !err) {
98 unlock_fpu_owner(); 192 enable_msa();
193 err = _restore_msa_context(sc);
194 } else {
195 /* signal handler may have used MSA */
196 disable_msa();
197 }
198 unlock_fpu_owner();
199 } else {
200 unlock_fpu_owner();
201 err = copy_fp_from_sigcontext(sc);
202 if (!err && (used_math & USEDMATH_MSA))
203 err = copy_msa_from_sigcontext(sc);
204 }
99 if (likely(!err)) 205 if (likely(!err))
100 break; 206 break;
101 /* touch the sigcontext and try again */ 207 /* touch the sigcontext and try again */
@@ -105,6 +211,17 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
105 if (err) 211 if (err)
106 break; /* really bad sigcontext */ 212 break; /* really bad sigcontext */
107 } 213 }
214#else
215 /*
216 * EVA does not have FPU EVA instructions so restoring fpu context
217 * directly does not work.
218 */
219 enable_msa();
220 lose_fpu(0);
221 err = restore_fp_context(sc); /* this might fail */
222 if (restore_msa && !err)
223 err = copy_msa_from_sigcontext(sc);
224#endif
108 return err; 225 return err;
109} 226}
110 227
@@ -135,7 +252,8 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
135 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 252 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
136 } 253 }
137 254
138 used_math = !!used_math(); 255 used_math = used_math() ? USEDMATH_FP : 0;
256 used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
139 err |= __put_user(used_math, &sc->sc_used_math); 257 err |= __put_user(used_math, &sc->sc_used_math);
140 258
141 if (used_math) { 259 if (used_math) {
@@ -143,7 +261,7 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
143 * Save FPU state to signal context. Signal handler 261 * Save FPU state to signal context. Signal handler
144 * will "inherit" current FPU state. 262 * will "inherit" current FPU state.
145 */ 263 */
146 err |= protected_save_fp_context(sc); 264 err |= protected_save_fp_context(sc, used_math);
147 } 265 }
148 return err; 266 return err;
149} 267}
@@ -168,14 +286,14 @@ int fpcsr_pending(unsigned int __user *fpcsr)
168} 286}
169 287
170static int 288static int
171check_and_restore_fp_context(struct sigcontext __user *sc) 289check_and_restore_fp_context(struct sigcontext __user *sc, unsigned used_math)
172{ 290{
173 int err, sig; 291 int err, sig;
174 292
175 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 293 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
176 if (err > 0) 294 if (err > 0)
177 err = 0; 295 err = 0;
178 err |= protected_restore_fp_context(sc); 296 err |= protected_restore_fp_context(sc, used_math);
179 return err ?: sig; 297 return err ?: sig;
180} 298}
181 299
@@ -215,9 +333,10 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
215 if (used_math) { 333 if (used_math) {
216 /* restore fpu context if we have used it before */ 334 /* restore fpu context if we have used it before */
217 if (!err) 335 if (!err)
218 err = check_and_restore_fp_context(sc); 336 err = check_and_restore_fp_context(sc, used_math);
219 } else { 337 } else {
220 /* signal handler may have used FPU. Give it up. */ 338 /* signal handler may have used FPU or MSA. Disable them. */
339 disable_msa();
221 lose_fpu(0); 340 lose_fpu(0);
222 } 341 }
223 342
@@ -591,23 +710,26 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
591} 710}
592 711
593#ifdef CONFIG_SMP 712#ifdef CONFIG_SMP
713#ifndef CONFIG_EVA
594static int smp_save_fp_context(struct sigcontext __user *sc) 714static int smp_save_fp_context(struct sigcontext __user *sc)
595{ 715{
596 return raw_cpu_has_fpu 716 return raw_cpu_has_fpu
597 ? _save_fp_context(sc) 717 ? _save_fp_context(sc)
598 : fpu_emulator_save_context(sc); 718 : copy_fp_to_sigcontext(sc);
599} 719}
600 720
601static int smp_restore_fp_context(struct sigcontext __user *sc) 721static int smp_restore_fp_context(struct sigcontext __user *sc)
602{ 722{
603 return raw_cpu_has_fpu 723 return raw_cpu_has_fpu
604 ? _restore_fp_context(sc) 724 ? _restore_fp_context(sc)
605 : fpu_emulator_restore_context(sc); 725 : copy_fp_from_sigcontext(sc);
606} 726}
727#endif /* CONFIG_EVA */
607#endif 728#endif
608 729
609static int signal_setup(void) 730static int signal_setup(void)
610{ 731{
732#ifndef CONFIG_EVA
611#ifdef CONFIG_SMP 733#ifdef CONFIG_SMP
612 /* For now just do the cpu_has_fpu check when the functions are invoked */ 734 /* For now just do the cpu_has_fpu check when the functions are invoked */
613 save_fp_context = smp_save_fp_context; 735 save_fp_context = smp_save_fp_context;
@@ -617,9 +739,13 @@ static int signal_setup(void)
617 save_fp_context = _save_fp_context; 739 save_fp_context = _save_fp_context;
618 restore_fp_context = _restore_fp_context; 740 restore_fp_context = _restore_fp_context;
619 } else { 741 } else {
620 save_fp_context = fpu_emulator_save_context; 742 save_fp_context = copy_fp_from_sigcontext;
621 restore_fp_context = fpu_emulator_restore_context; 743 restore_fp_context = copy_fp_to_sigcontext;
622 } 744 }
745#endif /* CONFIG_SMP */
746#else
747 save_fp_context = copy_fp_from_sigcontext;;
748 restore_fp_context = copy_fp_to_sigcontext;
623#endif 749#endif
624 750
625 return 0; 751 return 0;