aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2015-05-06 06:52:32 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-05-12 12:54:05 -0400
commit620b155034570f577470cf5309f741bac6a6e32b (patch)
treec3264695ac23aee0873484bf466f9ba7bc13f7f3 /arch/mips
parentcafb45b2562baa57cb58bef0636c073705954cc4 (diff)
MIPS: fix FP mode selection in lieu of .MIPS.abiflags data
Commit 46490b572544 ("MIPS: kernel: elf: Improve the overall ABI and FPU mode checks") reworked the ELF FP ABI mode selection logic, but when CONFIG_MIPS_O32_FP64_SUPPORT is enabled it breaks the use of binaries which have no PT_MIPS_ABIFLAGS program header & associated .MIPS.abiflags section. A default mode is selected based upon whether the ELF contains MIPS32 or MIPS64 code, but that selection is made in arch_elf_pt_proc. arch_elf_pt_proc only executes when a PT_MIPS_ABIFLAGS program header is found. If one is not found then arch_elf_pt_proc is never called, and no default overall_fp_mode value is selected. When arch_check_elf is called, both abi0 & abi1 are MIPS_ABI_FP_UNKNOWN which leads to both prog_req & interp_req being set to none_req. none_req matches none of the conditions for mode selection at the end of arch_check_elf, so overall_fp_mode is left untouched. Finally once mips_set_personality_fp is called the BUG() in the default case is then hit & the kernel likely panics. Fix this by moving the selection of a default overall mode to the start of arch_check_elf, which runs once per ELF executed regardless of whether it has a PT_MIPS_ABIFLAGS program header. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Matthew Fortune <matthew.fortune@imgtec.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # v4.0+ Patchwork: http://patchwork.linux-mips.org/patch/9978/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/elf.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c
index be4899f3c393..4a4d9e067c89 100644
--- a/arch/mips/kernel/elf.c
+++ b/arch/mips/kernel/elf.c
@@ -76,14 +76,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
76 76
77 /* Lets see if this is an O32 ELF */ 77 /* Lets see if this is an O32 ELF */
78 if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) { 78 if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
79 /* FR = 1 for N32 */
80 if (ehdr32->e_flags & EF_MIPS_ABI2)
81 state->overall_fp_mode = FP_FR1;
82 else
83 /* Set a good default FPU mode for O32 */
84 state->overall_fp_mode = cpu_has_mips_r6 ?
85 FP_FRE : FP_FR0;
86
87 if (ehdr32->e_flags & EF_MIPS_FP64) { 79 if (ehdr32->e_flags & EF_MIPS_FP64) {
88 /* 80 /*
89 * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it 81 * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
@@ -104,9 +96,6 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
104 (char *)&abiflags, 96 (char *)&abiflags,
105 sizeof(abiflags)); 97 sizeof(abiflags));
106 } else { 98 } else {
107 /* FR=1 is really the only option for 64-bit */
108 state->overall_fp_mode = FP_FR1;
109
110 if (phdr64->p_type != PT_MIPS_ABIFLAGS) 99 if (phdr64->p_type != PT_MIPS_ABIFLAGS)
111 return 0; 100 return 0;
112 if (phdr64->p_filesz < sizeof(abiflags)) 101 if (phdr64->p_filesz < sizeof(abiflags))
@@ -137,6 +126,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
137 struct elf32_hdr *ehdr = _ehdr; 126 struct elf32_hdr *ehdr = _ehdr;
138 struct mode_req prog_req, interp_req; 127 struct mode_req prog_req, interp_req;
139 int fp_abi, interp_fp_abi, abi0, abi1, max_abi; 128 int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
129 bool is_mips64;
140 130
141 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) 131 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
142 return 0; 132 return 0;
@@ -152,10 +142,22 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
152 abi0 = abi1 = fp_abi; 142 abi0 = abi1 = fp_abi;
153 } 143 }
154 144
155 /* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */ 145 is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
156 max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) && 146 (ehdr->e_flags & EF_MIPS_ABI2);
157 (!(ehdr->e_flags & EF_MIPS_ABI2))) ? 147
158 MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT; 148 if (is_mips64) {
149 /* MIPS64 code always uses FR=1, thus the default is easy */
150 state->overall_fp_mode = FP_FR1;
151
152 /* Disallow access to the various FPXX & FP64 ABIs */
153 max_abi = MIPS_ABI_FP_SOFT;
154 } else {
155 /* Default to a mode capable of running code expecting FR=0 */
156 state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
157
158 /* Allow all ABIs we know about */
159 max_abi = MIPS_ABI_FP_64A;
160 }
159 161
160 if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) || 162 if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||
161 (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN)) 163 (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN))