• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
20 int
module_frob_arch_sections(Elf_Ehdr * hdr,Elf_Shdr * sechdrs,char * secstrings,struct module * mod)21 module_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 /*************************************************************************/
150 int
apply_relocate_add(Elf_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * mod)151 apply_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 
233 int
module_finalize(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,struct module * mod)234 module_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 
module_arch_cleanup(struct module * mod)279 void 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