aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-02-13 06:26:41 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-03-26 18:09:09 -0400
commitbbd426f542cb61f2322e15dab4507f2661090c06 (patch)
tree66cc94a921b0342a4a412646d549562a578fc257 /arch/mips
parent490b004febb3fe9aca7330a729b29fe935be3b31 (diff)
MIPS: Simplify FP context access
This patch replaces the fpureg_t typedef with a "union fpureg" enabling easier access to 32 & 64 bit values. This allows the access macros used in cp1emu.c to be simplified somewhat. It will also make it easier to expand the width of the FP registers as will be done in a future patch in order to support the 128 bit registers introduced with MSA. No behavioural change is intended by this patch. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Reviewed-by: Qais Yousef <qais.yousef@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6532/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/asm/fpu.h2
-rw-r--r--arch/mips/include/asm/processor.h31
-rw-r--r--arch/mips/kernel/ptrace.c39
-rw-r--r--arch/mips/kernel/ptrace32.c25
-rw-r--r--arch/mips/math-emu/cp1emu.c37
-rw-r--r--arch/mips/math-emu/kernel_linkage.c21
6 files changed, 90 insertions, 65 deletions
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index 6b9749540edf..8a3d61f0017f 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -180,7 +180,7 @@ static inline void restore_fp(struct task_struct *tsk)
180 _restore_fp(tsk); 180 _restore_fp(tsk);
181} 181}
182 182
183static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) 183static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
184{ 184{
185 if (tsk == current) { 185 if (tsk == current) {
186 preempt_disable(); 186 preempt_disable();
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 3605b844ad87..49a61bedf40e 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -96,8 +96,33 @@ extern unsigned int vced_count, vcei_count;
96 96
97 97
98#define NUM_FPU_REGS 32 98#define NUM_FPU_REGS 32
99#define FPU_REG_WIDTH 64
99 100
100typedef __u64 fpureg_t; 101union fpureg {
102 __u32 val32[FPU_REG_WIDTH / 32];
103 __u64 val64[FPU_REG_WIDTH / 64];
104};
105
106#ifdef CONFIG_CPU_LITTLE_ENDIAN
107# define FPR_IDX(width, idx) (idx)
108#else
109# define FPR_IDX(width, idx) ((FPU_REG_WIDTH / (width)) - 1 - (idx))
110#endif
111
112#define BUILD_FPR_ACCESS(width) \
113static inline u##width get_fpr##width(union fpureg *fpr, unsigned idx) \
114{ \
115 return fpr->val##width[FPR_IDX(width, idx)]; \
116} \
117 \
118static inline void set_fpr##width(union fpureg *fpr, unsigned idx, \
119 u##width val) \
120{ \
121 fpr->val##width[FPR_IDX(width, idx)] = val; \
122}
123
124BUILD_FPR_ACCESS(32)
125BUILD_FPR_ACCESS(64)
101 126
102/* 127/*
103 * It would be nice to add some more fields for emulator statistics, but there 128 * It would be nice to add some more fields for emulator statistics, but there
@@ -107,7 +132,7 @@ typedef __u64 fpureg_t;
107 */ 132 */
108 133
109struct mips_fpu_struct { 134struct mips_fpu_struct {
110 fpureg_t fpr[NUM_FPU_REGS]; 135 union fpureg fpr[NUM_FPU_REGS];
111 unsigned int fcr31; 136 unsigned int fcr31;
112}; 137};
113 138
@@ -284,7 +309,7 @@ struct thread_struct {
284 * Saved FPU/FPU emulator stuff \ 309 * Saved FPU/FPU emulator stuff \
285 */ \ 310 */ \
286 .fpu = { \ 311 .fpu = { \
287 .fpr = {0,}, \ 312 .fpr = {{{0,},},}, \
288 .fcr31 = 0, \ 313 .fcr31 = 0, \
289 }, \ 314 }, \
290 /* \ 315 /* \
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index a17a7023d7c9..7d97709e715f 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -120,9 +120,10 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
120 return -EIO; 120 return -EIO;
121 121
122 if (tsk_used_math(child)) { 122 if (tsk_used_math(child)) {
123 fpureg_t *fregs = get_fpu_regs(child); 123 union fpureg *fregs = get_fpu_regs(child);
124 for (i = 0; i < 32; i++) 124 for (i = 0; i < 32; i++)
125 __put_user(fregs[i], i + (__u64 __user *) data); 125 __put_user(get_fpr64(&fregs[i], 0),
126 i + (__u64 __user *)data);
126 } else { 127 } else {
127 for (i = 0; i < 32; i++) 128 for (i = 0; i < 32; i++)
128 __put_user((__u64) -1, i + (__u64 __user *) data); 129 __put_user((__u64) -1, i + (__u64 __user *) data);
@@ -158,7 +159,8 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
158 159
159int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) 160int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
160{ 161{
161 fpureg_t *fregs; 162 union fpureg *fregs;
163 u64 fpr_val;
162 int i; 164 int i;
163 165
164 if (!access_ok(VERIFY_READ, data, 33 * 8)) 166 if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -166,8 +168,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
166 168
167 fregs = get_fpu_regs(child); 169 fregs = get_fpu_regs(child);
168 170
169 for (i = 0; i < 32; i++) 171 for (i = 0; i < 32; i++) {
170 __get_user(fregs[i], i + (__u64 __user *) data); 172 __get_user(fpr_val, i + (__u64 __user *)data);
173 set_fpr64(&fregs[i], 0, fpr_val);
174 }
171 175
172 __get_user(child->thread.fpu.fcr31, data + 64); 176 __get_user(child->thread.fpu.fcr31, data + 64);
173 177
@@ -408,7 +412,7 @@ long arch_ptrace(struct task_struct *child, long request,
408 /* Read the word at location addr in the USER area. */ 412 /* Read the word at location addr in the USER area. */
409 case PTRACE_PEEKUSR: { 413 case PTRACE_PEEKUSR: {
410 struct pt_regs *regs; 414 struct pt_regs *regs;
411 fpureg_t *fregs; 415 union fpureg *fregs;
412 unsigned long tmp = 0; 416 unsigned long tmp = 0;
413 417
414 regs = task_pt_regs(child); 418 regs = task_pt_regs(child);
@@ -433,14 +437,12 @@ long arch_ptrace(struct task_struct *child, long request,
433 * order bits of the values stored in the even 437 * order bits of the values stored in the even
434 * registers - unless we're using r2k_switch.S. 438 * registers - unless we're using r2k_switch.S.
435 */ 439 */
436 if (addr & 1) 440 tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
437 tmp = fregs[(addr & ~1) - 32] >> 32; 441 addr & 1);
438 else
439 tmp = fregs[addr - 32];
440 break; 442 break;
441 } 443 }
442#endif 444#endif
443 tmp = fregs[addr - FPR_BASE]; 445 tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
444 break; 446 break;
445 case PC: 447 case PC:
446 tmp = regs->cp0_epc; 448 tmp = regs->cp0_epc;
@@ -548,7 +550,7 @@ long arch_ptrace(struct task_struct *child, long request,
548 regs->regs[addr] = data; 550 regs->regs[addr] = data;
549 break; 551 break;
550 case FPR_BASE ... FPR_BASE + 31: { 552 case FPR_BASE ... FPR_BASE + 31: {
551 fpureg_t *fregs = get_fpu_regs(child); 553 union fpureg *fregs = get_fpu_regs(child);
552 554
553 if (!tsk_used_math(child)) { 555 if (!tsk_used_math(child)) {
554 /* FP not yet used */ 556 /* FP not yet used */
@@ -563,19 +565,12 @@ long arch_ptrace(struct task_struct *child, long request,
563 * order bits of the values stored in the even 565 * order bits of the values stored in the even
564 * registers - unless we're using r2k_switch.S. 566 * registers - unless we're using r2k_switch.S.
565 */ 567 */
566 if (addr & 1) { 568 set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
567 fregs[(addr & ~1) - FPR_BASE] &= 569 addr & 1, data);
568 0xffffffff;
569 fregs[(addr & ~1) - FPR_BASE] |=
570 ((u64)data) << 32;
571 } else {
572 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
573 fregs[addr - FPR_BASE] |= data;
574 }
575 break; 570 break;
576 } 571 }
577#endif 572#endif
578 fregs[addr - FPR_BASE] = data; 573 set_fpr64(&fregs[addr - FPR_BASE], 0, data);
579 break; 574 break;
580 } 575 }
581 case PC: 576 case PC:
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index b8aa2dd5b00b..c394d8f74265 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -80,7 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
80 /* Read the word at location addr in the USER area. */ 80 /* Read the word at location addr in the USER area. */
81 case PTRACE_PEEKUSR: { 81 case PTRACE_PEEKUSR: {
82 struct pt_regs *regs; 82 struct pt_regs *regs;
83 fpureg_t *fregs; 83 union fpureg *fregs;
84 unsigned int tmp; 84 unsigned int tmp;
85 85
86 regs = task_pt_regs(child); 86 regs = task_pt_regs(child);
@@ -103,13 +103,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
103 * order bits of the values stored in the even 103 * order bits of the values stored in the even
104 * registers - unless we're using r2k_switch.S. 104 * registers - unless we're using r2k_switch.S.
105 */ 105 */
106 if (addr & 1) 106 tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
107 tmp = fregs[(addr & ~1) - 32] >> 32; 107 addr & 1);
108 else
109 tmp = fregs[addr - 32];
110 break; 108 break;
111 } 109 }
112 tmp = fregs[addr - FPR_BASE]; 110 tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
113 break; 111 break;
114 case PC: 112 case PC:
115 tmp = regs->cp0_epc; 113 tmp = regs->cp0_epc;
@@ -233,7 +231,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
233 regs->regs[addr] = data; 231 regs->regs[addr] = data;
234 break; 232 break;
235 case FPR_BASE ... FPR_BASE + 31: { 233 case FPR_BASE ... FPR_BASE + 31: {
236 fpureg_t *fregs = get_fpu_regs(child); 234 union fpureg *fregs = get_fpu_regs(child);
237 235
238 if (!tsk_used_math(child)) { 236 if (!tsk_used_math(child)) {
239 /* FP not yet used */ 237 /* FP not yet used */
@@ -247,18 +245,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
247 * order bits of the values stored in the even 245 * order bits of the values stored in the even
248 * registers - unless we're using r2k_switch.S. 246 * registers - unless we're using r2k_switch.S.
249 */ 247 */
250 if (addr & 1) { 248 set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
251 fregs[(addr & ~1) - FPR_BASE] &= 249 addr & 1, data);
252 0xffffffff;
253 fregs[(addr & ~1) - FPR_BASE] |=
254 ((u64)data) << 32;
255 } else {
256 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
257 fregs[addr - FPR_BASE] |= data;
258 }
259 break; 250 break;
260 } 251 }
261 fregs[addr - FPR_BASE] = data; 252 set_fpr64(&fregs[addr - FPR_BASE], 0, data);
262 break; 253 break;
263 } 254 }
264 case PC: 255 case PC:
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 506925b2c3f3..196cf1ab65af 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -876,20 +876,28 @@ static inline int cop1_64bit(struct pt_regs *xcp)
876#endif 876#endif
877} 877}
878 878
879#define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \ 879#define SIFROMREG(si, x) do { \
880 (int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32)) 880 if (cop1_64bit(xcp)) \
881 (si) = get_fpr32(&ctx->fpr[x], 0); \
882 else \
883 (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \
884} while (0)
881 885
882#define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \ 886#define SITOREG(si, x) do { \
883 cop1_64bit(xcp) || !(x & 1) ? \ 887 if (cop1_64bit(xcp)) \
884 ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ 888 set_fpr32(&ctx->fpr[x], 0, si); \
885 ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) 889 else \
890 set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \
891} while (0)
886 892
887#define SIFROMHREG(si, x) ((si) = (int)(ctx->fpr[x] >> 32)) 893#define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1))
888#define SITOHREG(si, x) (ctx->fpr[x] = \ 894#define SITOHREG(si, x) set_fpr32(&ctx->fpr[x], 1, si)
889 ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32)
890 895
891#define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)]) 896#define DIFROMREG(di, x) \
892#define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di)) 897 ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
898
899#define DITOREG(di, x) \
900 set_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0, di)
893 901
894#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) 902#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
895#define SPTOREG(sp, x) SITOREG((sp).bits, x) 903#define SPTOREG(sp, x) SITOREG((sp).bits, x)
@@ -1960,15 +1968,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
1960 1968
1961#if defined(__mips64) 1969#if defined(__mips64)
1962 case l_fmt:{ 1970 case l_fmt:{
1971 u64 bits;
1972 DIFROMREG(bits, MIPSInst_FS(ir));
1973
1963 switch (MIPSInst_FUNC(ir)) { 1974 switch (MIPSInst_FUNC(ir)) {
1964 case fcvts_op: 1975 case fcvts_op:
1965 /* convert long to single precision real */ 1976 /* convert long to single precision real */
1966 rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]); 1977 rv.s = ieee754sp_flong(bits);
1967 rfmt = s_fmt; 1978 rfmt = s_fmt;
1968 goto copcsr; 1979 goto copcsr;
1969 case fcvtd_op: 1980 case fcvtd_op:
1970 /* convert long to double precision real */ 1981 /* convert long to double precision real */
1971 rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]); 1982 rv.d = ieee754dp_flong(bits);
1972 rfmt = d_fmt; 1983 rfmt = d_fmt;
1973 goto copcsr; 1984 goto copcsr;
1974 default: 1985 default:
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index 3aeae07ed5b8..9b46213b1035 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -40,9 +40,8 @@ void fpu_emulator_init_fpu(void)
40 } 40 }
41 41
42 current->thread.fpu.fcr31 = 0; 42 current->thread.fpu.fcr31 = 0;
43 for (i = 0; i < 32; i++) { 43 for (i = 0; i < 32; i++)
44 current->thread.fpu.fpr[i] = SIGNALLING_NAN; 44 set_fpr64(&current->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
45 }
46} 45}
47 46
48 47
@@ -59,7 +58,8 @@ int fpu_emulator_save_context(struct sigcontext __user *sc)
59 58
60 for (i = 0; i < 32; i++) { 59 for (i = 0; i < 32; i++) {
61 err |= 60 err |=
62 __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 61 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
62 &sc->sc_fpregs[i]);
63 } 63 }
64 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 64 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
65 65
@@ -70,10 +70,11 @@ int fpu_emulator_restore_context(struct sigcontext __user *sc)
70{ 70{
71 int i; 71 int i;
72 int err = 0; 72 int err = 0;
73 u64 fpr_val;
73 74
74 for (i = 0; i < 32; i++) { 75 for (i = 0; i < 32; i++) {
75 err |= 76 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
76 __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 77 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
77 } 78 }
78 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 79 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
79 80
@@ -93,7 +94,8 @@ int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
93 94
94 for (i = 0; i < 32; i += inc) { 95 for (i = 0; i < 32; i += inc) {
95 err |= 96 err |=
96 __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 97 __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
98 &sc->sc_fpregs[i]);
97 } 99 }
98 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 100 err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
99 101
@@ -105,10 +107,11 @@ int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
105 int i; 107 int i;
106 int err = 0; 108 int err = 0;
107 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; 109 int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
110 u64 fpr_val;
108 111
109 for (i = 0; i < 32; i += inc) { 112 for (i = 0; i < 32; i += inc) {
110 err |= 113 err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
111 __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]); 114 set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
112 } 115 }
113 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 116 err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
114 117