aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/binfmt_elfo32.c14
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/process.c3
-rw-r--r--arch/mips/kernel/ptrace.c60
-rw-r--r--arch/mips/kernel/ptrace32.c53
-rw-r--r--arch/mips/kernel/r4k_fpu.S74
-rw-r--r--arch/mips/kernel/r4k_switch.S45
-rw-r--r--arch/mips/kernel/signal.c10
-rw-r--r--arch/mips/kernel/signal32.c10
-rw-r--r--arch/mips/kernel/traps.c10
10 files changed, 209 insertions, 72 deletions
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 202e581e6096..7faf5f2bee25 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -28,6 +28,18 @@ typedef double elf_fpreg_t;
28typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; 28typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
29 29
30/* 30/*
31 * In order to be sure that we don't attempt to execute an O32 binary which
32 * requires 64 bit FP (FR=1) on a system which does not support it we refuse
33 * to execute any binary which has bits specified by the following macro set
34 * in its ELF header flags.
35 */
36#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
37# define __MIPS_O32_FP64_MUST_BE_ZERO 0
38#else
39# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64
40#endif
41
42/*
31 * This is used to ensure we don't load something for the wrong architecture. 43 * This is used to ensure we don't load something for the wrong architecture.
32 */ 44 */
33#define elf_check_arch(hdr) \ 45#define elf_check_arch(hdr) \
@@ -44,6 +56,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
44 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ 56 if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
45 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ 57 ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
46 __res = 0; \ 58 __res = 0; \
59 if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
60 __res = 0; \
47 \ 61 \
48 __res; \ 62 __res; \
49}) 63})
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index c814287bdf5d..e2b2d2043701 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void)
112 unsigned long tmp, fpu_id; 112 unsigned long tmp, fpu_id;
113 113
114 tmp = read_c0_status(); 114 tmp = read_c0_status();
115 __enable_fpu(); 115 __enable_fpu(FPU_AS_IS);
116 fpu_id = read_32bit_cp1_register(CP1_REVISION); 116 fpu_id = read_32bit_cp1_register(CP1_REVISION);
117 write_c0_status(tmp); 117 write_c0_status(tmp);
118 return fpu_id; 118 return fpu_id;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index ddc76103e78c..747a6cfbb709 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -60,9 +60,6 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
60 60
61 /* New thread loses kernel privileges. */ 61 /* New thread loses kernel privileges. */
62 status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); 62 status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
63#ifdef CONFIG_64BIT
64 status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR;
65#endif
66 status |= KU_USER; 63 status |= KU_USER;
67 regs->cp0_status = status; 64 regs->cp0_status = status;
68 clear_used_math(); 65 clear_used_math();
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index b52e1d2b33e0..7da9b76db4d9 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
137 if (cpu_has_mipsmt) { 137 if (cpu_has_mipsmt) {
138 unsigned int vpflags = dvpe(); 138 unsigned int vpflags = dvpe();
139 flags = read_c0_status(); 139 flags = read_c0_status();
140 __enable_fpu(); 140 __enable_fpu(FPU_AS_IS);
141 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); 141 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
142 write_c0_status(flags); 142 write_c0_status(flags);
143 evpe(vpflags); 143 evpe(vpflags);
144 } else { 144 } else {
145 flags = read_c0_status(); 145 flags = read_c0_status();
146 __enable_fpu(); 146 __enable_fpu(FPU_AS_IS);
147 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); 147 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
148 write_c0_status(flags); 148 write_c0_status(flags);
149 } 149 }
@@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request,
408 /* Read the word at location addr in the USER area. */ 408 /* Read the word at location addr in the USER area. */
409 case PTRACE_PEEKUSR: { 409 case PTRACE_PEEKUSR: {
410 struct pt_regs *regs; 410 struct pt_regs *regs;
411 fpureg_t *fregs;
411 unsigned long tmp = 0; 412 unsigned long tmp = 0;
412 413
413 regs = task_pt_regs(child); 414 regs = task_pt_regs(child);
@@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request,
418 tmp = regs->regs[addr]; 419 tmp = regs->regs[addr];
419 break; 420 break;
420 case FPR_BASE ... FPR_BASE + 31: 421 case FPR_BASE ... FPR_BASE + 31:
421 if (tsk_used_math(child)) { 422 if (!tsk_used_math(child)) {
422 fpureg_t *fregs = get_fpu_regs(child); 423 /* FP not yet used */
424 tmp = -1;
425 break;
426 }
427 fregs = get_fpu_regs(child);
423 428
424#ifdef CONFIG_32BIT 429#ifdef CONFIG_32BIT
430 if (test_thread_flag(TIF_32BIT_FPREGS)) {
425 /* 431 /*
426 * The odd registers are actually the high 432 * The odd registers are actually the high
427 * order bits of the values stored in the even 433 * order bits of the values stored in the even
428 * registers - unless we're using r2k_switch.S. 434 * registers - unless we're using r2k_switch.S.
429 */ 435 */
430 if (addr & 1) 436 if (addr & 1)
431 tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); 437 tmp = fregs[(addr & ~1) - 32] >> 32;
432 else 438 else
433 tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); 439 tmp = fregs[addr - 32];
434#endif 440 break;
435#ifdef CONFIG_64BIT
436 tmp = fregs[addr - FPR_BASE];
437#endif
438 } else {
439 tmp = -1; /* FP not yet used */
440 } 441 }
442#endif
443 tmp = fregs[addr - FPR_BASE];
441 break; 444 break;
442 case PC: 445 case PC:
443 tmp = regs->cp0_epc; 446 tmp = regs->cp0_epc;
@@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request,
483 if (cpu_has_mipsmt) { 486 if (cpu_has_mipsmt) {
484 unsigned int vpflags = dvpe(); 487 unsigned int vpflags = dvpe();
485 flags = read_c0_status(); 488 flags = read_c0_status();
486 __enable_fpu(); 489 __enable_fpu(FPU_AS_IS);
487 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 490 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
488 write_c0_status(flags); 491 write_c0_status(flags);
489 evpe(vpflags); 492 evpe(vpflags);
490 } else { 493 } else {
491 flags = read_c0_status(); 494 flags = read_c0_status();
492 __enable_fpu(); 495 __enable_fpu(FPU_AS_IS);
493 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 496 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
494 write_c0_status(flags); 497 write_c0_status(flags);
495 } 498 }
@@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request,
554 child->thread.fpu.fcr31 = 0; 557 child->thread.fpu.fcr31 = 0;
555 } 558 }
556#ifdef CONFIG_32BIT 559#ifdef CONFIG_32BIT
557 /* 560 if (test_thread_flag(TIF_32BIT_FPREGS)) {
558 * The odd registers are actually the high order bits 561 /*
559 * of the values stored in the even registers - unless 562 * The odd registers are actually the high
560 * we're using r2k_switch.S. 563 * order bits of the values stored in the even
561 */ 564 * registers - unless we're using r2k_switch.S.
562 if (addr & 1) { 565 */
563 fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; 566 if (addr & 1) {
564 fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; 567 fregs[(addr & ~1) - FPR_BASE] &=
565 } else { 568 0xffffffff;
566 fregs[addr - FPR_BASE] &= ~0xffffffffLL; 569 fregs[(addr & ~1) - FPR_BASE] |=
567 fregs[addr - FPR_BASE] |= data; 570 ((u64)data) << 32;
571 } else {
572 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
573 fregs[addr - FPR_BASE] |= data;
574 }
575 break;
568 } 576 }
569#endif 577#endif
570#ifdef CONFIG_64BIT
571 fregs[addr - FPR_BASE] = data; 578 fregs[addr - FPR_BASE] = data;
572#endif
573 break; 579 break;
574 } 580 }
575 case PC: 581 case PC:
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index 9486055ba660..b8aa2dd5b00b 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -80,6 +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 unsigned int tmp; 84 unsigned int tmp;
84 85
85 regs = task_pt_regs(child); 86 regs = task_pt_regs(child);
@@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
90 tmp = regs->regs[addr]; 91 tmp = regs->regs[addr];
91 break; 92 break;
92 case FPR_BASE ... FPR_BASE + 31: 93 case FPR_BASE ... FPR_BASE + 31:
93 if (tsk_used_math(child)) { 94 if (!tsk_used_math(child)) {
94 fpureg_t *fregs = get_fpu_regs(child); 95 /* FP not yet used */
95 96 tmp = -1;
97 break;
98 }
99 fregs = get_fpu_regs(child);
100 if (test_thread_flag(TIF_32BIT_FPREGS)) {
96 /* 101 /*
97 * The odd registers are actually the high 102 * The odd registers are actually the high
98 * order bits of the values stored in the even 103 * order bits of the values stored in the even
99 * registers - unless we're using r2k_switch.S. 104 * registers - unless we're using r2k_switch.S.
100 */ 105 */
101 if (addr & 1) 106 if (addr & 1)
102 tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); 107 tmp = fregs[(addr & ~1) - 32] >> 32;
103 else 108 else
104 tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); 109 tmp = fregs[addr - 32];
105 } else { 110 break;
106 tmp = -1; /* FP not yet used */
107 } 111 }
112 tmp = fregs[addr - FPR_BASE];
108 break; 113 break;
109 case PC: 114 case PC:
110 tmp = regs->cp0_epc; 115 tmp = regs->cp0_epc;
@@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
147 if (cpu_has_mipsmt) { 152 if (cpu_has_mipsmt) {
148 unsigned int vpflags = dvpe(); 153 unsigned int vpflags = dvpe();
149 flags = read_c0_status(); 154 flags = read_c0_status();
150 __enable_fpu(); 155 __enable_fpu(FPU_AS_IS);
151 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 156 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
152 write_c0_status(flags); 157 write_c0_status(flags);
153 evpe(vpflags); 158 evpe(vpflags);
154 } else { 159 } else {
155 flags = read_c0_status(); 160 flags = read_c0_status();
156 __enable_fpu(); 161 __enable_fpu(FPU_AS_IS);
157 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); 162 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
158 write_c0_status(flags); 163 write_c0_status(flags);
159 } 164 }
@@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
236 sizeof(child->thread.fpu)); 241 sizeof(child->thread.fpu));
237 child->thread.fpu.fcr31 = 0; 242 child->thread.fpu.fcr31 = 0;
238 } 243 }
239 /* 244 if (test_thread_flag(TIF_32BIT_FPREGS)) {
240 * The odd registers are actually the high order bits 245 /*
241 * of the values stored in the even registers - unless 246 * The odd registers are actually the high
242 * we're using r2k_switch.S. 247 * order bits of the values stored in the even
243 */ 248 * registers - unless we're using r2k_switch.S.
244 if (addr & 1) { 249 */
245 fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; 250 if (addr & 1) {
246 fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; 251 fregs[(addr & ~1) - FPR_BASE] &=
247 } else { 252 0xffffffff;
248 fregs[addr - FPR_BASE] &= ~0xffffffffLL; 253 fregs[(addr & ~1) - FPR_BASE] |=
249 /* Must cast, lest sign extension fill upper 254 ((u64)data) << 32;
250 bits! */ 255 } else {
251 fregs[addr - FPR_BASE] |= (unsigned int)data; 256 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
257 fregs[addr - FPR_BASE] |= data;
258 }
259 break;
252 } 260 }
261 fregs[addr - FPR_BASE] = data;
253 break; 262 break;
254 } 263 }
255 case PC: 264 case PC:
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 55ffe149dae9..253b2fb52026 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -35,7 +35,15 @@
35LEAF(_save_fp_context) 35LEAF(_save_fp_context)
36 cfc1 t1, fcr31 36 cfc1 t1, fcr31
37 37
38#ifdef CONFIG_64BIT 38#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
39 .set push
40#ifdef CONFIG_MIPS32_R2
41 .set mips64r2
42 mfc0 t0, CP0_STATUS
43 sll t0, t0, 5
44 bgez t0, 1f # skip storing odd if FR=0
45 nop
46#endif
39 /* Store the 16 odd double precision registers */ 47 /* Store the 16 odd double precision registers */
40 EX sdc1 $f1, SC_FPREGS+8(a0) 48 EX sdc1 $f1, SC_FPREGS+8(a0)
41 EX sdc1 $f3, SC_FPREGS+24(a0) 49 EX sdc1 $f3, SC_FPREGS+24(a0)
@@ -53,6 +61,7 @@ LEAF(_save_fp_context)
53 EX sdc1 $f27, SC_FPREGS+216(a0) 61 EX sdc1 $f27, SC_FPREGS+216(a0)
54 EX sdc1 $f29, SC_FPREGS+232(a0) 62 EX sdc1 $f29, SC_FPREGS+232(a0)
55 EX sdc1 $f31, SC_FPREGS+248(a0) 63 EX sdc1 $f31, SC_FPREGS+248(a0)
641: .set pop
56#endif 65#endif
57 66
58 /* Store the 16 even double precision registers */ 67 /* Store the 16 even double precision registers */
@@ -82,7 +91,31 @@ LEAF(_save_fp_context)
82LEAF(_save_fp_context32) 91LEAF(_save_fp_context32)
83 cfc1 t1, fcr31 92 cfc1 t1, fcr31
84 93
85 EX sdc1 $f0, SC32_FPREGS+0(a0) 94 mfc0 t0, CP0_STATUS
95 sll t0, t0, 5
96 bgez t0, 1f # skip storing odd if FR=0
97 nop
98
99 /* Store the 16 odd double precision registers */
100 EX sdc1 $f1, SC32_FPREGS+8(a0)
101 EX sdc1 $f3, SC32_FPREGS+24(a0)
102 EX sdc1 $f5, SC32_FPREGS+40(a0)
103 EX sdc1 $f7, SC32_FPREGS+56(a0)
104 EX sdc1 $f9, SC32_FPREGS+72(a0)
105 EX sdc1 $f11, SC32_FPREGS+88(a0)
106 EX sdc1 $f13, SC32_FPREGS+104(a0)
107 EX sdc1 $f15, SC32_FPREGS+120(a0)
108 EX sdc1 $f17, SC32_FPREGS+136(a0)
109 EX sdc1 $f19, SC32_FPREGS+152(a0)
110 EX sdc1 $f21, SC32_FPREGS+168(a0)
111 EX sdc1 $f23, SC32_FPREGS+184(a0)
112 EX sdc1 $f25, SC32_FPREGS+200(a0)
113 EX sdc1 $f27, SC32_FPREGS+216(a0)
114 EX sdc1 $f29, SC32_FPREGS+232(a0)
115 EX sdc1 $f31, SC32_FPREGS+248(a0)
116
117 /* Store the 16 even double precision registers */
1181: EX sdc1 $f0, SC32_FPREGS+0(a0)
86 EX sdc1 $f2, SC32_FPREGS+16(a0) 119 EX sdc1 $f2, SC32_FPREGS+16(a0)
87 EX sdc1 $f4, SC32_FPREGS+32(a0) 120 EX sdc1 $f4, SC32_FPREGS+32(a0)
88 EX sdc1 $f6, SC32_FPREGS+48(a0) 121 EX sdc1 $f6, SC32_FPREGS+48(a0)
@@ -114,7 +147,16 @@ LEAF(_save_fp_context32)
114 */ 147 */
115LEAF(_restore_fp_context) 148LEAF(_restore_fp_context)
116 EX lw t0, SC_FPC_CSR(a0) 149 EX lw t0, SC_FPC_CSR(a0)
117#ifdef CONFIG_64BIT 150
151#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
152 .set push
153#ifdef CONFIG_MIPS32_R2
154 .set mips64r2
155 mfc0 t0, CP0_STATUS
156 sll t0, t0, 5
157 bgez t0, 1f # skip loading odd if FR=0
158 nop
159#endif
118 EX ldc1 $f1, SC_FPREGS+8(a0) 160 EX ldc1 $f1, SC_FPREGS+8(a0)
119 EX ldc1 $f3, SC_FPREGS+24(a0) 161 EX ldc1 $f3, SC_FPREGS+24(a0)
120 EX ldc1 $f5, SC_FPREGS+40(a0) 162 EX ldc1 $f5, SC_FPREGS+40(a0)
@@ -131,6 +173,7 @@ LEAF(_restore_fp_context)
131 EX ldc1 $f27, SC_FPREGS+216(a0) 173 EX ldc1 $f27, SC_FPREGS+216(a0)
132 EX ldc1 $f29, SC_FPREGS+232(a0) 174 EX ldc1 $f29, SC_FPREGS+232(a0)
133 EX ldc1 $f31, SC_FPREGS+248(a0) 175 EX ldc1 $f31, SC_FPREGS+248(a0)
1761: .set pop
134#endif 177#endif
135 EX ldc1 $f0, SC_FPREGS+0(a0) 178 EX ldc1 $f0, SC_FPREGS+0(a0)
136 EX ldc1 $f2, SC_FPREGS+16(a0) 179 EX ldc1 $f2, SC_FPREGS+16(a0)
@@ -157,7 +200,30 @@ LEAF(_restore_fp_context)
157LEAF(_restore_fp_context32) 200LEAF(_restore_fp_context32)
158 /* Restore an o32 sigcontext. */ 201 /* Restore an o32 sigcontext. */
159 EX lw t0, SC32_FPC_CSR(a0) 202 EX lw t0, SC32_FPC_CSR(a0)
160 EX ldc1 $f0, SC32_FPREGS+0(a0) 203
204 mfc0 t0, CP0_STATUS
205 sll t0, t0, 5
206 bgez t0, 1f # skip loading odd if FR=0
207 nop
208
209 EX ldc1 $f1, SC32_FPREGS+8(a0)
210 EX ldc1 $f3, SC32_FPREGS+24(a0)
211 EX ldc1 $f5, SC32_FPREGS+40(a0)
212 EX ldc1 $f7, SC32_FPREGS+56(a0)
213 EX ldc1 $f9, SC32_FPREGS+72(a0)
214 EX ldc1 $f11, SC32_FPREGS+88(a0)
215 EX ldc1 $f13, SC32_FPREGS+104(a0)
216 EX ldc1 $f15, SC32_FPREGS+120(a0)
217 EX ldc1 $f17, SC32_FPREGS+136(a0)
218 EX ldc1 $f19, SC32_FPREGS+152(a0)
219 EX ldc1 $f21, SC32_FPREGS+168(a0)
220 EX ldc1 $f23, SC32_FPREGS+184(a0)
221 EX ldc1 $f25, SC32_FPREGS+200(a0)
222 EX ldc1 $f27, SC32_FPREGS+216(a0)
223 EX ldc1 $f29, SC32_FPREGS+232(a0)
224 EX ldc1 $f31, SC32_FPREGS+248(a0)
225
2261: EX ldc1 $f0, SC32_FPREGS+0(a0)
161 EX ldc1 $f2, SC32_FPREGS+16(a0) 227 EX ldc1 $f2, SC32_FPREGS+16(a0)
162 EX ldc1 $f4, SC32_FPREGS+32(a0) 228 EX ldc1 $f4, SC32_FPREGS+32(a0)
163 EX ldc1 $f6, SC32_FPREGS+48(a0) 229 EX ldc1 $f6, SC32_FPREGS+48(a0)
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 078de5eaca8f..cc78dd9a17c7 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -123,7 +123,7 @@
123 * Save a thread's fp context. 123 * Save a thread's fp context.
124 */ 124 */
125LEAF(_save_fp) 125LEAF(_save_fp)
126#ifdef CONFIG_64BIT 126#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
127 mfc0 t0, CP0_STATUS 127 mfc0 t0, CP0_STATUS
128#endif 128#endif
129 fpu_save_double a0 t0 t1 # clobbers t1 129 fpu_save_double a0 t0 t1 # clobbers t1
@@ -134,7 +134,7 @@ LEAF(_save_fp)
134 * Restore a thread's fp context. 134 * Restore a thread's fp context.
135 */ 135 */
136LEAF(_restore_fp) 136LEAF(_restore_fp)
137#ifdef CONFIG_64BIT 137#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
138 mfc0 t0, CP0_STATUS 138 mfc0 t0, CP0_STATUS
139#endif 139#endif
140 fpu_restore_double a0 t0 t1 # clobbers t1 140 fpu_restore_double a0 t0 t1 # clobbers t1
@@ -228,6 +228,47 @@ LEAF(_init_fpu)
228 mtc1 t1, $f29 228 mtc1 t1, $f29
229 mtc1 t1, $f30 229 mtc1 t1, $f30
230 mtc1 t1, $f31 230 mtc1 t1, $f31
231
232#ifdef CONFIG_CPU_MIPS32_R2
233 .set push
234 .set mips64r2
235 sll t0, t0, 5 # is Status.FR set?
236 bgez t0, 1f # no: skip setting upper 32b
237
238 mthc1 t1, $f0
239 mthc1 t1, $f1
240 mthc1 t1, $f2
241 mthc1 t1, $f3
242 mthc1 t1, $f4
243 mthc1 t1, $f5
244 mthc1 t1, $f6
245 mthc1 t1, $f7
246 mthc1 t1, $f8
247 mthc1 t1, $f9
248 mthc1 t1, $f10
249 mthc1 t1, $f11
250 mthc1 t1, $f12
251 mthc1 t1, $f13
252 mthc1 t1, $f14
253 mthc1 t1, $f15
254 mthc1 t1, $f16
255 mthc1 t1, $f17
256 mthc1 t1, $f18
257 mthc1 t1, $f19
258 mthc1 t1, $f20
259 mthc1 t1, $f21
260 mthc1 t1, $f22
261 mthc1 t1, $f23
262 mthc1 t1, $f24
263 mthc1 t1, $f25
264 mthc1 t1, $f26
265 mthc1 t1, $f27
266 mthc1 t1, $f28
267 mthc1 t1, $f29
268 mthc1 t1, $f30
269 mthc1 t1, $f31
2701: .set pop
271#endif /* CONFIG_CPU_MIPS32_R2 */
231#else 272#else
232 .set mips3 273 .set mips3
233 dmtc1 t1, $f0 274 dmtc1 t1, $f0
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 2f285abc76d5..5199563c4403 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -71,8 +71,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
71 int err; 71 int err;
72 while (1) { 72 while (1) {
73 lock_fpu_owner(); 73 lock_fpu_owner();
74 own_fpu_inatomic(1); 74 err = own_fpu_inatomic(1);
75 err = save_fp_context(sc); /* this might fail */ 75 if (!err)
76 err = save_fp_context(sc); /* this might fail */
76 unlock_fpu_owner(); 77 unlock_fpu_owner();
77 if (likely(!err)) 78 if (likely(!err))
78 break; 79 break;
@@ -91,8 +92,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
91 int err, tmp __maybe_unused; 92 int err, tmp __maybe_unused;
92 while (1) { 93 while (1) {
93 lock_fpu_owner(); 94 lock_fpu_owner();
94 own_fpu_inatomic(0); 95 err = own_fpu_inatomic(0);
95 err = restore_fp_context(sc); /* this might fail */ 96 if (!err)
97 err = restore_fp_context(sc); /* this might fail */
96 unlock_fpu_owner(); 98 unlock_fpu_owner();
97 if (likely(!err)) 99 if (likely(!err))
98 break; 100 break;
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 1905a419aa46..3d60f7750fa8 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -85,8 +85,9 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
85 int err; 85 int err;
86 while (1) { 86 while (1) {
87 lock_fpu_owner(); 87 lock_fpu_owner();
88 own_fpu_inatomic(1); 88 err = own_fpu_inatomic(1);
89 err = save_fp_context32(sc); /* this might fail */ 89 if (!err)
90 err = save_fp_context32(sc); /* this might fail */
90 unlock_fpu_owner(); 91 unlock_fpu_owner();
91 if (likely(!err)) 92 if (likely(!err))
92 break; 93 break;
@@ -105,8 +106,9 @@ static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
105 int err, tmp __maybe_unused; 106 int err, tmp __maybe_unused;
106 while (1) { 107 while (1) {
107 lock_fpu_owner(); 108 lock_fpu_owner();
108 own_fpu_inatomic(0); 109 err = own_fpu_inatomic(0);
109 err = restore_fp_context32(sc); /* this might fail */ 110 if (!err)
111 err = restore_fp_context32(sc); /* this might fail */
110 unlock_fpu_owner(); 112 unlock_fpu_owner();
111 if (likely(!err)) 113 if (likely(!err))
112 break; 114 break;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index f9c8746be8d6..f40f688276c2 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1080,7 +1080,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1080 unsigned long old_epc, old31; 1080 unsigned long old_epc, old31;
1081 unsigned int opcode; 1081 unsigned int opcode;
1082 unsigned int cpid; 1082 unsigned int cpid;
1083 int status; 1083 int status, err;
1084 unsigned long __maybe_unused flags; 1084 unsigned long __maybe_unused flags;
1085 1085
1086 prev_state = exception_enter(); 1086 prev_state = exception_enter();
@@ -1153,19 +1153,19 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1153 1153
1154 case 1: 1154 case 1:
1155 if (used_math()) /* Using the FPU again. */ 1155 if (used_math()) /* Using the FPU again. */
1156 own_fpu(1); 1156 err = own_fpu(1);
1157 else { /* First time FPU user. */ 1157 else { /* First time FPU user. */
1158 init_fpu(); 1158 err = init_fpu();
1159 set_used_math(); 1159 set_used_math();
1160 } 1160 }
1161 1161
1162 if (!raw_cpu_has_fpu) { 1162 if (!raw_cpu_has_fpu || err) {
1163 int sig; 1163 int sig;
1164 void __user *fault_addr = NULL; 1164 void __user *fault_addr = NULL;
1165 sig = fpu_emulator_cop1Handler(regs, 1165 sig = fpu_emulator_cop1Handler(regs,
1166 &current->thread.fpu, 1166 &current->thread.fpu,
1167 0, &fault_addr); 1167 0, &fault_addr);
1168 if (!process_fpemu_return(sig, fault_addr)) 1168 if (!process_fpemu_return(sig, fault_addr) && !err)
1169 mt_ase_fp_affinity(); 1169 mt_ase_fp_affinity();
1170 } 1170 }
1171 1171