aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2015-01-08 04:32:25 -0500
committerMarkos Chandras <markos.chandras@imgtec.com>2015-02-17 10:37:39 -0500
commit46490b572544fa908be051f7872beb2941e55ede (patch)
tree2f6ffb9c2af7571358238c74514278bcd1897a63
parent6134d94923d03556b4f74a7864759dc333030c98 (diff)
MIPS: kernel: elf: Improve the overall ABI and FPU mode checks
The previous implementation did not cover all possible FPU combinations and it silently allowed ABI incompatible objects to be loaded with the wrong ABI. For example, the previous logic would set the FP_64 ABI as the matching ABI for an FP_XX object combined with an FP_64A object. This was wrong, and the matching ABI should have been FP_64A. The previous logic is now replaced with a new one which determines the appropriate FPU mode to be used rather than the FP ABI. This has the advantage that the entire logic is much simpler since it is the FPU mode we are interested in rather than the FP ABI resulting to code simplifications. This also removes the now obsolete FP32XX_HYBRID_FPRS option. Cc: Matthew Fortune <Matthew.Fortune@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
-rw-r--r--arch/mips/Kconfig.debug13
-rw-r--r--arch/mips/include/asm/elf.h10
-rw-r--r--arch/mips/kernel/elf.c303
3 files changed, 194 insertions, 132 deletions
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 88a9f433f6fc..3a2b775e8458 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -122,17 +122,4 @@ config SPINLOCK_TEST
122 help 122 help
123 Add several files to the debugfs to test spinlock speed. 123 Add several files to the debugfs to test spinlock speed.
124 124
125config FP32XX_HYBRID_FPRS
126 bool "Run FP32 & FPXX code with hybrid FPRs"
127 depends on MIPS_O32_FP64_SUPPORT
128 help
129 The hybrid FPR scheme is normally used only when a program needs to
130 execute a mix of FP32 & FP64A code, since the trapping & emulation
131 that it entails is expensive. When enabled, this option will lead
132 to the kernel running programs which use the FP32 & FPXX FP ABIs
133 using the hybrid FPR scheme, which can be useful for debugging
134 purposes.
135
136 If unsure, say N.
137
138endmenu 125endmenu
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index eb4d95de619c..535f196ffe02 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -417,13 +417,15 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
417struct arch_elf_state { 417struct arch_elf_state {
418 int fp_abi; 418 int fp_abi;
419 int interp_fp_abi; 419 int interp_fp_abi;
420 int overall_abi; 420 int overall_fp_mode;
421}; 421};
422 422
423#define MIPS_ABI_FP_UNKNOWN (-1) /* Unknown FP ABI (kernel internal) */
424
423#define INIT_ARCH_ELF_STATE { \ 425#define INIT_ARCH_ELF_STATE { \
424 .fp_abi = -1, \ 426 .fp_abi = MIPS_ABI_FP_UNKNOWN, \
425 .interp_fp_abi = -1, \ 427 .interp_fp_abi = MIPS_ABI_FP_UNKNOWN, \
426 .overall_abi = -1, \ 428 .overall_fp_mode = -1, \
427} 429}
428 430
429extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, 431extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c
index c92b15df6893..d2c09f6475c5 100644
--- a/arch/mips/kernel/elf.c
+++ b/arch/mips/kernel/elf.c
@@ -11,29 +11,112 @@
11#include <linux/elf.h> 11#include <linux/elf.h>
12#include <linux/sched.h> 12#include <linux/sched.h>
13 13
14/* FPU modes */
14enum { 15enum {
15 FP_ERROR = -1, 16 FP_FRE,
16 FP_DOUBLE_64A = -2, 17 FP_FR0,
18 FP_FR1,
17}; 19};
18 20
21/**
22 * struct mode_req - ABI FPU mode requirements
23 * @single: The program being loaded needs an FPU but it will only issue
24 * single precision instructions meaning that it can execute in
25 * either FR0 or FR1.
26 * @soft: The soft(-float) requirement means that the program being
27 * loaded needs has no FPU dependency at all (i.e. it has no
28 * FPU instructions).
29 * @fr1: The program being loaded depends on FPU being in FR=1 mode.
30 * @frdefault: The program being loaded depends on the default FPU mode.
31 * That is FR0 for O32 and FR1 for N32/N64.
32 * @fre: The program being loaded depends on FPU with FRE=1. This mode is
33 * a bridge which uses FR=1 whilst still being able to maintain
34 * full compatibility with pre-existing code using the O32 FP32
35 * ABI.
36 *
37 * More information about the FP ABIs can be found here:
38 *
39 * https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking#10.4.1._Basic_mode_set-up
40 *
41 */
42
43struct mode_req {
44 bool single;
45 bool soft;
46 bool fr1;
47 bool frdefault;
48 bool fre;
49};
50
51static const struct mode_req fpu_reqs[] = {
52 [MIPS_ABI_FP_ANY] = { true, true, true, true, true },
53 [MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true },
54 [MIPS_ABI_FP_SINGLE] = { true, false, false, false, false },
55 [MIPS_ABI_FP_SOFT] = { false, true, false, false, false },
56 [MIPS_ABI_FP_OLD_64] = { false, false, false, false, false },
57 [MIPS_ABI_FP_XX] = { false, false, true, true, true },
58 [MIPS_ABI_FP_64] = { false, false, true, false, false },
59 [MIPS_ABI_FP_64A] = { false, false, true, false, true }
60};
61
62/*
63 * Mode requirements when .MIPS.abiflags is not present in the ELF.
64 * Not present means that everything is acceptable except FR1.
65 */
66static struct mode_req none_req = { true, true, false, true, true };
67
19int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, 68int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
20 bool is_interp, struct arch_elf_state *state) 69 bool is_interp, struct arch_elf_state *state)
21{ 70{
22 struct elfhdr *ehdr = _ehdr; 71 struct elf32_hdr *ehdr32 = _ehdr;
23 struct elf_phdr *phdr = _phdr; 72 struct elf32_phdr *phdr32 = _phdr;
73 struct elf64_phdr *phdr64 = _phdr;
24 struct mips_elf_abiflags_v0 abiflags; 74 struct mips_elf_abiflags_v0 abiflags;
25 int ret; 75 int ret;
26 76
27 if (config_enabled(CONFIG_64BIT) && 77 /* Lets see if this is an O32 ELF */
28 (ehdr->e_ident[EI_CLASS] != ELFCLASS32)) 78 if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
29 return 0; 79 /* FR = 1 for N32 */
30 if (phdr->p_type != PT_MIPS_ABIFLAGS) 80 if (ehdr32->e_flags & EF_MIPS_ABI2)
31 return 0; 81 state->overall_fp_mode = FP_FR1;
32 if (phdr->p_filesz < sizeof(abiflags)) 82 else
33 return -EINVAL; 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) {
88 /*
89 * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
90 * later if needed
91 */
92 if (is_interp)
93 state->interp_fp_abi = MIPS_ABI_FP_OLD_64;
94 else
95 state->fp_abi = MIPS_ABI_FP_OLD_64;
96 }
97 if (phdr32->p_type != PT_MIPS_ABIFLAGS)
98 return 0;
99
100 if (phdr32->p_filesz < sizeof(abiflags))
101 return -EINVAL;
102
103 ret = kernel_read(elf, phdr32->p_offset,
104 (char *)&abiflags,
105 sizeof(abiflags));
106 } 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)
111 return 0;
112 if (phdr64->p_filesz < sizeof(abiflags))
113 return -EINVAL;
114
115 ret = kernel_read(elf, phdr64->p_offset,
116 (char *)&abiflags,
117 sizeof(abiflags));
118 }
34 119
35 ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags,
36 sizeof(abiflags));
37 if (ret < 0) 120 if (ret < 0)
38 return ret; 121 return ret;
39 if (ret != sizeof(abiflags)) 122 if (ret != sizeof(abiflags))
@@ -48,35 +131,30 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
48 return 0; 131 return 0;
49} 132}
50 133
51static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi) 134static inline unsigned get_fp_abi(int in_abi)
52{ 135{
53 /* If the ABI requirement is provided, simply return that */ 136 /* If the ABI requirement is provided, simply return that */
54 if (in_abi != -1) 137 if (in_abi != MIPS_ABI_FP_UNKNOWN)
55 return in_abi; 138 return in_abi;
56 139
57 /* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */ 140 /* Unknown ABI */
58 if (ehdr->e_flags & EF_MIPS_FP64) 141 return MIPS_ABI_FP_UNKNOWN;
59 return MIPS_ABI_FP_64;
60
61 /* Default to MIPS_ABI_FP_DOUBLE */
62 return MIPS_ABI_FP_DOUBLE;
63} 142}
64 143
65int arch_check_elf(void *_ehdr, bool has_interpreter, 144int arch_check_elf(void *_ehdr, bool has_interpreter,
66 struct arch_elf_state *state) 145 struct arch_elf_state *state)
67{ 146{
68 struct elfhdr *ehdr = _ehdr; 147 struct elf32_hdr *ehdr = _ehdr;
69 unsigned fp_abi, interp_fp_abi, abi0, abi1; 148 struct mode_req prog_req, interp_req;
149 int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
70 150
71 /* Ignore non-O32 binaries */ 151 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
72 if (config_enabled(CONFIG_64BIT) &&
73 (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
74 return 0; 152 return 0;
75 153
76 fp_abi = get_fp_abi(ehdr, state->fp_abi); 154 fp_abi = get_fp_abi(state->fp_abi);
77 155
78 if (has_interpreter) { 156 if (has_interpreter) {
79 interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi); 157 interp_fp_abi = get_fp_abi(state->interp_fp_abi);
80 158
81 abi0 = min(fp_abi, interp_fp_abi); 159 abi0 = min(fp_abi, interp_fp_abi);
82 abi1 = max(fp_abi, interp_fp_abi); 160 abi1 = max(fp_abi, interp_fp_abi);
@@ -84,108 +162,103 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
84 abi0 = abi1 = fp_abi; 162 abi0 = abi1 = fp_abi;
85 } 163 }
86 164
87 state->overall_abi = FP_ERROR; 165 /* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */
88 166 max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
89 if (abi0 == abi1) { 167 (!(ehdr->e_flags & EF_MIPS_ABI2))) ?
90 state->overall_abi = abi0; 168 MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT;
91 } else if (abi0 == MIPS_ABI_FP_ANY) {
92 state->overall_abi = abi1;
93 } else if (abi0 == MIPS_ABI_FP_DOUBLE) {
94 switch (abi1) {
95 case MIPS_ABI_FP_XX:
96 state->overall_abi = MIPS_ABI_FP_DOUBLE;
97 break;
98
99 case MIPS_ABI_FP_64A:
100 state->overall_abi = FP_DOUBLE_64A;
101 break;
102 }
103 } else if (abi0 == MIPS_ABI_FP_SINGLE ||
104 abi0 == MIPS_ABI_FP_SOFT) {
105 /* Cannot link with other ABIs */
106 } else if (abi0 == MIPS_ABI_FP_OLD_64) {
107 switch (abi1) {
108 case MIPS_ABI_FP_XX:
109 case MIPS_ABI_FP_64:
110 case MIPS_ABI_FP_64A:
111 state->overall_abi = MIPS_ABI_FP_64;
112 break;
113 }
114 } else if (abi0 == MIPS_ABI_FP_XX ||
115 abi0 == MIPS_ABI_FP_64 ||
116 abi0 == MIPS_ABI_FP_64A) {
117 state->overall_abi = MIPS_ABI_FP_64;
118 }
119 169
120 switch (state->overall_abi) { 170 if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||
121 case MIPS_ABI_FP_64: 171 (abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN))
122 case MIPS_ABI_FP_64A: 172 return -ELIBBAD;
123 case FP_DOUBLE_64A: 173
124 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) 174 /* It's time to determine the FPU mode requirements */
125 return -ELIBBAD; 175 prog_req = (abi0 == MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi0];
126 break; 176 interp_req = (abi1 == MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi1];
127 177
128 case FP_ERROR: 178 /*
179 * Check whether the program's and interp's ABIs have a matching FPU
180 * mode requirement.
181 */
182 prog_req.single = interp_req.single && prog_req.single;
183 prog_req.soft = interp_req.soft && prog_req.soft;
184 prog_req.fr1 = interp_req.fr1 && prog_req.fr1;
185 prog_req.frdefault = interp_req.frdefault && prog_req.frdefault;
186 prog_req.fre = interp_req.fre && prog_req.fre;
187
188 /*
189 * Determine the desired FPU mode
190 *
191 * Decision making:
192 *
193 * - We want FR_FRE if FRE=1 and both FR=1 and FR=0 are false. This
194 * means that we have a combination of program and interpreter
195 * that inherently require the hybrid FP mode.
196 * - If FR1 and FRDEFAULT is true, that means we hit the any-abi or
197 * fpxx case. This is because, in any-ABI (or no-ABI) we have no FPU
198 * instructions so we don't care about the mode. We will simply use
199 * the one preferred by the hardware. In fpxx case, that ABI can
200 * handle both FR=1 and FR=0, so, again, we simply choose the one
201 * preferred by the hardware. Next, if we only use single-precision
202 * FPU instructions, and the default ABI FPU mode is not good
203 * (ie single + any ABI combination), we set again the FPU mode to the
204 * one is preferred by the hardware. Next, if we know that the code
205 * will only use single-precision instructions, shown by single being
206 * true but frdefault being false, then we again set the FPU mode to
207 * the one that is preferred by the hardware.
208 * - We want FP_FR1 if that's the only matching mode and the default one
209 * is not good.
210 * - Return with -ELIBADD if we can't find a matching FPU mode.
211 */
212 if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1)
213 state->overall_fp_mode = FP_FRE;
214 else if ((prog_req.fr1 && prog_req.frdefault) ||
215 (prog_req.single && !prog_req.frdefault))
216 /* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */
217 state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) &&
218 cpu_has_mips_r2_r6) ?
219 FP_FR1 : FP_FR0;
220 else if (prog_req.fr1)
221 state->overall_fp_mode = FP_FR1;
222 else if (!prog_req.fre && !prog_req.frdefault &&
223 !prog_req.fr1 && !prog_req.single && !prog_req.soft)
129 return -ELIBBAD; 224 return -ELIBBAD;
130 }
131 225
132 return 0; 226 return 0;
133} 227}
134 228
135void mips_set_personality_fp(struct arch_elf_state *state) 229static inline void set_thread_fp_mode(int hybrid, int regs32)
136{ 230{
137 if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) { 231 if (hybrid)
138 /* 232 set_thread_flag(TIF_HYBRID_FPREGS);
139 * Use hybrid FPRs for all code which can correctly execute 233 else
140 * with that mode.
141 */
142 switch (state->overall_abi) {
143 case MIPS_ABI_FP_DOUBLE:
144 case MIPS_ABI_FP_SINGLE:
145 case MIPS_ABI_FP_SOFT:
146 case MIPS_ABI_FP_XX:
147 case MIPS_ABI_FP_ANY:
148 /* FR=1, FRE=1 */
149 clear_thread_flag(TIF_32BIT_FPREGS);
150 set_thread_flag(TIF_HYBRID_FPREGS);
151 return;
152 }
153 }
154
155 switch (state->overall_abi) {
156 case MIPS_ABI_FP_DOUBLE:
157 case MIPS_ABI_FP_SINGLE:
158 case MIPS_ABI_FP_SOFT:
159 /* FR=0 */
160 set_thread_flag(TIF_32BIT_FPREGS);
161 clear_thread_flag(TIF_HYBRID_FPREGS); 234 clear_thread_flag(TIF_HYBRID_FPREGS);
162 break; 235 if (regs32)
163 236 set_thread_flag(TIF_32BIT_FPREGS);
164 case FP_DOUBLE_64A: 237 else
165 /* FR=1, FRE=1 */
166 clear_thread_flag(TIF_32BIT_FPREGS); 238 clear_thread_flag(TIF_32BIT_FPREGS);
167 set_thread_flag(TIF_HYBRID_FPREGS); 239}
168 break;
169 240
170 case MIPS_ABI_FP_64: 241void mips_set_personality_fp(struct arch_elf_state *state)
171 case MIPS_ABI_FP_64A: 242{
172 /* FR=1, FRE=0 */ 243 /*
173 clear_thread_flag(TIF_32BIT_FPREGS); 244 * This function is only ever called for O32 ELFs so we should
174 clear_thread_flag(TIF_HYBRID_FPREGS); 245 * not be worried about N32/N64 binaries.
175 break; 246 */
176 247
177 case MIPS_ABI_FP_XX: 248 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
178 case MIPS_ABI_FP_ANY: 249 return;
179 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
180 set_thread_flag(TIF_32BIT_FPREGS);
181 else
182 clear_thread_flag(TIF_32BIT_FPREGS);
183 250
184 clear_thread_flag(TIF_HYBRID_FPREGS); 251 switch (state->overall_fp_mode) {
252 case FP_FRE:
253 set_thread_fp_mode(1, 0);
254 break;
255 case FP_FR0:
256 set_thread_fp_mode(0, 1);
257 break;
258 case FP_FR1:
259 set_thread_fp_mode(0, 0);
185 break; 260 break;
186
187 default: 261 default:
188 case FP_ERROR:
189 BUG(); 262 BUG();
190 } 263 }
191} 264}