Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mn10300/kernel/module.c
10817 views
1
/* MN10300 Kernel module helper routines
2
*
3
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All Rights Reserved.
4
* Written by Mark Salter ([email protected])
5
* - Derived from arch/i386/kernel/module.c
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public Licence as published by
9
* the Free Software Foundation; either version 2 of the Licence, or
10
* (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public Licence for more details.
16
*
17
* You should have received a copy of the GNU General Public Licence
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
*/
21
#include <linux/moduleloader.h>
22
#include <linux/elf.h>
23
#include <linux/vmalloc.h>
24
#include <linux/fs.h>
25
#include <linux/string.h>
26
#include <linux/kernel.h>
27
#include <linux/bug.h>
28
29
#if 0
30
#define DEBUGP printk
31
#else
32
#define DEBUGP(fmt, ...)
33
#endif
34
35
/*
36
* allocate storage for a module
37
*/
38
void *module_alloc(unsigned long size)
39
{
40
if (size == 0)
41
return NULL;
42
return vmalloc_exec(size);
43
}
44
45
/*
46
* free memory returned from module_alloc()
47
*/
48
void module_free(struct module *mod, void *module_region)
49
{
50
vfree(module_region);
51
}
52
53
/*
54
* allow the arch to fix up the section table
55
* - we don't need anything special
56
*/
57
int module_frob_arch_sections(Elf_Ehdr *hdr,
58
Elf_Shdr *sechdrs,
59
char *secstrings,
60
struct module *mod)
61
{
62
return 0;
63
}
64
65
static void reloc_put16(uint8_t *p, uint32_t val)
66
{
67
p[0] = val & 0xff;
68
p[1] = (val >> 8) & 0xff;
69
}
70
71
static void reloc_put24(uint8_t *p, uint32_t val)
72
{
73
reloc_put16(p, val);
74
p[2] = (val >> 16) & 0xff;
75
}
76
77
static void reloc_put32(uint8_t *p, uint32_t val)
78
{
79
reloc_put16(p, val);
80
reloc_put16(p+2, val >> 16);
81
}
82
83
/*
84
* apply a REL relocation
85
*/
86
int apply_relocate(Elf32_Shdr *sechdrs,
87
const char *strtab,
88
unsigned int symindex,
89
unsigned int relsec,
90
struct module *me)
91
{
92
printk(KERN_ERR "module %s: RELOCATION unsupported\n",
93
me->name);
94
return -ENOEXEC;
95
}
96
97
/*
98
* apply a RELA relocation
99
*/
100
int apply_relocate_add(Elf32_Shdr *sechdrs,
101
const char *strtab,
102
unsigned int symindex,
103
unsigned int relsec,
104
struct module *me)
105
{
106
unsigned int i, sym_diff_seen = 0;
107
Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
108
Elf32_Sym *sym;
109
Elf32_Addr relocation, sym_diff_val = 0;
110
uint8_t *location;
111
uint32_t value;
112
113
DEBUGP("Applying relocate section %u to %u\n",
114
relsec, sechdrs[relsec].sh_info);
115
116
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
117
/* this is where to make the change */
118
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
119
+ rel[i].r_offset;
120
121
/* this is the symbol the relocation is referring to (note that
122
* all undefined symbols have been resolved by the caller) */
123
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
124
+ ELF32_R_SYM(rel[i].r_info);
125
126
/* this is the adjustment to be made */
127
relocation = sym->st_value + rel[i].r_addend;
128
129
if (sym_diff_seen) {
130
switch (ELF32_R_TYPE(rel[i].r_info)) {
131
case R_MN10300_32:
132
case R_MN10300_24:
133
case R_MN10300_16:
134
case R_MN10300_8:
135
relocation -= sym_diff_val;
136
sym_diff_seen = 0;
137
break;
138
default:
139
printk(KERN_ERR "module %s: Unexpected SYM_DIFF relocation: %u\n",
140
me->name, ELF32_R_TYPE(rel[i].r_info));
141
return -ENOEXEC;
142
}
143
}
144
145
switch (ELF32_R_TYPE(rel[i].r_info)) {
146
/* for the first four relocation types, we simply
147
* store the adjustment at the location given */
148
case R_MN10300_32:
149
reloc_put32(location, relocation);
150
break;
151
case R_MN10300_24:
152
reloc_put24(location, relocation);
153
break;
154
case R_MN10300_16:
155
reloc_put16(location, relocation);
156
break;
157
case R_MN10300_8:
158
*location = relocation;
159
break;
160
161
/* for the next three relocation types, we write the
162
* adjustment with the address subtracted over the
163
* value at the location given */
164
case R_MN10300_PCREL32:
165
value = relocation - (uint32_t) location;
166
reloc_put32(location, value);
167
break;
168
case R_MN10300_PCREL16:
169
value = relocation - (uint32_t) location;
170
reloc_put16(location, value);
171
break;
172
case R_MN10300_PCREL8:
173
*location = relocation - (uint32_t) location;
174
break;
175
176
case R_MN10300_SYM_DIFF:
177
/* This is used to adjust the next reloc as required
178
* by relaxation. */
179
sym_diff_seen = 1;
180
sym_diff_val = sym->st_value;
181
break;
182
183
case R_MN10300_ALIGN:
184
/* Just ignore the ALIGN relocs.
185
* Only interesting if kernel performed relaxation. */
186
continue;
187
188
default:
189
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
190
me->name, ELF32_R_TYPE(rel[i].r_info));
191
return -ENOEXEC;
192
}
193
}
194
if (sym_diff_seen) {
195
printk(KERN_ERR "module %s: Nothing follows SYM_DIFF relocation: %u\n",
196
me->name, ELF32_R_TYPE(rel[i].r_info));
197
return -ENOEXEC;
198
}
199
return 0;
200
}
201
202
/*
203
* finish loading the module
204
*/
205
int module_finalize(const Elf_Ehdr *hdr,
206
const Elf_Shdr *sechdrs,
207
struct module *me)
208
{
209
return 0;
210
}
211
212
/*
213
* finish clearing the module
214
*/
215
void module_arch_cleanup(struct module *mod)
216
{
217
}
218
219