diff options
-rw-r--r-- | arch/mips/include/asm/fpu.h | 2 | ||||
-rw-r--r-- | arch/mips/include/asm/processor.h | 31 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 39 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 25 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 37 | ||||
-rw-r--r-- | arch/mips/math-emu/kernel_linkage.c | 21 |
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 | ||
183 | static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) | 183 | static 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 | ||
100 | typedef __u64 fpureg_t; | 101 | union 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) \ | ||
113 | static inline u##width get_fpr##width(union fpureg *fpr, unsigned idx) \ | ||
114 | { \ | ||
115 | return fpr->val##width[FPR_IDX(width, idx)]; \ | ||
116 | } \ | ||
117 | \ | ||
118 | static 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 | |||
124 | BUILD_FPR_ACCESS(32) | ||
125 | BUILD_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 | ||
109 | struct mips_fpu_struct { | 134 | struct 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 | ||
159 | int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) | 160 | int 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(¤t->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(¤t->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(¤t->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(¤t->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(¤t->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 | ||