• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/blackfin/kernel/
1/*
2 * Copyright 2004-2009 Analog Devices Inc.
3 *
4 * Licensed under the GPL-2 or later
5 */
6
7#define pr_fmt(fmt) "module %s: " fmt
8
9#include <linux/moduleloader.h>
10#include <linux/elf.h>
11#include <linux/vmalloc.h>
12#include <linux/fs.h>
13#include <linux/string.h>
14#include <linux/kernel.h>
15#include <asm/dma.h>
16#include <asm/cacheflush.h>
17#include <asm/uaccess.h>
18
19void *module_alloc(unsigned long size)
20{
21	if (size == 0)
22		return NULL;
23	return vmalloc(size);
24}
25
26/* Free memory returned from module_alloc */
27void module_free(struct module *mod, void *module_region)
28{
29	vfree(module_region);
30}
31
32/* Transfer the section to the L1 memory */
33int
34module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
35			  char *secstrings, struct module *mod)
36{
37	Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
38	void *dest;
39
40	for (s = sechdrs; s < sechdrs_end; ++s) {
41		const char *shname = secstrings + s->sh_name;
42
43		if (s->sh_size == 0)
44			continue;
45
46		if (!strcmp(".l1.text", shname) ||
47		    (!strcmp(".text", shname) &&
48		     (hdr->e_flags & EF_BFIN_CODE_IN_L1))) {
49
50			dest = l1_inst_sram_alloc(s->sh_size);
51			mod->arch.text_l1 = dest;
52			if (dest == NULL) {
53				pr_err("L1 inst memory allocation failed\n",
54					mod->name);
55				return -1;
56			}
57			dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
58
59		} else if (!strcmp(".l1.data", shname) ||
60		           (!strcmp(".data", shname) &&
61		            (hdr->e_flags & EF_BFIN_DATA_IN_L1))) {
62
63			dest = l1_data_sram_alloc(s->sh_size);
64			mod->arch.data_a_l1 = dest;
65			if (dest == NULL) {
66				pr_err("L1 data memory allocation failed\n",
67					mod->name);
68				return -1;
69			}
70			memcpy(dest, (void *)s->sh_addr, s->sh_size);
71
72		} else if (!strcmp(".l1.bss", shname) ||
73		           (!strcmp(".bss", shname) &&
74		            (hdr->e_flags & EF_BFIN_DATA_IN_L1))) {
75
76			dest = l1_data_sram_zalloc(s->sh_size);
77			mod->arch.bss_a_l1 = dest;
78			if (dest == NULL) {
79				pr_err("L1 data memory allocation failed\n",
80					mod->name);
81				return -1;
82			}
83
84		} else if (!strcmp(".l1.data.B", shname)) {
85
86			dest = l1_data_B_sram_alloc(s->sh_size);
87			mod->arch.data_b_l1 = dest;
88			if (dest == NULL) {
89				pr_err("L1 data memory allocation failed\n",
90					mod->name);
91				return -1;
92			}
93			memcpy(dest, (void *)s->sh_addr, s->sh_size);
94
95		} else if (!strcmp(".l1.bss.B", shname)) {
96
97			dest = l1_data_B_sram_alloc(s->sh_size);
98			mod->arch.bss_b_l1 = dest;
99			if (dest == NULL) {
100				pr_err("L1 data memory allocation failed\n",
101					mod->name);
102				return -1;
103			}
104			memset(dest, 0, s->sh_size);
105
106		} else if (!strcmp(".l2.text", shname) ||
107		           (!strcmp(".text", shname) &&
108		            (hdr->e_flags & EF_BFIN_CODE_IN_L2))) {
109
110			dest = l2_sram_alloc(s->sh_size);
111			mod->arch.text_l2 = dest;
112			if (dest == NULL) {
113				pr_err("L2 SRAM allocation failed\n",
114					mod->name);
115				return -1;
116			}
117			memcpy(dest, (void *)s->sh_addr, s->sh_size);
118
119		} else if (!strcmp(".l2.data", shname) ||
120		           (!strcmp(".data", shname) &&
121		            (hdr->e_flags & EF_BFIN_DATA_IN_L2))) {
122
123			dest = l2_sram_alloc(s->sh_size);
124			mod->arch.data_l2 = dest;
125			if (dest == NULL) {
126				pr_err("L2 SRAM allocation failed\n",
127					mod->name);
128				return -1;
129			}
130			memcpy(dest, (void *)s->sh_addr, s->sh_size);
131
132		} else if (!strcmp(".l2.bss", shname) ||
133		           (!strcmp(".bss", shname) &&
134		            (hdr->e_flags & EF_BFIN_DATA_IN_L2))) {
135
136			dest = l2_sram_zalloc(s->sh_size);
137			mod->arch.bss_l2 = dest;
138			if (dest == NULL) {
139				pr_err("L2 SRAM allocation failed\n",
140					mod->name);
141				return -1;
142			}
143
144		} else
145			continue;
146
147		s->sh_flags &= ~SHF_ALLOC;
148		s->sh_addr = (unsigned long)dest;
149	}
150
151	return 0;
152}
153
154int
155apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
156	       unsigned int symindex, unsigned int relsec, struct module *me)
157{
158	pr_err(".rel unsupported\n", me->name);
159	return -ENOEXEC;
160}
161
162/*************************************************************************/
163/* FUNCTION : apply_relocate_add                                         */
164/* ABSTRACT : Blackfin specific relocation handling for the loadable     */
165/*            modules. Modules are expected to be .o files.              */
166/*            Arithmetic relocations are handled.                        */
167/*            We do not expect LSETUP to be split and hence is not       */
168/*            handled.                                                   */
169/*            R_BFIN_BYTE and R_BFIN_BYTE2 are also not handled as the   */
170/*            gas does not generate it.                                  */
171/*************************************************************************/
172int
173apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
174		   unsigned int symindex, unsigned int relsec,
175		   struct module *mod)
176{
177	unsigned int i;
178	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
179	Elf32_Sym *sym;
180	unsigned long location, value, size;
181
182	pr_debug("applying relocate section %u to %u\n", mod->name,
183		relsec, sechdrs[relsec].sh_info);
184
185	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
186		/* This is where to make the change */
187		location = sechdrs[sechdrs[relsec].sh_info].sh_addr +
188		           rel[i].r_offset;
189
190		/* This is the symbol it is referring to. Note that all
191		   undefined symbols have been resolved. */
192		sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
193		    + ELF32_R_SYM(rel[i].r_info);
194		value = sym->st_value;
195		value += rel[i].r_addend;
196
197#ifdef CONFIG_SMP
198		if (location >= COREB_L1_DATA_A_START) {
199			pr_err("cannot relocate in L1: %u (SMP kernel)",
200				mod->name, ELF32_R_TYPE(rel[i].r_info));
201			return -ENOEXEC;
202		}
203#endif
204
205		pr_debug("location is %lx, value is %lx type is %d\n",
206			mod->name, location, value, ELF32_R_TYPE(rel[i].r_info));
207
208		switch (ELF32_R_TYPE(rel[i].r_info)) {
209
210		case R_BFIN_HUIMM16:
211			value >>= 16;
212		case R_BFIN_LUIMM16:
213		case R_BFIN_RIMM16:
214			size = 2;
215			break;
216		case R_BFIN_BYTE4_DATA:
217			size = 4;
218			break;
219
220		case R_BFIN_PCREL24:
221		case R_BFIN_PCREL24_JUMP_L:
222		case R_BFIN_PCREL12_JUMP:
223		case R_BFIN_PCREL12_JUMP_S:
224		case R_BFIN_PCREL10:
225			pr_err("unsupported relocation: %u (no -mlong-calls?)\n",
226				mod->name, ELF32_R_TYPE(rel[i].r_info));
227			return -ENOEXEC;
228
229		default:
230			pr_err("unknown relocation: %u\n", mod->name,
231				ELF32_R_TYPE(rel[i].r_info));
232			return -ENOEXEC;
233		}
234
235		switch (bfin_mem_access_type(location, size)) {
236		case BFIN_MEM_ACCESS_CORE:
237		case BFIN_MEM_ACCESS_CORE_ONLY:
238			memcpy((void *)location, &value, size);
239			break;
240		case BFIN_MEM_ACCESS_DMA:
241			dma_memcpy((void *)location, &value, size);
242			break;
243		case BFIN_MEM_ACCESS_ITEST:
244			isram_memcpy((void *)location, &value, size);
245			break;
246		default:
247			pr_err("invalid relocation for %#lx\n",
248				mod->name, location);
249			return -ENOEXEC;
250		}
251	}
252
253	return 0;
254}
255
256int
257module_finalize(const Elf_Ehdr * hdr,
258		const Elf_Shdr * sechdrs, struct module *mod)
259{
260	unsigned int i, strindex = 0, symindex = 0;
261	char *secstrings;
262	long err = 0;
263
264	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
265
266	for (i = 1; i < hdr->e_shnum; i++) {
267		/* Internal symbols and strings. */
268		if (sechdrs[i].sh_type == SHT_SYMTAB) {
269			symindex = i;
270			strindex = sechdrs[i].sh_link;
271		}
272	}
273
274	for (i = 1; i < hdr->e_shnum; i++) {
275		const char *strtab = (char *)sechdrs[strindex].sh_addr;
276		unsigned int info = sechdrs[i].sh_info;
277		const char *shname = secstrings + sechdrs[i].sh_name;
278
279		/* Not a valid relocation section? */
280		if (info >= hdr->e_shnum)
281			continue;
282
283		/* Only support RELA relocation types */
284		if (sechdrs[i].sh_type != SHT_RELA)
285			continue;
286
287		if (!strcmp(".rela.l2.text", shname) ||
288		    !strcmp(".rela.l1.text", shname) ||
289		    (!strcmp(".rela.text", shname) &&
290			 (hdr->e_flags & (EF_BFIN_CODE_IN_L1 | EF_BFIN_CODE_IN_L2)))) {
291
292			err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
293					   symindex, i, mod);
294			if (err < 0)
295				return -ENOEXEC;
296		}
297	}
298
299	return 0;
300}
301
302void module_arch_cleanup(struct module *mod)
303{
304	l1_inst_sram_free(mod->arch.text_l1);
305	l1_data_A_sram_free(mod->arch.data_a_l1);
306	l1_data_A_sram_free(mod->arch.bss_a_l1);
307	l1_data_B_sram_free(mod->arch.data_b_l1);
308	l1_data_B_sram_free(mod->arch.bss_b_l1);
309	l2_sram_free(mod->arch.text_l2);
310	l2_sram_free(mod->arch.data_l2);
311	l2_sram_free(mod->arch.bss_l2);
312}
313