Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/xtensa/kernel/module.c
10817 views
1
/*
2
* arch/xtensa/kernel/module.c
3
*
4
* Module support.
5
*
6
* This file is subject to the terms and conditions of the GNU General Public
7
* License. See the file "COPYING" in the main directory of this archive
8
* for more details.
9
*
10
* Copyright (C) 2001 - 2006 Tensilica Inc.
11
*
12
* Chris Zankel <[email protected]>
13
*
14
*/
15
16
#include <linux/module.h>
17
#include <linux/moduleloader.h>
18
#include <linux/elf.h>
19
#include <linux/vmalloc.h>
20
#include <linux/fs.h>
21
#include <linux/string.h>
22
#include <linux/kernel.h>
23
#include <linux/cache.h>
24
25
#undef DEBUG_RELOCATE
26
27
void *module_alloc(unsigned long size)
28
{
29
if (size == 0)
30
return NULL;
31
return vmalloc_exec(size);
32
}
33
34
void module_free(struct module *mod, void *module_region)
35
{
36
vfree(module_region);
37
}
38
39
int module_frob_arch_sections(Elf32_Ehdr *hdr,
40
Elf32_Shdr *sechdrs,
41
char *secstrings,
42
struct module *mod)
43
{
44
return 0;
45
}
46
47
static int
48
decode_calln_opcode (unsigned char *location)
49
{
50
#ifdef __XTENSA_EB__
51
return (location[0] & 0xf0) == 0x50;
52
#endif
53
#ifdef __XTENSA_EL__
54
return (location[0] & 0xf) == 0x5;
55
#endif
56
}
57
58
static int
59
decode_l32r_opcode (unsigned char *location)
60
{
61
#ifdef __XTENSA_EB__
62
return (location[0] & 0xf0) == 0x10;
63
#endif
64
#ifdef __XTENSA_EL__
65
return (location[0] & 0xf) == 0x1;
66
#endif
67
}
68
69
int apply_relocate(Elf32_Shdr *sechdrs,
70
const char *strtab,
71
unsigned int symindex,
72
unsigned int relsec,
73
struct module *mod)
74
{
75
printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
76
mod->name);
77
return -ENOEXEC;
78
79
}
80
81
int apply_relocate_add(Elf32_Shdr *sechdrs,
82
const char *strtab,
83
unsigned int symindex,
84
unsigned int relsec,
85
struct module *mod)
86
{
87
unsigned int i;
88
Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
89
Elf32_Sym *sym;
90
unsigned char *location;
91
uint32_t value;
92
93
#ifdef DEBUG_RELOCATE
94
printk("Applying relocate section %u to %u\n", relsec,
95
sechdrs[relsec].sh_info);
96
#endif
97
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
98
location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
99
+ rela[i].r_offset;
100
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
101
+ ELF32_R_SYM(rela[i].r_info);
102
value = sym->st_value + rela[i].r_addend;
103
104
switch (ELF32_R_TYPE(rela[i].r_info)) {
105
case R_XTENSA_NONE:
106
case R_XTENSA_DIFF8:
107
case R_XTENSA_DIFF16:
108
case R_XTENSA_DIFF32:
109
case R_XTENSA_ASM_EXPAND:
110
break;
111
112
case R_XTENSA_32:
113
case R_XTENSA_PLT:
114
*(uint32_t *)location += value;
115
break;
116
117
case R_XTENSA_SLOT0_OP:
118
if (decode_calln_opcode(location)) {
119
value -= ((unsigned long)location & -4) + 4;
120
if ((value & 3) != 0 ||
121
((value + (1 << 19)) >> 20) != 0) {
122
printk("%s: relocation out of range, "
123
"section %d reloc %d "
124
"sym '%s'\n",
125
mod->name, relsec, i,
126
strtab + sym->st_name);
127
return -ENOEXEC;
128
}
129
value = (signed int)value >> 2;
130
#ifdef __XTENSA_EB__
131
location[0] = ((location[0] & ~0x3) |
132
((value >> 16) & 0x3));
133
location[1] = (value >> 8) & 0xff;
134
location[2] = value & 0xff;
135
#endif
136
#ifdef __XTENSA_EL__
137
location[0] = ((location[0] & ~0xc0) |
138
((value << 6) & 0xc0));
139
location[1] = (value >> 2) & 0xff;
140
location[2] = (value >> 10) & 0xff;
141
#endif
142
} else if (decode_l32r_opcode(location)) {
143
value -= (((unsigned long)location + 3) & -4);
144
if ((value & 3) != 0 ||
145
(signed int)value >> 18 != -1) {
146
printk("%s: relocation out of range, "
147
"section %d reloc %d "
148
"sym '%s'\n",
149
mod->name, relsec, i,
150
strtab + sym->st_name);
151
return -ENOEXEC;
152
}
153
value = (signed int)value >> 2;
154
155
#ifdef __XTENSA_EB__
156
location[1] = (value >> 8) & 0xff;
157
location[2] = value & 0xff;
158
#endif
159
#ifdef __XTENSA_EL__
160
location[1] = value & 0xff;
161
location[2] = (value >> 8) & 0xff;
162
#endif
163
}
164
/* FIXME: Ignore any other opcodes. The Xtensa
165
assembler currently assumes that the linker will
166
always do relaxation and so all PC-relative
167
operands need relocations. (The assembler also
168
writes out the tentative PC-relative values,
169
assuming no link-time relaxation, so it is usually
170
safe to ignore the relocations.) If the
171
assembler's "--no-link-relax" flag can be made to
172
work, and if all kernel modules can be assembled
173
with that flag, then unexpected relocations could
174
be detected here. */
175
break;
176
177
case R_XTENSA_SLOT1_OP:
178
case R_XTENSA_SLOT2_OP:
179
case R_XTENSA_SLOT3_OP:
180
case R_XTENSA_SLOT4_OP:
181
case R_XTENSA_SLOT5_OP:
182
case R_XTENSA_SLOT6_OP:
183
case R_XTENSA_SLOT7_OP:
184
case R_XTENSA_SLOT8_OP:
185
case R_XTENSA_SLOT9_OP:
186
case R_XTENSA_SLOT10_OP:
187
case R_XTENSA_SLOT11_OP:
188
case R_XTENSA_SLOT12_OP:
189
case R_XTENSA_SLOT13_OP:
190
case R_XTENSA_SLOT14_OP:
191
printk("%s: unexpected FLIX relocation: %u\n",
192
mod->name,
193
ELF32_R_TYPE(rela[i].r_info));
194
return -ENOEXEC;
195
196
case R_XTENSA_SLOT0_ALT:
197
case R_XTENSA_SLOT1_ALT:
198
case R_XTENSA_SLOT2_ALT:
199
case R_XTENSA_SLOT3_ALT:
200
case R_XTENSA_SLOT4_ALT:
201
case R_XTENSA_SLOT5_ALT:
202
case R_XTENSA_SLOT6_ALT:
203
case R_XTENSA_SLOT7_ALT:
204
case R_XTENSA_SLOT8_ALT:
205
case R_XTENSA_SLOT9_ALT:
206
case R_XTENSA_SLOT10_ALT:
207
case R_XTENSA_SLOT11_ALT:
208
case R_XTENSA_SLOT12_ALT:
209
case R_XTENSA_SLOT13_ALT:
210
case R_XTENSA_SLOT14_ALT:
211
printk("%s: unexpected ALT relocation: %u\n",
212
mod->name,
213
ELF32_R_TYPE(rela[i].r_info));
214
return -ENOEXEC;
215
216
default:
217
printk("%s: unexpected relocation: %u\n",
218
mod->name,
219
ELF32_R_TYPE(rela[i].r_info));
220
return -ENOEXEC;
221
}
222
}
223
return 0;
224
}
225
226
int module_finalize(const Elf_Ehdr *hdr,
227
const Elf_Shdr *sechdrs,
228
struct module *mod)
229
{
230
return 0;
231
}
232
233
void module_arch_cleanup(struct module *mod)
234
{
235
}
236
237