diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 742f69d18fc8..4bcd23355e86 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1436,6 +1436,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted. In such case C2/C3 won't be used again. 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 setting - this will print /all/ kernel messages to the console. Useful for debugging. diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 3dba5d05830c..cefb7a596878 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -447,6 +447,10 @@ struct arch_elf_state { .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, bool is_interp, struct arch_elf_state *state); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 0aa61a95eb4b..b725b713b9f8 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.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 - * for the FPU emulator. Clear the flags where required in case called - * from `fpu_disable', to override details obtained from FPU hardware. + * IEEE 754 conformance mode to use. Affects the NaN encoding and the + * ABS.fmt/NEG.fmt execution mode. + */ +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) { + c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY); c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | - MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | - MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) { - c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY; - c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); - } else { - c->options &= ~MIPS_CPU_NAN_2008; + c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008); + + switch (ieee754) { + case STRICT: + if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | + MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | + 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->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. */ @@ -212,6 +295,7 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c) cpu_set_fpu_fcsr_mask(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) c->fpu_msk31 = mips_nofpu_msk31; cpu_set_nofpu_2008(c); + cpu_set_nan_2008(c); cpu_set_nofpu_id(c); } diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index f36a261b275c..c3c234dc0c07 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -13,6 +13,10 @@ #include +/* Whether to accept legacy-NaN and 2008-NaN user binaries. */ +bool mips_use_nan_legacy; +bool mips_use_nan_2008; + /* FPU modes */ enum { FP_FRE, @@ -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; /* - * Determine the NaN personality, reject the binary if no hardware - * support. Also ensure that any interpreter matches the executable. + * Determine the NaN personality, reject the binary if not allowed. + * Also ensure that any interpreter matches the executable. */ if (flags & EF_MIPS_NAN2008) { - if (cpu_has_nan_2008) + if (mips_use_nan_2008) state->nan_2008 = 1; else return -ENOEXEC; } else { - if (cpu_has_nan_legacy) + if (mips_use_nan_legacy) state->nan_2008 = 0; else return -ENOEXEC;