diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/include/asm/elf.h | 4 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 105 | ||||
-rw-r--r-- | arch/mips/kernel/elf.c | 12 |
3 files changed, 107 insertions, 14 deletions
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,26 +151,109 @@ 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. */ static void cpu_set_nofpu_id(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_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 <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 */ 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; |