~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/kernel/module.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  linux/arch/arm/kernel/module.c
 
3
 *
 
4
 *  Copyright (C) 2002 Russell King.
 
5
 *  Modified for nommu by Hyok S. Choi
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License version 2 as
 
9
 * published by the Free Software Foundation.
 
10
 *
 
11
 * Module allocation method suggested by Andi Kleen.
 
12
 */
 
13
#include <linux/module.h>
 
14
#include <linux/moduleloader.h>
 
15
#include <linux/kernel.h>
 
16
#include <linux/mm.h>
 
17
#include <linux/elf.h>
 
18
#include <linux/vmalloc.h>
 
19
#include <linux/fs.h>
 
20
#include <linux/string.h>
 
21
#include <linux/gfp.h>
 
22
 
 
23
#include <asm/pgtable.h>
 
24
#include <asm/sections.h>
 
25
#include <asm/smp_plat.h>
 
26
#include <asm/unwind.h>
 
27
 
 
28
#ifdef CONFIG_XIP_KERNEL
 
29
/*
 
30
 * The XIP kernel text is mapped in the module area for modules and
 
31
 * some other stuff to work without any indirect relocations.
 
32
 * MODULES_VADDR is redefined here and not in asm/memory.h to avoid
 
33
 * recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
 
34
 */
 
35
#undef MODULES_VADDR
 
36
#define MODULES_VADDR   (((unsigned long)_etext + ~PMD_MASK) & PMD_MASK)
 
37
#endif
 
38
 
 
39
#ifdef CONFIG_MMU
 
40
void *module_alloc(unsigned long size)
 
41
{
 
42
        return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
 
43
                                GFP_KERNEL, PAGE_KERNEL_EXEC, -1,
 
44
                                __builtin_return_address(0));
 
45
}
 
46
#endif
 
47
 
 
48
int
 
49
apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 
50
               unsigned int relindex, struct module *module)
 
51
{
 
52
        Elf32_Shdr *symsec = sechdrs + symindex;
 
53
        Elf32_Shdr *relsec = sechdrs + relindex;
 
54
        Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
 
55
        Elf32_Rel *rel = (void *)relsec->sh_addr;
 
56
        unsigned int i;
 
57
 
 
58
        for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
 
59
                unsigned long loc;
 
60
                Elf32_Sym *sym;
 
61
                const char *symname;
 
62
                s32 offset;
 
63
#ifdef CONFIG_THUMB2_KERNEL
 
64
                u32 upper, lower, sign, j1, j2;
 
65
#endif
 
66
 
 
67
                offset = ELF32_R_SYM(rel->r_info);
 
68
                if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
 
69
                        pr_err("%s: section %u reloc %u: bad relocation sym offset\n",
 
70
                                module->name, relindex, i);
 
71
                        return -ENOEXEC;
 
72
                }
 
73
 
 
74
                sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
 
75
                symname = strtab + sym->st_name;
 
76
 
 
77
                if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
 
78
                        pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n",
 
79
                               module->name, relindex, i, symname,
 
80
                               rel->r_offset, dstsec->sh_size);
 
81
                        return -ENOEXEC;
 
82
                }
 
83
 
 
84
                loc = dstsec->sh_addr + rel->r_offset;
 
85
 
 
86
                switch (ELF32_R_TYPE(rel->r_info)) {
 
87
                case R_ARM_NONE:
 
88
                        /* ignore */
 
89
                        break;
 
90
 
 
91
                case R_ARM_ABS32:
 
92
                        *(u32 *)loc += sym->st_value;
 
93
                        break;
 
94
 
 
95
                case R_ARM_PC24:
 
96
                case R_ARM_CALL:
 
97
                case R_ARM_JUMP24:
 
98
                        offset = (*(u32 *)loc & 0x00ffffff) << 2;
 
99
                        if (offset & 0x02000000)
 
100
                                offset -= 0x04000000;
 
101
 
 
102
                        offset += sym->st_value - loc;
 
103
                        if (offset & 3 ||
 
104
                            offset <= (s32)0xfe000000 ||
 
105
                            offset >= (s32)0x02000000) {
 
106
                                pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
 
107
                                       module->name, relindex, i, symname,
 
108
                                       ELF32_R_TYPE(rel->r_info), loc,
 
109
                                       sym->st_value);
 
110
                                return -ENOEXEC;
 
111
                        }
 
112
 
 
113
                        offset >>= 2;
 
114
 
 
115
                        *(u32 *)loc &= 0xff000000;
 
116
                        *(u32 *)loc |= offset & 0x00ffffff;
 
117
                        break;
 
118
 
 
119
               case R_ARM_V4BX:
 
120
                       /* Preserve Rm and the condition code. Alter
 
121
                        * other bits to re-code instruction as
 
122
                        * MOV PC,Rm.
 
123
                        */
 
124
                       *(u32 *)loc &= 0xf000000f;
 
125
                       *(u32 *)loc |= 0x01a0f000;
 
126
                       break;
 
127
 
 
128
                case R_ARM_PREL31:
 
129
                        offset = *(u32 *)loc + sym->st_value - loc;
 
130
                        *(u32 *)loc = offset & 0x7fffffff;
 
131
                        break;
 
132
 
 
133
                case R_ARM_MOVW_ABS_NC:
 
134
                case R_ARM_MOVT_ABS:
 
135
                        offset = *(u32 *)loc;
 
136
                        offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
 
137
                        offset = (offset ^ 0x8000) - 0x8000;
 
138
 
 
139
                        offset += sym->st_value;
 
140
                        if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)
 
141
                                offset >>= 16;
 
142
 
 
143
                        *(u32 *)loc &= 0xfff0f000;
 
144
                        *(u32 *)loc |= ((offset & 0xf000) << 4) |
 
145
                                        (offset & 0x0fff);
 
146
                        break;
 
147
 
 
148
#ifdef CONFIG_THUMB2_KERNEL
 
149
                case R_ARM_THM_CALL:
 
150
                case R_ARM_THM_JUMP24:
 
151
                        upper = *(u16 *)loc;
 
152
                        lower = *(u16 *)(loc + 2);
 
153
 
 
154
                        /*
 
155
                         * 25 bit signed address range (Thumb-2 BL and B.W
 
156
                         * instructions):
 
157
                         *   S:I1:I2:imm10:imm11:0
 
158
                         * where:
 
159
                         *   S     = upper[10]   = offset[24]
 
160
                         *   I1    = ~(J1 ^ S)   = offset[23]
 
161
                         *   I2    = ~(J2 ^ S)   = offset[22]
 
162
                         *   imm10 = upper[9:0]  = offset[21:12]
 
163
                         *   imm11 = lower[10:0] = offset[11:1]
 
164
                         *   J1    = lower[13]
 
165
                         *   J2    = lower[11]
 
166
                         */
 
167
                        sign = (upper >> 10) & 1;
 
168
                        j1 = (lower >> 13) & 1;
 
169
                        j2 = (lower >> 11) & 1;
 
170
                        offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
 
171
                                ((~(j2 ^ sign) & 1) << 22) |
 
172
                                ((upper & 0x03ff) << 12) |
 
173
                                ((lower & 0x07ff) << 1);
 
174
                        if (offset & 0x01000000)
 
175
                                offset -= 0x02000000;
 
176
                        offset += sym->st_value - loc;
 
177
 
 
178
                        /*
 
179
                         * For function symbols, only Thumb addresses are
 
180
                         * allowed (no interworking).
 
181
                         *
 
182
                         * For non-function symbols, the destination
 
183
                         * has no specific ARM/Thumb disposition, so
 
184
                         * the branch is resolved under the assumption
 
185
                         * that interworking is not required.
 
186
                         */
 
187
                        if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
 
188
                                !(offset & 1)) ||
 
189
                            offset <= (s32)0xff000000 ||
 
190
                            offset >= (s32)0x01000000) {
 
191
                                pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
 
192
                                       module->name, relindex, i, symname,
 
193
                                       ELF32_R_TYPE(rel->r_info), loc,
 
194
                                       sym->st_value);
 
195
                                return -ENOEXEC;
 
196
                        }
 
197
 
 
198
                        sign = (offset >> 24) & 1;
 
199
                        j1 = sign ^ (~(offset >> 23) & 1);
 
200
                        j2 = sign ^ (~(offset >> 22) & 1);
 
201
                        *(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) |
 
202
                                            ((offset >> 12) & 0x03ff));
 
203
                        *(u16 *)(loc + 2) = (u16)((lower & 0xd000) |
 
204
                                                  (j1 << 13) | (j2 << 11) |
 
205
                                                  ((offset >> 1) & 0x07ff));
 
206
                        break;
 
207
 
 
208
                case R_ARM_THM_MOVW_ABS_NC:
 
209
                case R_ARM_THM_MOVT_ABS:
 
210
                        upper = *(u16 *)loc;
 
211
                        lower = *(u16 *)(loc + 2);
 
212
 
 
213
                        /*
 
214
                         * MOVT/MOVW instructions encoding in Thumb-2:
 
215
                         *
 
216
                         * i    = upper[10]
 
217
                         * imm4 = upper[3:0]
 
218
                         * imm3 = lower[14:12]
 
219
                         * imm8 = lower[7:0]
 
220
                         *
 
221
                         * imm16 = imm4:i:imm3:imm8
 
222
                         */
 
223
                        offset = ((upper & 0x000f) << 12) |
 
224
                                ((upper & 0x0400) << 1) |
 
225
                                ((lower & 0x7000) >> 4) | (lower & 0x00ff);
 
226
                        offset = (offset ^ 0x8000) - 0x8000;
 
227
                        offset += sym->st_value;
 
228
 
 
229
                        if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
 
230
                                offset >>= 16;
 
231
 
 
232
                        *(u16 *)loc = (u16)((upper & 0xfbf0) |
 
233
                                            ((offset & 0xf000) >> 12) |
 
234
                                            ((offset & 0x0800) >> 1));
 
235
                        *(u16 *)(loc + 2) = (u16)((lower & 0x8f00) |
 
236
                                                  ((offset & 0x0700) << 4) |
 
237
                                                  (offset & 0x00ff));
 
238
                        break;
 
239
#endif
 
240
 
 
241
                default:
 
242
                        printk(KERN_ERR "%s: unknown relocation: %u\n",
 
243
                               module->name, ELF32_R_TYPE(rel->r_info));
 
244
                        return -ENOEXEC;
 
245
                }
 
246
        }
 
247
        return 0;
 
248
}
 
249
 
 
250
struct mod_unwind_map {
 
251
        const Elf_Shdr *unw_sec;
 
252
        const Elf_Shdr *txt_sec;
 
253
};
 
254
 
 
255
static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
 
256
        const Elf_Shdr *sechdrs, const char *name)
 
257
{
 
258
        const Elf_Shdr *s, *se;
 
259
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
260
 
 
261
        for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++)
 
262
                if (strcmp(name, secstrs + s->sh_name) == 0)
 
263
                        return s;
 
264
 
 
265
        return NULL;
 
266
}
 
267
 
 
268
extern void fixup_pv_table(const void *, unsigned long);
 
269
extern void fixup_smp(const void *, unsigned long);
 
270
 
 
271
int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 
272
                    struct module *mod)
 
273
{
 
274
        const Elf_Shdr *s = NULL;
 
275
#ifdef CONFIG_ARM_UNWIND
 
276
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
277
        const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
 
278
        struct mod_unwind_map maps[ARM_SEC_MAX];
 
279
        int i;
 
280
 
 
281
        memset(maps, 0, sizeof(maps));
 
282
 
 
283
        for (s = sechdrs; s < sechdrs_end; s++) {
 
284
                const char *secname = secstrs + s->sh_name;
 
285
 
 
286
                if (!(s->sh_flags & SHF_ALLOC))
 
287
                        continue;
 
288
 
 
289
                if (strcmp(".ARM.exidx.init.text", secname) == 0)
 
290
                        maps[ARM_SEC_INIT].unw_sec = s;
 
291
                else if (strcmp(".ARM.exidx.devinit.text", secname) == 0)
 
292
                        maps[ARM_SEC_DEVINIT].unw_sec = s;
 
293
                else if (strcmp(".ARM.exidx", secname) == 0)
 
294
                        maps[ARM_SEC_CORE].unw_sec = s;
 
295
                else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
 
296
                        maps[ARM_SEC_EXIT].unw_sec = s;
 
297
                else if (strcmp(".ARM.exidx.devexit.text", secname) == 0)
 
298
                        maps[ARM_SEC_DEVEXIT].unw_sec = s;
 
299
                else if (strcmp(".init.text", secname) == 0)
 
300
                        maps[ARM_SEC_INIT].txt_sec = s;
 
301
                else if (strcmp(".devinit.text", secname) == 0)
 
302
                        maps[ARM_SEC_DEVINIT].txt_sec = s;
 
303
                else if (strcmp(".text", secname) == 0)
 
304
                        maps[ARM_SEC_CORE].txt_sec = s;
 
305
                else if (strcmp(".exit.text", secname) == 0)
 
306
                        maps[ARM_SEC_EXIT].txt_sec = s;
 
307
                else if (strcmp(".devexit.text", secname) == 0)
 
308
                        maps[ARM_SEC_DEVEXIT].txt_sec = s;
 
309
        }
 
310
 
 
311
        for (i = 0; i < ARM_SEC_MAX; i++)
 
312
                if (maps[i].unw_sec && maps[i].txt_sec)
 
313
                        mod->arch.unwind[i] =
 
314
                                unwind_table_add(maps[i].unw_sec->sh_addr,
 
315
                                                 maps[i].unw_sec->sh_size,
 
316
                                                 maps[i].txt_sec->sh_addr,
 
317
                                                 maps[i].txt_sec->sh_size);
 
318
#endif
 
319
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
 
320
        s = find_mod_section(hdr, sechdrs, ".pv_table");
 
321
        if (s)
 
322
                fixup_pv_table((void *)s->sh_addr, s->sh_size);
 
323
#endif
 
324
        s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
 
325
        if (s && !is_smp())
 
326
#ifdef CONFIG_SMP_ON_UP
 
327
                fixup_smp((void *)s->sh_addr, s->sh_size);
 
328
#else
 
329
                return -EINVAL;
 
330
#endif
 
331
        return 0;
 
332
}
 
333
 
 
334
void
 
335
module_arch_cleanup(struct module *mod)
 
336
{
 
337
#ifdef CONFIG_ARM_UNWIND
 
338
        int i;
 
339
 
 
340
        for (i = 0; i < ARM_SEC_MAX; i++)
 
341
                if (mod->arch.unwind[i])
 
342
                        unwind_table_del(mod->arch.unwind[i]);
 
343
#endif
 
344
}