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