diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/binfmt_elfo32.c | 14 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 60 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 53 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 74 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_switch.S | 45 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 10 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 10 |
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; | |||
28 | typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; | 28 | typedef 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 @@ | |||
35 | LEAF(_save_fp_context) | 35 | LEAF(_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) |
64 | 1: .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) | |||
82 | LEAF(_save_fp_context32) | 91 | LEAF(_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 */ | ||
118 | 1: 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 | */ |
115 | LEAF(_restore_fp_context) | 148 | LEAF(_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) |
176 | 1: .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) | |||
157 | LEAF(_restore_fp_context32) | 200 | LEAF(_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 | |||
226 | 1: 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 | */ |
125 | LEAF(_save_fp) | 125 | LEAF(_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 | */ |
136 | LEAF(_restore_fp) | 136 | LEAF(_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 | ||
270 | 1: .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 | ¤t->thread.fpu, | 1166 | ¤t->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 | ||