2 * Copyright (C) 2014 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
11 #include <linux/elf.h>
12 #include <linux/sched.h>
19 int arch_elf_pt_proc(void *_ehdr
, void *_phdr
, struct file
*elf
,
20 bool is_interp
, struct arch_elf_state
*state
)
22 struct elfhdr
*ehdr
= _ehdr
;
23 struct elf_phdr
*phdr
= _phdr
;
24 struct mips_elf_abiflags_v0 abiflags
;
27 if (config_enabled(CONFIG_64BIT
) &&
28 (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS32
))
30 if (phdr
->p_type
!= PT_MIPS_ABIFLAGS
)
32 if (phdr
->p_filesz
< sizeof(abiflags
))
35 ret
= kernel_read(elf
, phdr
->p_offset
, (char *)&abiflags
,
39 if (ret
!= sizeof(abiflags
))
42 /* Record the required FP ABIs for use by mips_check_elf */
44 state
->interp_fp_abi
= abiflags
.fp_abi
;
46 state
->fp_abi
= abiflags
.fp_abi
;
51 static inline unsigned get_fp_abi(struct elfhdr
*ehdr
, int in_abi
)
53 /* If the ABI requirement is provided, simply return that */
57 /* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */
58 if (ehdr
->e_flags
& EF_MIPS_FP64
)
59 return MIPS_ABI_FP_64
;
61 /* Default to MIPS_ABI_FP_DOUBLE */
62 return MIPS_ABI_FP_DOUBLE
;
65 int arch_check_elf(void *_ehdr
, bool has_interpreter
,
66 struct arch_elf_state
*state
)
68 struct elfhdr
*ehdr
= _ehdr
;
69 unsigned fp_abi
, interp_fp_abi
, abi0
, abi1
;
71 /* Ignore non-O32 binaries */
72 if (config_enabled(CONFIG_64BIT
) &&
73 (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS32
))
76 fp_abi
= get_fp_abi(ehdr
, state
->fp_abi
);
78 if (has_interpreter
) {
79 interp_fp_abi
= get_fp_abi(ehdr
, state
->interp_fp_abi
);
81 abi0
= min(fp_abi
, interp_fp_abi
);
82 abi1
= max(fp_abi
, interp_fp_abi
);
87 state
->overall_abi
= FP_ERROR
;
90 state
->overall_abi
= abi0
;
91 } else if (abi0
== MIPS_ABI_FP_ANY
) {
92 state
->overall_abi
= abi1
;
93 } else if (abi0
== MIPS_ABI_FP_DOUBLE
) {
96 state
->overall_abi
= MIPS_ABI_FP_DOUBLE
;
100 state
->overall_abi
= FP_DOUBLE_64A
;
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
) {
110 case MIPS_ABI_FP_64A
:
111 state
->overall_abi
= MIPS_ABI_FP_64
;
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
;
120 switch (state
->overall_abi
) {
122 case MIPS_ABI_FP_64A
:
124 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT
))
135 void mips_set_personality_fp(struct arch_elf_state
*state
)
137 if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS
)) {
139 * Use hybrid FPRs for all code which can correctly execute
142 switch (state
->overall_abi
) {
143 case MIPS_ABI_FP_DOUBLE
:
144 case MIPS_ABI_FP_SINGLE
:
145 case MIPS_ABI_FP_SOFT
:
147 case MIPS_ABI_FP_ANY
:
149 clear_thread_flag(TIF_32BIT_FPREGS
);
150 set_thread_flag(TIF_HYBRID_FPREGS
);
155 switch (state
->overall_abi
) {
156 case MIPS_ABI_FP_DOUBLE
:
157 case MIPS_ABI_FP_SINGLE
:
158 case MIPS_ABI_FP_SOFT
:
160 set_thread_flag(TIF_32BIT_FPREGS
);
161 clear_thread_flag(TIF_HYBRID_FPREGS
);
166 clear_thread_flag(TIF_32BIT_FPREGS
);
167 set_thread_flag(TIF_HYBRID_FPREGS
);
171 case MIPS_ABI_FP_64A
:
173 clear_thread_flag(TIF_32BIT_FPREGS
);
174 clear_thread_flag(TIF_HYBRID_FPREGS
);
178 case MIPS_ABI_FP_ANY
:
179 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT
))
180 set_thread_flag(TIF_32BIT_FPREGS
);
182 clear_thread_flag(TIF_32BIT_FPREGS
);
184 clear_thread_flag(TIF_HYBRID_FPREGS
);