Skip to content

Commit b0c34f6

Browse files
committed
MIPS: Do not fiddle with FRE unless FRE is actually available.
Commit 4227a2d (MIPS: Support for hybrid FPRs) changes the kernel to execute read_c0_config5() even on processors that don't have a Config5 register. According to the arch spec the behaviour of trying to read or write this register is UNDEFINED where this register doesn't exist, that is merely looking at this register is already cruel because that might kill a kitten. In case of Qemu older than v2.2 Qemu has elected to implement this UNDEFINED behaviour by taking a RI exception - which then fries the kernel: [...] Freeing YAMON memory: 956k freed Freeing unused kernel memory: 240K (80674000 - 806b0000) Reserved instruction in kernel code[#1]: CPU: 0 PID: 1 Comm: init Not tainted 3.18.0-rc6-00058-g4227a2d #26 task: 86047588 ti: 86048000 task.ti: 86048000 $ 0 : 00000000 77a638cc 00000000 00000000 [...] For qemu v2.2.0 commit f31b035 (target-mips: correctly handle access to unimplemented CP0 register) changed the behaviour to returning zero on read and ignoring writes which more matches how typical hardware implementations actually behave. Signed-off-by: Ralf Baechle <[email protected]>
1 parent eaa27f3 commit b0c34f6

File tree

1 file changed

+27
-16
lines changed
  • arch/mips/include/asm

1 file changed

+27
-16
lines changed

arch/mips/include/asm/fpu.h

+27-16
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ static inline int __enable_fpu(enum fpu_mode mode)
7474
#endif
7575
/* fall through */
7676
case FPU_32BIT:
77-
/* clear FRE */
78-
write_c0_config5(read_c0_config5() & ~MIPS_CONF5_FRE);
77+
if (cpu_has_fre) {
78+
/* clear FRE */
79+
write_c0_config5(read_c0_config5() & ~MIPS_CONF5_FRE);
80+
}
7981
fr_common:
8082
/* set CU1 & change FR appropriately */
8183
fr = (int)mode & FPU_FR_MASK;
@@ -182,25 +184,34 @@ static inline int init_fpu(void)
182184
int ret = 0;
183185

184186
if (cpu_has_fpu) {
187+
unsigned int config5;
188+
185189
ret = __own_fpu();
186-
if (!ret) {
187-
unsigned int config5 = read_c0_config5();
188-
189-
/*
190-
* Ensure FRE is clear whilst running _init_fpu, since
191-
* single precision FP instructions are used. If FRE
192-
* was set then we'll just end up initialising all 32
193-
* 64b registers.
194-
*/
195-
write_c0_config5(config5 & ~MIPS_CONF5_FRE);
196-
enable_fpu_hazard();
190+
if (ret)
191+
return ret;
197192

193+
if (!cpu_has_fre) {
198194
_init_fpu();
199195

200-
/* Restore FRE */
201-
write_c0_config5(config5);
202-
enable_fpu_hazard();
196+
return 0;
203197
}
198+
199+
config5 = read_c0_config5();
200+
201+
/*
202+
* Ensure FRE is clear whilst running _init_fpu, since
203+
* single precision FP instructions are used. If FRE
204+
* was set then we'll just end up initialising all 32
205+
* 64b registers.
206+
*/
207+
write_c0_config5(config5 & ~MIPS_CONF5_FRE);
208+
enable_fpu_hazard();
209+
210+
_init_fpu();
211+
212+
/* Restore FRE */
213+
write_c0_config5(config5);
214+
enable_fpu_hazard();
204215
} else
205216
fpu_emulator_init_fpu();
206217

0 commit comments

Comments
 (0)