Merge branches 'pm-cpufreq', 'pm-cpuidle', 'pm-devfreq', 'pm-opp' and 'pm-tools'
[linux-drm-fsl-dcu.git] / arch / mips / kernel / elf.c
1 /*
2  * Copyright (C) 2014 Imagination Technologies
3  * Author: Paul Burton <paul.burton@imgtec.com>
4  *
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.
9  */
10
11 #include <linux/elf.h>
12 #include <linux/sched.h>
13
14 enum {
15         FP_ERROR = -1,
16         FP_DOUBLE_64A = -2,
17 };
18
19 int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
20                      bool is_interp, struct arch_elf_state *state)
21 {
22         struct elf32_hdr *ehdr = _ehdr;
23         struct elf32_phdr *phdr = _phdr;
24         struct mips_elf_abiflags_v0 abiflags;
25         int ret;
26
27         if (config_enabled(CONFIG_64BIT) &&
28             (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
29                 return 0;
30         if (phdr->p_type != PT_MIPS_ABIFLAGS)
31                 return 0;
32         if (phdr->p_filesz < sizeof(abiflags))
33                 return -EINVAL;
34
35         ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags,
36                           sizeof(abiflags));
37         if (ret < 0)
38                 return ret;
39         if (ret != sizeof(abiflags))
40                 return -EIO;
41
42         /* Record the required FP ABIs for use by mips_check_elf */
43         if (is_interp)
44                 state->interp_fp_abi = abiflags.fp_abi;
45         else
46                 state->fp_abi = abiflags.fp_abi;
47
48         return 0;
49 }
50
51 static inline unsigned get_fp_abi(struct elf32_hdr *ehdr, int in_abi)
52 {
53         /* If the ABI requirement is provided, simply return that */
54         if (in_abi != -1)
55                 return in_abi;
56
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;
60
61         /* Default to MIPS_ABI_FP_DOUBLE */
62         return MIPS_ABI_FP_DOUBLE;
63 }
64
65 int arch_check_elf(void *_ehdr, bool has_interpreter,
66                    struct arch_elf_state *state)
67 {
68         struct elf32_hdr *ehdr = _ehdr;
69         unsigned fp_abi, interp_fp_abi, abi0, abi1;
70
71         /* Ignore non-O32 binaries */
72         if (config_enabled(CONFIG_64BIT) &&
73             (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
74                 return 0;
75
76         fp_abi = get_fp_abi(ehdr, state->fp_abi);
77
78         if (has_interpreter) {
79                 interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi);
80
81                 abi0 = min(fp_abi, interp_fp_abi);
82                 abi1 = max(fp_abi, interp_fp_abi);
83         } else {
84                 abi0 = abi1 = fp_abi;
85         }
86
87         state->overall_abi = FP_ERROR;
88
89         if (abi0 == abi1) {
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) {
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
120         switch (state->overall_abi) {
121         case MIPS_ABI_FP_64:
122         case MIPS_ABI_FP_64A:
123         case FP_DOUBLE_64A:
124                 if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
125                         return -ELIBBAD;
126                 break;
127
128         case FP_ERROR:
129                 return -ELIBBAD;
130         }
131
132         return 0;
133 }
134
135 void mips_set_personality_fp(struct arch_elf_state *state)
136 {
137         if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) {
138                 /*
139                  * Use hybrid FPRs for all code which can correctly execute
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);
162                 break;
163
164         case FP_DOUBLE_64A:
165                 /* FR=1, FRE=1 */
166                 clear_thread_flag(TIF_32BIT_FPREGS);
167                 set_thread_flag(TIF_HYBRID_FPREGS);
168                 break;
169
170         case MIPS_ABI_FP_64:
171         case MIPS_ABI_FP_64A:
172                 /* FR=1, FRE=0 */
173                 clear_thread_flag(TIF_32BIT_FPREGS);
174                 clear_thread_flag(TIF_HYBRID_FPREGS);
175                 break;
176
177         case MIPS_ABI_FP_XX:
178         case MIPS_ABI_FP_ANY:
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
184                 clear_thread_flag(TIF_HYBRID_FPREGS);
185                 break;
186
187         default:
188         case FP_ERROR:
189                 BUG();
190         }
191 }