Commit 503943e0 authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Ralf Baechle

MIPS: Add IEEE Std 754 conformance mode selection

Add an `ieee754=' kernel parameter to control IEEE Std 754 conformance
mode.

Use separate flags copied from the respective CPU feature flags, and
adjusted according to the conformance mode selected, to make binaries
requesting individual NaN encoding modes accepted or rejected as needed.
Update the initial setting for FCSR and, in the full FPU emulation mode,
its read-only mask accordingly.  Accept the mode selection requested for
legacy processors as well.

As with the EF_MIPS_NAN2008 ELF file header flag adjust both ABS2008 and
NAN2008 bits at the same time, to match the choice made for hardware
currently implemented.
Signed-off-by: default avatarMaciej W. Rozycki <macro@imgtec.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Matthew Fortune <Matthew.Fortune@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/11481/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 93adeaf6
...@@ -1436,6 +1436,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1436,6 +1436,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
In such case C2/C3 won't be used again. In such case C2/C3 won't be used again.
idle=nomwait: Disable mwait for CPU C-states idle=nomwait: Disable mwait for CPU C-states
ieee754= [MIPS] Select IEEE Std 754 conformance mode
Format: { strict | legacy | 2008 | relaxed }
Default: strict
Choose which programs will be accepted for execution
based on the IEEE 754 NaN encoding(s) supported by
the FPU and the NaN encoding requested with the value
of an ELF file header flag individually set by each
binary. Hardware implementations are permitted to
support either or both of the legacy and the 2008 NaN
encoding mode.
Available settings are as follows:
strict accept binaries that request a NaN encoding
supported by the FPU
legacy only accept legacy-NaN binaries, if supported
by the FPU
2008 only accept 2008-NaN binaries, if supported
by the FPU
relaxed accept any binaries regardless of whether
supported by the FPU
The FPU emulator is always able to support both NaN
encodings, so if no FPU hardware is present or it has
been disabled with 'nofpu', then the settings of
'legacy' and '2008' strap the emulator accordingly,
'relaxed' straps the emulator for both legacy-NaN and
2008-NaN, whereas 'strict' enables legacy-NaN only on
legacy processors and both NaN encodings on MIPS32 or
MIPS64 CPUs.
The setting for ABS.fmt/NEG.fmt instruction execution
mode generally follows that for the NaN encoding,
except where unsupported by hardware.
ignore_loglevel [KNL] ignore_loglevel [KNL]
Ignore loglevel setting - this will print /all/ Ignore loglevel setting - this will print /all/
kernel messages to the console. Useful for debugging. kernel messages to the console. Useful for debugging.
......
...@@ -447,6 +447,10 @@ struct arch_elf_state { ...@@ -447,6 +447,10 @@ struct arch_elf_state {
.overall_fp_mode = -1, \ .overall_fp_mode = -1, \
} }
/* Whether to accept legacy-NaN and 2008-NaN user binaries. */
extern bool mips_use_nan_legacy;
extern bool mips_use_nan_2008;
extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
bool is_interp, struct arch_elf_state *state); bool is_interp, struct arch_elf_state *state);
......
...@@ -151,25 +151,108 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c) ...@@ -151,25 +151,108 @@ static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
} }
/* /*
* Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes * IEEE 754 conformance mode to use. Affects the NaN encoding and the
* for the FPU emulator. Clear the flags where required in case called * ABS.fmt/NEG.fmt execution mode.
* from `fpu_disable', to override details obtained from FPU hardware. */
static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT;
/*
* Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
* to support by the FPU emulator according to the IEEE 754 conformance
* mode selected. Note that "relaxed" straps the emulator so that it
* allows 2008-NaN binaries even for legacy processors.
*/ */
static void cpu_set_nofpu_2008(struct cpuinfo_mips *c) static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
{ {
c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY);
c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { switch (ieee754) {
c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; case STRICT:
c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
} else { MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
c->options &= ~MIPS_CPU_NAN_2008; MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
} else {
c->options |= MIPS_CPU_NAN_LEGACY;
c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
}
break;
case LEGACY:
c->options |= MIPS_CPU_NAN_LEGACY; c->options |= MIPS_CPU_NAN_LEGACY;
c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008; c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
break;
case STD2008:
c->options |= MIPS_CPU_NAN_2008;
c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
break;
case RELAXED:
c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
break;
}
}
/*
* Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
* according to the "ieee754=" parameter.
*/
static void cpu_set_nan_2008(struct cpuinfo_mips *c)
{
switch (ieee754) {
case STRICT:
mips_use_nan_legacy = !!cpu_has_nan_legacy;
mips_use_nan_2008 = !!cpu_has_nan_2008;
break;
case LEGACY:
mips_use_nan_legacy = !!cpu_has_nan_legacy;
mips_use_nan_2008 = !cpu_has_nan_legacy;
break;
case STD2008:
mips_use_nan_legacy = !cpu_has_nan_2008;
mips_use_nan_2008 = !!cpu_has_nan_2008;
break;
case RELAXED:
mips_use_nan_legacy = true;
mips_use_nan_2008 = true;
break;
} }
} }
/*
* IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
* settings:
*
* strict: accept binaries that request a NaN encoding supported by the FPU
* legacy: only accept legacy-NaN binaries
* 2008: only accept 2008-NaN binaries
* relaxed: accept any binaries regardless of whether supported by the FPU
*/
static int __init ieee754_setup(char *s)
{
if (!s)
return -1;
else if (!strcmp(s, "strict"))
ieee754 = STRICT;
else if (!strcmp(s, "legacy"))
ieee754 = LEGACY;
else if (!strcmp(s, "2008"))
ieee754 = STD2008;
else if (!strcmp(s, "relaxed"))
ieee754 = RELAXED;
else
return -1;
if (!(boot_cpu_data.options & MIPS_CPU_FPU))
cpu_set_nofpu_2008(&boot_cpu_data);
cpu_set_nan_2008(&boot_cpu_data);
return 0;
}
early_param("ieee754", ieee754_setup);
/* /*
* Set the FIR feature flags for the FPU emulator. * Set the FIR feature flags for the FPU emulator.
*/ */
...@@ -212,6 +295,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c) ...@@ -212,6 +295,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c)
cpu_set_fpu_fcsr_mask(c); cpu_set_fpu_fcsr_mask(c);
cpu_set_fpu_2008(c); cpu_set_fpu_2008(c);
cpu_set_nan_2008(c);
} }
/* /*
...@@ -223,6 +307,7 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c) ...@@ -223,6 +307,7 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c)
c->fpu_msk31 = mips_nofpu_msk31; c->fpu_msk31 = mips_nofpu_msk31;
cpu_set_nofpu_2008(c); cpu_set_nofpu_2008(c);
cpu_set_nan_2008(c);
cpu_set_nofpu_id(c); cpu_set_nofpu_id(c);
} }
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
#include <asm/cpu-info.h> #include <asm/cpu-info.h>
/* Whether to accept legacy-NaN and 2008-NaN user binaries. */
bool mips_use_nan_legacy;
bool mips_use_nan_2008;
/* FPU modes */ /* FPU modes */
enum { enum {
FP_FRE, FP_FRE,
...@@ -150,16 +154,16 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, ...@@ -150,16 +154,16 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags; flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
/* /*
* Determine the NaN personality, reject the binary if no hardware * Determine the NaN personality, reject the binary if not allowed.
* support. Also ensure that any interpreter matches the executable. * Also ensure that any interpreter matches the executable.
*/ */
if (flags & EF_MIPS_NAN2008) { if (flags & EF_MIPS_NAN2008) {
if (cpu_has_nan_2008) if (mips_use_nan_2008)
state->nan_2008 = 1; state->nan_2008 = 1;
else else
return -ENOEXEC; return -ENOEXEC;
} else { } else {
if (cpu_has_nan_legacy) if (mips_use_nan_legacy)
state->nan_2008 = 0; state->nan_2008 = 0;
else else
return -ENOEXEC; return -ENOEXEC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment