aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/module.c
diff options
context:
space:
mode:
authorBryan Wu <bryan.wu@analog.com>2007-05-06 17:50:22 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:58 -0400
commit1394f03221790a988afc3e4b3cb79f2e477246a9 (patch)
tree2c1963c9a4f2d84a5e021307fde240c5d567cf70 /arch/blackfin/kernel/module.c
parent73243284463a761e04d69d22c7516b2be7de096c (diff)
blackfin architecture
This adds support for the Analog Devices Blackfin processor architecture, and currently supports the BF533, BF532, BF531, BF537, BF536, BF534, and BF561 (Dual Core) devices, with a variety of development platforms including those avaliable from Analog Devices (BF533-EZKit, BF533-STAMP, BF537-STAMP, BF561-EZKIT), and Bluetechnix! Tinyboards. The Blackfin architecture was jointly developed by Intel and Analog Devices Inc. (ADI) as the Micro Signal Architecture (MSA) core and introduced it in December of 2000. Since then ADI has put this core into its Blackfin processor family of devices. The Blackfin core has the advantages of a clean, orthogonal,RISC-like microprocessor instruction set. It combines a dual-MAC (Multiply/Accumulate), state-of-the-art signal processing engine and single-instruction, multiple-data (SIMD) multimedia capabilities into a single instruction-set architecture. The Blackfin architecture, including the instruction set, is described by the ADSP-BF53x/BF56x Blackfin Processor Programming Reference http://blackfin.uclinux.org/gf/download/frsrelease/29/2549/Blackfin_PRM.pdf The Blackfin processor is already supported by major releases of gcc, and there are binary and source rpms/tarballs for many architectures at: http://blackfin.uclinux.org/gf/project/toolchain/frs There is complete documentation, including "getting started" guides available at: http://docs.blackfin.uclinux.org/ which provides links to the sources and patches you will need in order to set up a cross-compiling environment for bfin-linux-uclibc This patch, as well as the other patches (toolchain, distribution, uClibc) are actively supported by Analog Devices Inc, at: http://blackfin.uclinux.org/ We have tested this on LTP, and our test plan (including pass/fails) can be found at: http://docs.blackfin.uclinux.org/doku.php?id=testing_the_linux_kernel [m.kozlowski@tuxland.pl: balance parenthesis in blackfin header files] Signed-off-by: Bryan Wu <bryan.wu@analog.com> Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Aubrey Li <aubrey.li@analog.com> Signed-off-by: Jie Zhang <jie.zhang@analog.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/blackfin/kernel/module.c')
-rw-r--r--arch/blackfin/kernel/module.c429
1 files changed, 429 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
new file mode 100644
index 00000000000..372f756f1ad
--- /dev/null
+++ b/arch/blackfin/kernel/module.c
@@ -0,0 +1,429 @@
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
31#include <linux/moduleloader.h>
32#include <linux/elf.h>
33#include <linux/vmalloc.h>
34#include <linux/fs.h>
35#include <linux/string.h>
36#include <linux/kernel.h>
37#include <asm/dma.h>
38#include <asm/cacheflush.h>
39
40/*
41 * handle arithmetic relocations.
42 * See binutils/bfd/elf32-bfin.c for more details
43 */
44#define RELOC_STACK_SIZE 100
45static uint32_t reloc_stack[RELOC_STACK_SIZE];
46static unsigned int reloc_stack_tos;
47
48#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
49
50static void reloc_stack_push(uint32_t value)
51{
52 reloc_stack[reloc_stack_tos++] = value;
53}
54
55static uint32_t reloc_stack_pop(void)
56{
57 return reloc_stack[--reloc_stack_tos];
58}
59
60static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
61{
62 uint32_t value;
63
64 switch (oper) {
65 case R_add:
66 value = reloc_stack[reloc_stack_tos - 2] +
67 reloc_stack[reloc_stack_tos - 1];
68 reloc_stack_tos -= 2;
69 break;
70 case R_sub:
71 value = reloc_stack[reloc_stack_tos - 2] -
72 reloc_stack[reloc_stack_tos - 1];
73 reloc_stack_tos -= 2;
74 break;
75 case R_mult:
76 value = reloc_stack[reloc_stack_tos - 2] *
77 reloc_stack[reloc_stack_tos - 1];
78 reloc_stack_tos -= 2;
79 break;
80 case R_div:
81 value = reloc_stack[reloc_stack_tos - 2] /
82 reloc_stack[reloc_stack_tos - 1];
83 reloc_stack_tos -= 2;
84 break;
85 case R_mod:
86 value = reloc_stack[reloc_stack_tos - 2] %
87 reloc_stack[reloc_stack_tos - 1];
88 reloc_stack_tos -= 2;
89 break;
90 case R_lshift:
91 value = reloc_stack[reloc_stack_tos - 2] <<
92 reloc_stack[reloc_stack_tos - 1];
93 reloc_stack_tos -= 2;
94 break;
95 case R_rshift:
96 value = reloc_stack[reloc_stack_tos - 2] >>
97 reloc_stack[reloc_stack_tos - 1];
98 reloc_stack_tos -= 2;
99 break;
100 case R_and:
101 value = reloc_stack[reloc_stack_tos - 2] &
102 reloc_stack[reloc_stack_tos - 1];
103 reloc_stack_tos -= 2;
104 break;
105 case R_or:
106 value = reloc_stack[reloc_stack_tos - 2] |
107 reloc_stack[reloc_stack_tos - 1];
108 reloc_stack_tos -= 2;
109 break;
110 case R_xor:
111 value = reloc_stack[reloc_stack_tos - 2] ^
112 reloc_stack[reloc_stack_tos - 1];
113 reloc_stack_tos -= 2;
114 break;
115 case R_land:
116 value = reloc_stack[reloc_stack_tos - 2] &&
117 reloc_stack[reloc_stack_tos - 1];
118 reloc_stack_tos -= 2;
119 break;
120 case R_lor:
121 value = reloc_stack[reloc_stack_tos - 2] ||
122 reloc_stack[reloc_stack_tos - 1];
123 reloc_stack_tos -= 2;
124 break;
125 case R_neg:
126 value = -reloc_stack[reloc_stack_tos - 1];
127 reloc_stack_tos--;
128 break;
129 case R_comp:
130 value = ~reloc_stack[reloc_stack_tos - 1];
131 reloc_stack_tos -= 1;
132 break;
133 default:
134 printk(KERN_WARNING "module %s: unhandled reloction\n",
135 mod->name);
136 return 0;
137 }
138
139 /* now push the new value back on stack */
140 reloc_stack_push(value);
141
142 return value;
143}
144
145void *module_alloc(unsigned long size)
146{
147 if (size == 0)
148 return NULL;
149 return vmalloc(size);
150}
151
152/* Free memory returned from module_alloc */
153void module_free(struct module *mod, void *module_region)
154{
155 vfree(module_region);
156}
157
158/* Transfer the section to the L1 memory */
159int
160module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
161 char *secstrings, struct module *mod)
162{
163 Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
164 void *dest = NULL;
165
166 for (s = sechdrs; s < sechdrs_end; ++s) {
167 if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
168 ((strcmp(".text", secstrings + s->sh_name)==0) &&
169 (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
170 mod->arch.text_l1 = s;
171 dest = l1_inst_sram_alloc(s->sh_size);
172 if (dest == NULL) {
173 printk(KERN_ERR
174 "module %s: L1 instruction memory allocation failed\n",
175 mod->name);
176 return -1;
177 }
178 dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
179 s->sh_flags &= ~SHF_ALLOC;
180 s->sh_addr = (unsigned long)dest;
181 }
182 if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
183 ((strcmp(".data", secstrings + s->sh_name)==0) &&
184 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
185 mod->arch.data_a_l1 = s;
186 dest = l1_data_sram_alloc(s->sh_size);
187 if (dest == NULL) {
188 printk(KERN_ERR
189 "module %s: L1 data memory allocation failed\n",
190 mod->name);
191 return -1;
192 }
193 memcpy(dest, (void *)s->sh_addr, s->sh_size);
194 s->sh_flags &= ~SHF_ALLOC;
195 s->sh_addr = (unsigned long)dest;
196 }
197 if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
198 ((strcmp(".bss", secstrings + s->sh_name)==0) &&
199 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
200 mod->arch.bss_a_l1 = s;
201 dest = l1_data_sram_alloc(s->sh_size);
202 if (dest == NULL) {
203 printk(KERN_ERR
204 "module %s: L1 data memory allocation failed\n",
205 mod->name);
206 return -1;
207 }
208 memset(dest, 0, s->sh_size);
209 s->sh_flags &= ~SHF_ALLOC;
210 s->sh_addr = (unsigned long)dest;
211 }
212 if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
213 mod->arch.data_b_l1 = s;
214 dest = l1_data_B_sram_alloc(s->sh_size);
215 if (dest == NULL) {
216 printk(KERN_ERR
217 "module %s: L1 data memory allocation failed\n",
218 mod->name);
219 return -1;
220 }
221 memcpy(dest, (void *)s->sh_addr, s->sh_size);
222 s->sh_flags &= ~SHF_ALLOC;
223 s->sh_addr = (unsigned long)dest;
224 }
225 if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
226 mod->arch.bss_b_l1 = s;
227 dest = l1_data_B_sram_alloc(s->sh_size);
228 if (dest == NULL) {
229 printk(KERN_ERR
230 "module %s: L1 data memory allocation failed\n",
231 mod->name);
232 return -1;
233 }
234 memset(dest, 0, s->sh_size);
235 s->sh_flags &= ~SHF_ALLOC;
236 s->sh_addr = (unsigned long)dest;
237 }
238 }
239 return 0;
240}
241
242int
243apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
244 unsigned int symindex, unsigned int relsec, struct module *me)
245{
246 printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
247 return -ENOEXEC;
248}
249
250/*************************************************************************/
251/* FUNCTION : apply_relocate_add */
252/* ABSTRACT : Blackfin specific relocation handling for the loadable */
253/* modules. Modules are expected to be .o files. */
254/* Arithmetic relocations are handled. */
255/* We do not expect LSETUP to be split and hence is not */
256/* handled. */
257/* R_byte and R_byte2 are also not handled as the gas */
258/* does not generate it. */
259/*************************************************************************/
260int
261apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
262 unsigned int symindex, unsigned int relsec,
263 struct module *mod)
264{
265 unsigned int i;
266 unsigned short tmp;
267 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
268 Elf32_Sym *sym;
269 uint32_t *location32;
270 uint16_t *location16;
271 uint32_t value;
272
273 pr_debug("Applying relocate section %u to %u\n", relsec,
274 sechdrs[relsec].sh_info);
275 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
276 /* This is where to make the change */
277 location16 =
278 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
279 rel[i].r_offset);
280 location32 = (uint32_t *) location16;
281 /* This is the symbol it is referring to. Note that all
282 undefined symbols have been resolved. */
283 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
284 + ELF32_R_SYM(rel[i].r_info);
285 if (is_reloc_stack_empty()) {
286 value = sym->st_value;
287 } else {
288 value = reloc_stack_pop();
289 }
290 value += rel[i].r_addend;
291 pr_debug("location is %x, value is %x type is %d \n",
292 (unsigned int) location32, value,
293 ELF32_R_TYPE(rel[i].r_info));
294
295 switch (ELF32_R_TYPE(rel[i].r_info)) {
296
297 case R_pcrel24:
298 case R_pcrel24_jump_l:
299 /* Add the value, subtract its postition */
300 location16 =
301 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
302 sh_addr + rel[i].r_offset - 2);
303 location32 = (uint32_t *) location16;
304 value -= (uint32_t) location32;
305 value >>= 1;
306 pr_debug("value is %x, before %x-%x after %x-%x\n", value,
307 *location16, *(location16 + 1),
308 (*location16 & 0xff00) | (value >> 16 & 0x00ff),
309 value & 0xffff);
310 *location16 =
311 (*location16 & 0xff00) | (value >> 16 & 0x00ff);
312 *(location16 + 1) = value & 0xffff;
313 break;
314 case R_pcrel12_jump:
315 case R_pcrel12_jump_s:
316 value -= (uint32_t) location32;
317 value >>= 1;
318 *location16 = (value & 0xfff);
319 break;
320 case R_pcrel10:
321 value -= (uint32_t) location32;
322 value >>= 1;
323 *location16 = (value & 0x3ff);
324 break;
325 case R_luimm16:
326 pr_debug("before %x after %x\n", *location16,
327 (value & 0xffff));
328 tmp = (value & 0xffff);
329 if((unsigned long)location16 >= L1_CODE_START) {
330 dma_memcpy(location16, &tmp, 2);
331 } else
332 *location16 = tmp;
333 break;
334 case R_huimm16:
335 pr_debug("before %x after %x\n", *location16,
336 ((value >> 16) & 0xffff));
337 tmp = ((value >> 16) & 0xffff);
338 if((unsigned long)location16 >= L1_CODE_START) {
339 dma_memcpy(location16, &tmp, 2);
340 } else
341 *location16 = tmp;
342 break;
343 case R_rimm16:
344 *location16 = (value & 0xffff);
345 break;
346 case R_byte4_data:
347 pr_debug("before %x after %x\n", *location32, value);
348 *location32 = value;
349 break;
350 case R_push:
351 reloc_stack_push(value);
352 break;
353 case R_const:
354 reloc_stack_push(rel[i].r_addend);
355 break;
356 case R_add:
357 case R_sub:
358 case R_mult:
359 case R_div:
360 case R_mod:
361 case R_lshift:
362 case R_rshift:
363 case R_and:
364 case R_or:
365 case R_xor:
366 case R_land:
367 case R_lor:
368 case R_neg:
369 case R_comp:
370 reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
371 break;
372 default:
373 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
374 mod->name, ELF32_R_TYPE(rel[i].r_info));
375 return -ENOEXEC;
376 }
377 }
378 return 0;
379}
380
381int
382module_finalize(const Elf_Ehdr * hdr,
383 const Elf_Shdr * sechdrs, struct module *mod)
384{
385 unsigned int i, strindex = 0, symindex = 0;
386 char *secstrings;
387
388 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
389
390 for (i = 1; i < hdr->e_shnum; i++) {
391 /* Internal symbols and strings. */
392 if (sechdrs[i].sh_type == SHT_SYMTAB) {
393 symindex = i;
394 strindex = sechdrs[i].sh_link;
395 }
396 }
397
398 for (i = 1; i < hdr->e_shnum; i++) {
399 const char *strtab = (char *)sechdrs[strindex].sh_addr;
400 unsigned int info = sechdrs[i].sh_info;
401
402 /* Not a valid relocation section? */
403 if (info >= hdr->e_shnum)
404 continue;
405
406 if ((sechdrs[i].sh_type == SHT_RELA) &&
407 ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
408 ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
409 (hdr->e_flags & FLG_CODE_IN_L1)))) {
410 apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
411 symindex, i, mod);
412 }
413 }
414 return 0;
415}
416
417void module_arch_cleanup(struct module *mod)
418{
419 if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
420 l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
421 if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
422 l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
423 if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
424 l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
425 if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
426 l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
427 if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
428 l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
429}