]> git.karo-electronics.de Git - mv-sheeva.git/blob - arch/blackfin/kernel/module.c
Blackfin: convert malloc()/memset() to zalloc() in module code
[mv-sheeva.git] / arch / blackfin / kernel / module.c
1 /*
2  * File:         arch/blackfin/kernel/module.c
3  * Based on:
4  * Author:
5  *
6  * Created:
7  * Description:
8  *
9  * Modified:
10  *               Copyright 2004-2006 Analog Devices Inc.
11  *
12  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see the file COPYING, or write
26  * to the Free Software Foundation, Inc.,
27  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29
30 #define pr_fmt(fmt) "module %s: " fmt
31
32 #include <linux/moduleloader.h>
33 #include <linux/elf.h>
34 #include <linux/vmalloc.h>
35 #include <linux/fs.h>
36 #include <linux/string.h>
37 #include <linux/kernel.h>
38 #include <asm/dma.h>
39 #include <asm/cacheflush.h>
40
41 void *module_alloc(unsigned long size)
42 {
43         if (size == 0)
44                 return NULL;
45         return vmalloc(size);
46 }
47
48 /* Free memory returned from module_alloc */
49 void module_free(struct module *mod, void *module_region)
50 {
51         vfree(module_region);
52 }
53
54 /* Transfer the section to the L1 memory */
55 int
56 module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
57                           char *secstrings, struct module *mod)
58 {
59         /*
60          * XXX: sechdrs are vmalloced in kernel/module.c
61          * and would be vfreed just after module is loaded,
62          * so we hack to keep the only information we needed
63          * in mod->arch to correctly free L1 I/D sram later.
64          * NOTE: this breaks the semantic of mod->arch structure.
65          */
66         Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
67         void *dest = NULL;
68
69         for (s = sechdrs; s < sechdrs_end; ++s) {
70                 if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
71                     ((strcmp(".text", secstrings + s->sh_name) == 0) &&
72                      (hdr->e_flags & EF_BFIN_CODE_IN_L1) && (s->sh_size > 0))) {
73                         dest = l1_inst_sram_alloc(s->sh_size);
74                         mod->arch.text_l1 = dest;
75                         if (dest == NULL) {
76                                 pr_err("L1 inst memory allocation failed\n",
77                                         mod->name);
78                                 return -1;
79                         }
80                         dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
81                         s->sh_flags &= ~SHF_ALLOC;
82                         s->sh_addr = (unsigned long)dest;
83                 }
84                 if ((strcmp(".l1.data", secstrings + s->sh_name) == 0) ||
85                     ((strcmp(".data", secstrings + s->sh_name) == 0) &&
86                      (hdr->e_flags & EF_BFIN_DATA_IN_L1) && (s->sh_size > 0))) {
87                         dest = l1_data_sram_alloc(s->sh_size);
88                         mod->arch.data_a_l1 = dest;
89                         if (dest == NULL) {
90                                 pr_err("L1 data memory allocation failed\n",
91                                         mod->name);
92                                 return -1;
93                         }
94                         memcpy(dest, (void *)s->sh_addr, s->sh_size);
95                         s->sh_flags &= ~SHF_ALLOC;
96                         s->sh_addr = (unsigned long)dest;
97                 }
98                 if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
99                     ((strcmp(".bss", secstrings + s->sh_name) == 0) &&
100                      (hdr->e_flags & EF_BFIN_DATA_IN_L1) && (s->sh_size > 0))) {
101                         dest = l1_data_sram_zalloc(s->sh_size);
102                         mod->arch.bss_a_l1 = dest;
103                         if (dest == NULL) {
104                                 pr_err("L1 data memory allocation failed\n",
105                                         mod->name);
106                                 return -1;
107                         }
108                         s->sh_flags &= ~SHF_ALLOC;
109                         s->sh_addr = (unsigned long)dest;
110                 }
111                 if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
112                         dest = l1_data_B_sram_alloc(s->sh_size);
113                         mod->arch.data_b_l1 = dest;
114                         if (dest == NULL) {
115                                 pr_err("L1 data memory allocation failed\n",
116                                         mod->name);
117                                 return -1;
118                         }
119                         memcpy(dest, (void *)s->sh_addr, s->sh_size);
120                         s->sh_flags &= ~SHF_ALLOC;
121                         s->sh_addr = (unsigned long)dest;
122                 }
123                 if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
124                         dest = l1_data_B_sram_alloc(s->sh_size);
125                         mod->arch.bss_b_l1 = dest;
126                         if (dest == NULL) {
127                                 pr_err("L1 data memory allocation failed\n",
128                                         mod->name);
129                                 return -1;
130                         }
131                         memset(dest, 0, s->sh_size);
132                         s->sh_flags &= ~SHF_ALLOC;
133                         s->sh_addr = (unsigned long)dest;
134                 }
135                 if ((strcmp(".l2.text", secstrings + s->sh_name) == 0) ||
136                     ((strcmp(".text", secstrings + s->sh_name) == 0) &&
137                      (hdr->e_flags & EF_BFIN_CODE_IN_L2) && (s->sh_size > 0))) {
138                         dest = l2_sram_alloc(s->sh_size);
139                         mod->arch.text_l2 = dest;
140                         if (dest == NULL) {
141                                 pr_err("L2 SRAM allocation failed\n",
142                                         mod->name);
143                                 return -1;
144                         }
145                         memcpy(dest, (void *)s->sh_addr, s->sh_size);
146                         s->sh_flags &= ~SHF_ALLOC;
147                         s->sh_addr = (unsigned long)dest;
148                 }
149                 if ((strcmp(".l2.data", secstrings + s->sh_name) == 0) ||
150                     ((strcmp(".data", secstrings + s->sh_name) == 0) &&
151                      (hdr->e_flags & EF_BFIN_DATA_IN_L2) && (s->sh_size > 0))) {
152                         dest = l2_sram_alloc(s->sh_size);
153                         mod->arch.data_l2 = dest;
154                         if (dest == NULL) {
155                                 pr_err("L2 SRAM allocation failed\n",
156                                         mod->name);
157                                 return -1;
158                         }
159                         memcpy(dest, (void *)s->sh_addr, s->sh_size);
160                         s->sh_flags &= ~SHF_ALLOC;
161                         s->sh_addr = (unsigned long)dest;
162                 }
163                 if (strcmp(".l2.bss", secstrings + s->sh_name) == 0 ||
164                     ((strcmp(".bss", secstrings + s->sh_name) == 0) &&
165                      (hdr->e_flags & EF_BFIN_DATA_IN_L2) && (s->sh_size > 0))) {
166                         dest = l2_sram_zalloc(s->sh_size);
167                         mod->arch.bss_l2 = dest;
168                         if (dest == NULL) {
169                                 pr_err("L2 SRAM allocation failed\n",
170                                         mod->name);
171                                 return -1;
172                         }
173                         s->sh_flags &= ~SHF_ALLOC;
174                         s->sh_addr = (unsigned long)dest;
175                 }
176         }
177         return 0;
178 }
179
180 int
181 apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
182                unsigned int symindex, unsigned int relsec, struct module *me)
183 {
184         pr_err(".rel unsupported\n", me->name);
185         return -ENOEXEC;
186 }
187
188 /*************************************************************************/
189 /* FUNCTION : apply_relocate_add                                         */
190 /* ABSTRACT : Blackfin specific relocation handling for the loadable     */
191 /*            modules. Modules are expected to be .o files.              */
192 /*            Arithmetic relocations are handled.                        */
193 /*            We do not expect LSETUP to be split and hence is not       */
194 /*            handled.                                                   */
195 /*            R_BFIN_BYTE and R_BFIN_BYTE2 are also not handled as the   */
196 /*            gas does not generate it.                                  */
197 /*************************************************************************/
198 int
199 apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
200                    unsigned int symindex, unsigned int relsec,
201                    struct module *mod)
202 {
203         unsigned int i;
204         unsigned short tmp;
205         Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
206         Elf32_Sym *sym;
207         uint32_t *location32;
208         uint16_t *location16;
209         uint32_t value;
210
211         pr_debug("applying relocate section %u to %u\n", mod->name,
212                 relsec, sechdrs[relsec].sh_info);
213         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
214                 /* This is where to make the change */
215                 location16 =
216                     (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
217                                   rel[i].r_offset);
218                 location32 = (uint32_t *) location16;
219                 /* This is the symbol it is referring to. Note that all
220                    undefined symbols have been resolved. */
221                 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
222                     + ELF32_R_SYM(rel[i].r_info);
223                 value = sym->st_value;
224                 value += rel[i].r_addend;
225
226 #ifdef CONFIG_SMP
227                 if ((unsigned long)location16 >= COREB_L1_DATA_A_START) {
228                         pr_err("cannot relocate in L1: %u (SMP kernel)",
229                                 mod->name, ELF32_R_TYPE(rel[i].r_info));
230                         return -ENOEXEC;
231                 }
232 #endif
233
234                 pr_debug("location is %lx, value is %x type is %d\n",
235                         mod->name, (unsigned long)location32, value,
236                         ELF32_R_TYPE(rel[i].r_info));
237
238                 switch (ELF32_R_TYPE(rel[i].r_info)) {
239
240                 case R_BFIN_LUIMM16:
241                         tmp = (value & 0xffff);
242                         if ((unsigned long)location16 >= L1_CODE_START) {
243                                 dma_memcpy(location16, &tmp, 2);
244                         } else
245                                 *location16 = tmp;
246                         break;
247                 case R_BFIN_HUIMM16:
248                         tmp = ((value >> 16) & 0xffff);
249                         if ((unsigned long)location16 >= L1_CODE_START) {
250                                 dma_memcpy(location16, &tmp, 2);
251                         } else
252                                 *location16 = tmp;
253                         break;
254                 case R_BFIN_RIMM16:
255                         *location16 = (value & 0xffff);
256                         break;
257                 case R_BFIN_BYTE4_DATA:
258                         *location32 = value;
259                         break;
260                 case R_BFIN_PCREL24:
261                 case R_BFIN_PCREL24_JUMP_L:
262                 case R_BFIN_PCREL12_JUMP:
263                 case R_BFIN_PCREL12_JUMP_S:
264                 case R_BFIN_PCREL10:
265                         pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
266                                 mod->name, ELF32_R_TYPE(rel[i].r_info));
267                         return -ENOEXEC;
268                 default:
269                         pr_err("unknown relocation: %u\n", mod->name,
270                                 ELF32_R_TYPE(rel[i].r_info));
271                         return -ENOEXEC;
272                 }
273         }
274         return 0;
275 }
276
277 int
278 module_finalize(const Elf_Ehdr * hdr,
279                 const Elf_Shdr * sechdrs, struct module *mod)
280 {
281         unsigned int i, strindex = 0, symindex = 0;
282         char *secstrings;
283         long err = 0;
284
285         secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
286
287         for (i = 1; i < hdr->e_shnum; i++) {
288                 /* Internal symbols and strings. */
289                 if (sechdrs[i].sh_type == SHT_SYMTAB) {
290                         symindex = i;
291                         strindex = sechdrs[i].sh_link;
292                 }
293         }
294
295         for (i = 1; i < hdr->e_shnum; i++) {
296                 const char *strtab = (char *)sechdrs[strindex].sh_addr;
297                 unsigned int info = sechdrs[i].sh_info;
298
299                 /* Not a valid relocation section? */
300                 if (info >= hdr->e_shnum)
301                         continue;
302
303                 if ((sechdrs[i].sh_type == SHT_RELA) &&
304                     ((strcmp(".rela.l2.text", secstrings + sechdrs[i].sh_name) == 0) ||
305                     (strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) ||
306                     ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
307                         (hdr->e_flags & (EF_BFIN_CODE_IN_L1|EF_BFIN_CODE_IN_L2))))) {
308                         err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
309                                            symindex, i, mod);
310                         if (err < 0)
311                                 return -ENOEXEC;
312                 }
313         }
314         return 0;
315 }
316
317 void module_arch_cleanup(struct module *mod)
318 {
319         l1_inst_sram_free(mod->arch.text_l1);
320         l1_data_A_sram_free(mod->arch.data_a_l1);
321         l1_data_A_sram_free(mod->arch.bss_a_l1);
322         l1_data_B_sram_free(mod->arch.data_b_l1);
323         l1_data_B_sram_free(mod->arch.bss_b_l1);
324         l2_sram_free(mod->arch.text_l2);
325         l2_sram_free(mod->arch.data_l2);
326         l2_sram_free(mod->arch.bss_l2);
327 }