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