aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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