aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2015-04-03 18:27:48 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-04-07 19:10:37 -0400
commit9b26616c8d9dae53fbac7f7cb2c6dd1308102976 (patch)
treed4249bd953d4fa955cecd1283cc0f518df83f8a2 /arch/mips/kernel
parent232b6ec5df874236166fb0167cd473601a631715 (diff)
MIPS: Respect the ISA level in FCSR handling
Define the central place the default FCSR value is set from, initialised in `cpu_probe'. Determine the FCSR mask applied to values written to the register with CTC1 in the full emulation mode and via ptrace(2), according to the ISA level of processor hardware or the writability of bits 31:18 if actual FPU hardware is used. Software may rely on FCSR bits whose functions our emulator does not implement, so it should not allow them to be set or software may get confused. For ptrace(2) it's just sanity. [ralf@linux-mips.org: Fixed double inclusion of <asm/current.h>.] Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9711/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/cpu-probe.c53
-rw-r--r--arch/mips/kernel/ptrace.c10
-rw-r--r--arch/mips/kernel/r2300_switch.S7
-rw-r--r--arch/mips/kernel/r4k_switch.S7
4 files changed, 65 insertions, 12 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index ca9b9c62c6ea..2911ad5977d7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -33,6 +33,35 @@
33#include <asm/uaccess.h> 33#include <asm/uaccess.h>
34 34
35/* 35/*
36 * Determine the FCSR mask for FPU hardware.
37 */
38static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
39{
40 unsigned long sr, mask, fcsr, fcsr0, fcsr1;
41
42 mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM;
43
44 sr = read_c0_status();
45 __enable_fpu(FPU_AS_IS);
46
47 fcsr = read_32bit_cp1_register(CP1_STATUS);
48
49 fcsr0 = fcsr & mask;
50 write_32bit_cp1_register(CP1_STATUS, fcsr0);
51 fcsr0 = read_32bit_cp1_register(CP1_STATUS);
52
53 fcsr1 = fcsr | ~mask;
54 write_32bit_cp1_register(CP1_STATUS, fcsr1);
55 fcsr1 = read_32bit_cp1_register(CP1_STATUS);
56
57 write_32bit_cp1_register(CP1_STATUS, fcsr);
58
59 write_c0_status(sr);
60
61 c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask;
62}
63
64/*
36 * Set the FIR feature flags for the FPU emulator. 65 * Set the FIR feature flags for the FPU emulator.
37 */ 66 */
38static void cpu_set_nofpu_id(struct cpuinfo_mips *c) 67static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -50,11 +79,15 @@ static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
50 c->fpu_id = value; 79 c->fpu_id = value;
51} 80}
52 81
82/* Determined FPU emulator mask to use for the boot CPU with "nofpu". */
83static unsigned int mips_nofpu_msk31;
84
53static int mips_fpu_disabled; 85static int mips_fpu_disabled;
54 86
55static int __init fpu_disable(char *s) 87static int __init fpu_disable(char *s)
56{ 88{
57 boot_cpu_data.options &= ~MIPS_CPU_FPU; 89 boot_cpu_data.options &= ~MIPS_CPU_FPU;
90 boot_cpu_data.fpu_msk31 = mips_nofpu_msk31;
58 cpu_set_nofpu_id(&boot_cpu_data); 91 cpu_set_nofpu_id(&boot_cpu_data);
59 mips_fpu_disabled = 1; 92 mips_fpu_disabled = 1;
60 93
@@ -597,6 +630,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
597 case PRID_IMP_R2000: 630 case PRID_IMP_R2000:
598 c->cputype = CPU_R2000; 631 c->cputype = CPU_R2000;
599 __cpu_name[cpu] = "R2000"; 632 __cpu_name[cpu] = "R2000";
633 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
600 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 634 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
601 MIPS_CPU_NOFPUEX; 635 MIPS_CPU_NOFPUEX;
602 if (__cpu_has_fpu()) 636 if (__cpu_has_fpu())
@@ -616,6 +650,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
616 c->cputype = CPU_R3000; 650 c->cputype = CPU_R3000;
617 __cpu_name[cpu] = "R3000"; 651 __cpu_name[cpu] = "R3000";
618 } 652 }
653 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
619 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 654 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
620 MIPS_CPU_NOFPUEX; 655 MIPS_CPU_NOFPUEX;
621 if (__cpu_has_fpu()) 656 if (__cpu_has_fpu())
@@ -664,6 +699,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
664 } 699 }
665 700
666 set_isa(c, MIPS_CPU_ISA_III); 701 set_isa(c, MIPS_CPU_ISA_III);
702 c->fpu_msk31 |= FPU_CSR_CONDX;
667 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 703 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
668 MIPS_CPU_WATCH | MIPS_CPU_VCE | 704 MIPS_CPU_WATCH | MIPS_CPU_VCE |
669 MIPS_CPU_LLSC; 705 MIPS_CPU_LLSC;
@@ -671,6 +707,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
671 break; 707 break;
672 case PRID_IMP_VR41XX: 708 case PRID_IMP_VR41XX:
673 set_isa(c, MIPS_CPU_ISA_III); 709 set_isa(c, MIPS_CPU_ISA_III);
710 c->fpu_msk31 |= FPU_CSR_CONDX;
674 c->options = R4K_OPTS; 711 c->options = R4K_OPTS;
675 c->tlbsize = 32; 712 c->tlbsize = 32;
676 switch (c->processor_id & 0xf0) { 713 switch (c->processor_id & 0xf0) {
@@ -712,6 +749,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
712 c->cputype = CPU_R4300; 749 c->cputype = CPU_R4300;
713 __cpu_name[cpu] = "R4300"; 750 __cpu_name[cpu] = "R4300";
714 set_isa(c, MIPS_CPU_ISA_III); 751 set_isa(c, MIPS_CPU_ISA_III);
752 c->fpu_msk31 |= FPU_CSR_CONDX;
715 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 753 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
716 MIPS_CPU_LLSC; 754 MIPS_CPU_LLSC;
717 c->tlbsize = 32; 755 c->tlbsize = 32;
@@ -720,6 +758,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
720 c->cputype = CPU_R4600; 758 c->cputype = CPU_R4600;
721 __cpu_name[cpu] = "R4600"; 759 __cpu_name[cpu] = "R4600";
722 set_isa(c, MIPS_CPU_ISA_III); 760 set_isa(c, MIPS_CPU_ISA_III);
761 c->fpu_msk31 |= FPU_CSR_CONDX;
723 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 762 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
724 MIPS_CPU_LLSC; 763 MIPS_CPU_LLSC;
725 c->tlbsize = 48; 764 c->tlbsize = 48;
@@ -735,11 +774,13 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
735 c->cputype = CPU_R4650; 774 c->cputype = CPU_R4650;
736 __cpu_name[cpu] = "R4650"; 775 __cpu_name[cpu] = "R4650";
737 set_isa(c, MIPS_CPU_ISA_III); 776 set_isa(c, MIPS_CPU_ISA_III);
777 c->fpu_msk31 |= FPU_CSR_CONDX;
738 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC; 778 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
739 c->tlbsize = 48; 779 c->tlbsize = 48;
740 break; 780 break;
741 #endif 781 #endif
742 case PRID_IMP_TX39: 782 case PRID_IMP_TX39:
783 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
743 c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE; 784 c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
744 785
745 if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { 786 if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
@@ -765,6 +806,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
765 c->cputype = CPU_R4700; 806 c->cputype = CPU_R4700;
766 __cpu_name[cpu] = "R4700"; 807 __cpu_name[cpu] = "R4700";
767 set_isa(c, MIPS_CPU_ISA_III); 808 set_isa(c, MIPS_CPU_ISA_III);
809 c->fpu_msk31 |= FPU_CSR_CONDX;
768 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 810 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
769 MIPS_CPU_LLSC; 811 MIPS_CPU_LLSC;
770 c->tlbsize = 48; 812 c->tlbsize = 48;
@@ -773,6 +815,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
773 c->cputype = CPU_TX49XX; 815 c->cputype = CPU_TX49XX;
774 __cpu_name[cpu] = "R49XX"; 816 __cpu_name[cpu] = "R49XX";
775 set_isa(c, MIPS_CPU_ISA_III); 817 set_isa(c, MIPS_CPU_ISA_III);
818 c->fpu_msk31 |= FPU_CSR_CONDX;
776 c->options = R4K_OPTS | MIPS_CPU_LLSC; 819 c->options = R4K_OPTS | MIPS_CPU_LLSC;
777 if (!(c->processor_id & 0x08)) 820 if (!(c->processor_id & 0x08))
778 c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR; 821 c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
@@ -814,6 +857,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
814 c->cputype = CPU_R6000; 857 c->cputype = CPU_R6000;
815 __cpu_name[cpu] = "R6000"; 858 __cpu_name[cpu] = "R6000";
816 set_isa(c, MIPS_CPU_ISA_II); 859 set_isa(c, MIPS_CPU_ISA_II);
860 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
817 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | 861 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
818 MIPS_CPU_LLSC; 862 MIPS_CPU_LLSC;
819 c->tlbsize = 32; 863 c->tlbsize = 32;
@@ -822,6 +866,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
822 c->cputype = CPU_R6000A; 866 c->cputype = CPU_R6000A;
823 __cpu_name[cpu] = "R6000A"; 867 __cpu_name[cpu] = "R6000A";
824 set_isa(c, MIPS_CPU_ISA_II); 868 set_isa(c, MIPS_CPU_ISA_II);
869 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
825 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | 870 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
826 MIPS_CPU_LLSC; 871 MIPS_CPU_LLSC;
827 c->tlbsize = 32; 872 c->tlbsize = 32;
@@ -893,12 +938,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
893 __cpu_name[cpu] = "ICT Loongson-2"; 938 __cpu_name[cpu] = "ICT Loongson-2";
894 set_elf_platform(cpu, "loongson2e"); 939 set_elf_platform(cpu, "loongson2e");
895 set_isa(c, MIPS_CPU_ISA_III); 940 set_isa(c, MIPS_CPU_ISA_III);
941 c->fpu_msk31 |= FPU_CSR_CONDX;
896 break; 942 break;
897 case PRID_REV_LOONGSON2F: 943 case PRID_REV_LOONGSON2F:
898 c->cputype = CPU_LOONGSON2; 944 c->cputype = CPU_LOONGSON2;
899 __cpu_name[cpu] = "ICT Loongson-2"; 945 __cpu_name[cpu] = "ICT Loongson-2";
900 set_elf_platform(cpu, "loongson2f"); 946 set_elf_platform(cpu, "loongson2f");
901 set_isa(c, MIPS_CPU_ISA_III); 947 set_isa(c, MIPS_CPU_ISA_III);
948 c->fpu_msk31 |= FPU_CSR_CONDX;
902 break; 949 break;
903 case PRID_REV_LOONGSON3A: 950 case PRID_REV_LOONGSON3A:
904 c->cputype = CPU_LOONGSON3; 951 c->cputype = CPU_LOONGSON3;
@@ -1335,6 +1382,9 @@ void cpu_probe(void)
1335 c->cputype = CPU_UNKNOWN; 1382 c->cputype = CPU_UNKNOWN;
1336 c->writecombine = _CACHE_UNCACHED; 1383 c->writecombine = _CACHE_UNCACHED;
1337 1384
1385 c->fpu_csr31 = FPU_CSR_RN;
1386 c->fpu_msk31 = FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
1387
1338 c->processor_id = read_c0_prid(); 1388 c->processor_id = read_c0_prid();
1339 switch (c->processor_id & PRID_COMP_MASK) { 1389 switch (c->processor_id & PRID_COMP_MASK) {
1340 case PRID_COMP_LEGACY: 1390 case PRID_COMP_LEGACY:
@@ -1393,6 +1443,7 @@ void cpu_probe(void)
1393 1443
1394 if (c->options & MIPS_CPU_FPU) { 1444 if (c->options & MIPS_CPU_FPU) {
1395 c->fpu_id = cpu_get_fpu_id(); 1445 c->fpu_id = cpu_get_fpu_id();
1446 mips_nofpu_msk31 = c->fpu_msk31;
1396 1447
1397 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 1448 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
1398 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 1449 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
@@ -1402,6 +1453,8 @@ void cpu_probe(void)
1402 if (c->fpu_id & MIPS_FPIR_FREP) 1453 if (c->fpu_id & MIPS_FPIR_FREP)
1403 c->options |= MIPS_CPU_FRE; 1454 c->options |= MIPS_CPU_FRE;
1404 } 1455 }
1456
1457 cpu_set_fpu_fcsr_mask(c);
1405 } else 1458 } else
1406 cpu_set_nofpu_id(c); 1459 cpu_set_nofpu_id(c);
1407 1460
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 510452812594..6d1e3f8005f7 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -32,6 +32,7 @@
32 32
33#include <asm/byteorder.h> 33#include <asm/byteorder.h>
34#include <asm/cpu.h> 34#include <asm/cpu.h>
35#include <asm/cpu-info.h>
35#include <asm/dsp.h> 36#include <asm/dsp.h>
36#include <asm/fpu.h> 37#include <asm/fpu.h>
37#include <asm/mipsregs.h> 38#include <asm/mipsregs.h>
@@ -137,6 +138,9 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
137{ 138{
138 union fpureg *fregs; 139 union fpureg *fregs;
139 u64 fpr_val; 140 u64 fpr_val;
141 u32 fcr31;
142 u32 value;
143 u32 mask;
140 int i; 144 int i;
141 145
142 if (!access_ok(VERIFY_READ, data, 33 * 8)) 146 if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -149,8 +153,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
149 set_fpr64(&fregs[i], 0, fpr_val); 153 set_fpr64(&fregs[i], 0, fpr_val);
150 } 154 }
151 155
152 __get_user(child->thread.fpu.fcr31, data + 64); 156 __get_user(value, data + 64);
153 child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; 157 fcr31 = child->thread.fpu.fcr31;
158 mask = current_cpu_data.fpu_msk31;
159 child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
154 160
155 /* FIR may not be written. */ 161 /* FIR may not be written. */
156 162
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 435ea652f5fa..5087a4b72e6b 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -115,11 +115,9 @@ LEAF(_restore_fp)
115 * the property that no matter whether considered as single or as double 115 * the property that no matter whether considered as single or as double
116 * precision represents signaling NANS. 116 * precision represents signaling NANS.
117 * 117 *
118 * We initialize fcr31 to rounding to nearest, no exceptions. 118 * The value to initialize fcr31 to comes in $a0.
119 */ 119 */
120 120
121#define FPU_DEFAULT 0x00000000
122
123 .set push 121 .set push
124 SET_HARDFLOAT 122 SET_HARDFLOAT
125 123
@@ -129,8 +127,7 @@ LEAF(_init_fpu)
129 or t0, t1 127 or t0, t1
130 mtc0 t0, CP0_STATUS 128 mtc0 t0, CP0_STATUS
131 129
132 li t1, FPU_DEFAULT 130 ctc1 a0, fcr31
133 ctc1 t1, fcr31
134 131
135 li t0, -1 132 li t0, -1
136 133
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 3b1a36f13a7d..04cbbde3521b 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -165,11 +165,9 @@ LEAF(_init_msa_upper)
165 * the property that no matter whether considered as single or as double 165 * the property that no matter whether considered as single or as double
166 * precision represents signaling NANS. 166 * precision represents signaling NANS.
167 * 167 *
168 * We initialize fcr31 to rounding to nearest, no exceptions. 168 * The value to initialize fcr31 to comes in $a0.
169 */ 169 */
170 170
171#define FPU_DEFAULT 0x00000000
172
173 .set push 171 .set push
174 SET_HARDFLOAT 172 SET_HARDFLOAT
175 173
@@ -180,8 +178,7 @@ LEAF(_init_fpu)
180 mtc0 t0, CP0_STATUS 178 mtc0 t0, CP0_STATUS
181 enable_fpu_hazard 179 enable_fpu_hazard
182 180
183 li t1, FPU_DEFAULT 181 ctc1 a0, fcr31
184 ctc1 t1, fcr31
185 182
186 li t1, -1 # SNaN 183 li t1, -1 # SNaN
187 184