OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [kernel/] [module_64.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*  Kernel module help for PPC64.
2
    Copyright (C) 2001, 2003 Rusty Russell IBM Corporation.
3
 
4
    This program is free software; you can redistribute it and/or modify
5
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation; either version 2 of the License, or
7
    (at your option) any later version.
8
 
9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU General Public License for more details.
13
 
14
    You should have received a copy of the GNU General Public License
15
    along with this program; if not, write to the Free Software
16
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
*/
18
#include <linux/module.h>
19
#include <linux/elf.h>
20
#include <linux/moduleloader.h>
21
#include <linux/err.h>
22
#include <linux/vmalloc.h>
23
#include <linux/bug.h>
24
#include <asm/module.h>
25
#include <asm/uaccess.h>
26
#include <asm/firmware.h>
27
 
28
#include "setup.h"
29
 
30
/* FIXME: We don't do .init separately.  To do this, we'd need to have
31
   a separate r2 value in the init and core section, and stub between
32
   them, too.
33
 
34
   Using a magic allocator which places modules within 32MB solves
35
   this, and makes other things simpler.  Anton?
36
   --RR.  */
37
#if 0
38
#define DEBUGP printk
39
#else
40
#define DEBUGP(fmt , ...)
41
#endif
42
 
43
/* There's actually a third entry here, but it's unused */
44
struct ppc64_opd_entry
45
{
46
        unsigned long funcaddr;
47
        unsigned long r2;
48
};
49
 
50
/* Like PPC32, we need little trampolines to do > 24-bit jumps (into
51
   the kernel itself).  But on PPC64, these need to be used for every
52
   jump, actually, to reset r2 (TOC+0x8000). */
53
struct ppc64_stub_entry
54
{
55
        /* 28 byte jump instruction sequence (7 instructions) */
56
        unsigned char jump[28];
57
        unsigned char unused[4];
58
        /* Data for the above code */
59
        struct ppc64_opd_entry opd;
60
};
61
 
62
/* We use a stub to fix up r2 (TOC ptr) and to jump to the (external)
63
   function which may be more than 24-bits away.  We could simply
64
   patch the new r2 value and function pointer into the stub, but it's
65
   significantly shorter to put these values at the end of the stub
66
   code, and patch the stub address (32-bits relative to the TOC ptr,
67
   r2) into the stub. */
68
static struct ppc64_stub_entry ppc64_stub =
69
{ .jump = {
70
        0x3d, 0x82, 0x00, 0x00, /* addis   r12,r2, <high> */
71
        0x39, 0x8c, 0x00, 0x00, /* addi    r12,r12, <low> */
72
        /* Save current r2 value in magic place on the stack. */
73
        0xf8, 0x41, 0x00, 0x28, /* std     r2,40(r1) */
74
        0xe9, 0x6c, 0x00, 0x20, /* ld      r11,32(r12) */
75
        0xe8, 0x4c, 0x00, 0x28, /* ld      r2,40(r12) */
76
        0x7d, 0x69, 0x03, 0xa6, /* mtctr   r11 */
77
        0x4e, 0x80, 0x04, 0x20  /* bctr */
78
} };
79
 
80
/* Count how many different 24-bit relocations (different symbol,
81
   different addend) */
82
static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num)
83
{
84
        unsigned int i, j, ret = 0;
85
 
86
        /* FIXME: Only count external ones --RR */
87
        /* Sure, this is order(n^2), but it's usually short, and not
88
           time critical */
89
        for (i = 0; i < num; i++) {
90
                /* Only count 24-bit relocs, others don't need stubs */
91
                if (ELF64_R_TYPE(rela[i].r_info) != R_PPC_REL24)
92
                        continue;
93
                for (j = 0; j < i; j++) {
94
                        /* If this addend appeared before, it's
95
                           already been counted */
96
                        if (rela[i].r_info == rela[j].r_info
97
                            && rela[i].r_addend == rela[j].r_addend)
98
                                break;
99
                }
100
                if (j == i) ret++;
101
        }
102
        return ret;
103
}
104
 
105
void *module_alloc(unsigned long size)
106
{
107
        if (size == 0)
108
                return NULL;
109
 
110
        return vmalloc_exec(size);
111
}
112
 
113
/* Free memory returned from module_alloc */
114
void module_free(struct module *mod, void *module_region)
115
{
116
        vfree(module_region);
117
        /* FIXME: If module_region == mod->init_region, trim exception
118
           table entries. */
119
}
120
 
121
/* Get size of potential trampolines required. */
122
static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
123
                                    const Elf64_Shdr *sechdrs)
124
{
125
        /* One extra reloc so it's always 0-funcaddr terminated */
126
        unsigned long relocs = 1;
127
        unsigned i;
128
 
129
        /* Every relocated section... */
130
        for (i = 1; i < hdr->e_shnum; i++) {
131
                if (sechdrs[i].sh_type == SHT_RELA) {
132
                        DEBUGP("Found relocations in section %u\n", i);
133
                        DEBUGP("Ptr: %p.  Number: %lu\n",
134
                               (void *)sechdrs[i].sh_addr,
135
                               sechdrs[i].sh_size / sizeof(Elf64_Rela));
136
                        relocs += count_relocs((void *)sechdrs[i].sh_addr,
137
                                               sechdrs[i].sh_size
138
                                               / sizeof(Elf64_Rela));
139
                }
140
        }
141
 
142
        DEBUGP("Looks like a total of %lu stubs, max\n", relocs);
143
        return relocs * sizeof(struct ppc64_stub_entry);
144
}
145
 
146
static void dedotify_versions(struct modversion_info *vers,
147
                              unsigned long size)
148
{
149
        struct modversion_info *end;
150
 
151
        for (end = (void *)vers + size; vers < end; vers++)
152
                if (vers->name[0] == '.')
153
                        memmove(vers->name, vers->name+1, strlen(vers->name));
154
}
155
 
156
/* Undefined symbols which refer to .funcname, hack to funcname */
157
static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
158
{
159
        unsigned int i;
160
 
161
        for (i = 1; i < numsyms; i++) {
162
                if (syms[i].st_shndx == SHN_UNDEF) {
163
                        char *name = strtab + syms[i].st_name;
164
                        if (name[0] == '.')
165
                                memmove(name, name+1, strlen(name));
166
                }
167
        }
168
}
169
 
170
int module_frob_arch_sections(Elf64_Ehdr *hdr,
171
                              Elf64_Shdr *sechdrs,
172
                              char *secstrings,
173
                              struct module *me)
174
{
175
        unsigned int i;
176
 
177
        /* Find .toc and .stubs sections, symtab and strtab */
178
        for (i = 1; i < hdr->e_shnum; i++) {
179
                char *p;
180
                if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0)
181
                        me->arch.stubs_section = i;
182
                else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0)
183
                        me->arch.toc_section = i;
184
                else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
185
                        dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
186
                                          sechdrs[i].sh_size);
187
 
188
                /* We don't handle .init for the moment: rename to _init */
189
                while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init")))
190
                        p[0] = '_';
191
 
192
                if (sechdrs[i].sh_type == SHT_SYMTAB)
193
                        dedotify((void *)hdr + sechdrs[i].sh_offset,
194
                                 sechdrs[i].sh_size / sizeof(Elf64_Sym),
195
                                 (void *)hdr
196
                                 + sechdrs[sechdrs[i].sh_link].sh_offset);
197
        }
198
 
199
        if (!me->arch.stubs_section) {
200
                printk("%s: doesn't contain .stubs.\n", me->name);
201
                return -ENOEXEC;
202
        }
203
 
204
        /* If we don't have a .toc, just use .stubs.  We need to set r2
205
           to some reasonable value in case the module calls out to
206
           other functions via a stub, or if a function pointer escapes
207
           the module by some means.  */
208
        if (!me->arch.toc_section)
209
                me->arch.toc_section = me->arch.stubs_section;
210
 
211
        /* Override the stubs size */
212
        sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs);
213
        return 0;
214
}
215
 
216
int apply_relocate(Elf64_Shdr *sechdrs,
217
                   const char *strtab,
218
                   unsigned int symindex,
219
                   unsigned int relsec,
220
                   struct module *me)
221
{
222
        printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n", me->name);
223
        return -ENOEXEC;
224
}
225
 
226
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
227
   gives the value maximum span in an instruction which uses a signed
228
   offset) */
229
static inline unsigned long my_r2(Elf64_Shdr *sechdrs, struct module *me)
230
{
231
        return sechdrs[me->arch.toc_section].sh_addr + 0x8000;
232
}
233
 
234
/* Both low and high 16 bits are added as SIGNED additions, so if low
235
   16 bits has high bit set, high 16 bits must be adjusted.  These
236
   macros do that (stolen from binutils). */
237
#define PPC_LO(v) ((v) & 0xffff)
238
#define PPC_HI(v) (((v) >> 16) & 0xffff)
239
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
240
 
241
/* Patch stub to reference function and correct r2 value. */
242
static inline int create_stub(Elf64_Shdr *sechdrs,
243
                              struct ppc64_stub_entry *entry,
244
                              struct ppc64_opd_entry *opd,
245
                              struct module *me)
246
{
247
        Elf64_Half *loc1, *loc2;
248
        long reladdr;
249
 
250
        *entry = ppc64_stub;
251
 
252
        loc1 = (Elf64_Half *)&entry->jump[2];
253
        loc2 = (Elf64_Half *)&entry->jump[6];
254
 
255
        /* Stub uses address relative to r2. */
256
        reladdr = (unsigned long)entry - my_r2(sechdrs, me);
257
        if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
258
                printk("%s: Address %p of stub out of range of %p.\n",
259
                       me->name, (void *)reladdr, (void *)my_r2);
260
                return 0;
261
        }
262
        DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr);
263
 
264
        *loc1 = PPC_HA(reladdr);
265
        *loc2 = PPC_LO(reladdr);
266
        entry->opd.funcaddr = opd->funcaddr;
267
        entry->opd.r2 = opd->r2;
268
        return 1;
269
}
270
 
271
/* Create stub to jump to function described in this OPD: we need the
272
   stub to set up the TOC ptr (r2) for the function. */
273
static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
274
                                   unsigned long opdaddr,
275
                                   struct module *me)
276
{
277
        struct ppc64_stub_entry *stubs;
278
        struct ppc64_opd_entry *opd = (void *)opdaddr;
279
        unsigned int i, num_stubs;
280
 
281
        num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs);
282
 
283
        /* Find this stub, or if that fails, the next avail. entry */
284
        stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr;
285
        for (i = 0; stubs[i].opd.funcaddr; i++) {
286
                BUG_ON(i >= num_stubs);
287
 
288
                if (stubs[i].opd.funcaddr == opd->funcaddr)
289
                        return (unsigned long)&stubs[i];
290
        }
291
 
292
        if (!create_stub(sechdrs, &stubs[i], opd, me))
293
                return 0;
294
 
295
        return (unsigned long)&stubs[i];
296
}
297
 
298
/* We expect a noop next: if it is, replace it with instruction to
299
   restore r2. */
300
static int restore_r2(u32 *instruction, struct module *me)
301
{
302
        if (*instruction != 0x60000000) {
303
                printk("%s: Expect noop after relocate, got %08x\n",
304
                       me->name, *instruction);
305
                return 0;
306
        }
307
        *instruction = 0xe8410028;      /* ld r2,40(r1) */
308
        return 1;
309
}
310
 
311
int apply_relocate_add(Elf64_Shdr *sechdrs,
312
                       const char *strtab,
313
                       unsigned int symindex,
314
                       unsigned int relsec,
315
                       struct module *me)
316
{
317
        unsigned int i;
318
        Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
319
        Elf64_Sym *sym;
320
        unsigned long *location;
321
        unsigned long value;
322
 
323
        DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
324
               sechdrs[relsec].sh_info);
325
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
326
                /* This is where to make the change */
327
                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
328
                        + rela[i].r_offset;
329
                /* This is the symbol it is referring to */
330
                sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
331
                        + ELF64_R_SYM(rela[i].r_info);
332
 
333
                DEBUGP("RELOC at %p: %li-type as %s (%lu) + %li\n",
334
                       location, (long)ELF64_R_TYPE(rela[i].r_info),
335
                       strtab + sym->st_name, (unsigned long)sym->st_value,
336
                       (long)rela[i].r_addend);
337
 
338
                /* `Everything is relative'. */
339
                value = sym->st_value + rela[i].r_addend;
340
 
341
                switch (ELF64_R_TYPE(rela[i].r_info)) {
342
                case R_PPC64_ADDR32:
343
                        /* Simply set it */
344
                        *(u32 *)location = value;
345
                        break;
346
 
347
                case R_PPC64_ADDR64:
348
                        /* Simply set it */
349
                        *(unsigned long *)location = value;
350
                        break;
351
 
352
                case R_PPC64_TOC:
353
                        *(unsigned long *)location = my_r2(sechdrs, me);
354
                        break;
355
 
356
                case R_PPC64_TOC16:
357
                        /* Subtract TOC pointer */
358
                        value -= my_r2(sechdrs, me);
359
                        if (value + 0x8000 > 0xffff) {
360
                                printk("%s: bad TOC16 relocation (%lu)\n",
361
                                       me->name, value);
362
                                return -ENOEXEC;
363
                        }
364
                        *((uint16_t *) location)
365
                                = (*((uint16_t *) location) & ~0xffff)
366
                                | (value & 0xffff);
367
                        break;
368
 
369
                case R_PPC64_TOC16_DS:
370
                        /* Subtract TOC pointer */
371
                        value -= my_r2(sechdrs, me);
372
                        if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
373
                                printk("%s: bad TOC16_DS relocation (%lu)\n",
374
                                       me->name, value);
375
                                return -ENOEXEC;
376
                        }
377
                        *((uint16_t *) location)
378
                                = (*((uint16_t *) location) & ~0xfffc)
379
                                | (value & 0xfffc);
380
                        break;
381
 
382
                case R_PPC_REL24:
383
                        /* FIXME: Handle weak symbols here --RR */
384
                        if (sym->st_shndx == SHN_UNDEF) {
385
                                /* External: go via stub */
386
                                value = stub_for_addr(sechdrs, value, me);
387
                                if (!value)
388
                                        return -ENOENT;
389
                                if (!restore_r2((u32 *)location + 1, me))
390
                                        return -ENOEXEC;
391
                        }
392
 
393
                        /* Convert value to relative */
394
                        value -= (unsigned long)location;
395
                        if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
396
                                printk("%s: REL24 %li out of range!\n",
397
                                       me->name, (long int)value);
398
                                return -ENOEXEC;
399
                        }
400
 
401
                        /* Only replace bits 2 through 26 */
402
                        *(uint32_t *)location
403
                                = (*(uint32_t *)location & ~0x03fffffc)
404
                                | (value & 0x03fffffc);
405
                        break;
406
 
407
                case R_PPC64_REL64:
408
                        /* 64 bits relative (used by features fixups) */
409
                        *location = value - (unsigned long)location;
410
                        break;
411
 
412
                default:
413
                        printk("%s: Unknown ADD relocation: %lu\n",
414
                               me->name,
415
                               (unsigned long)ELF64_R_TYPE(rela[i].r_info));
416
                        return -ENOEXEC;
417
                }
418
        }
419
 
420
        return 0;
421
}
422
 
423
LIST_HEAD(module_bug_list);
424
 
425
static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
426
                                    const Elf_Shdr *sechdrs,
427
                                    const char *name)
428
{
429
        char *secstrings;
430
        unsigned int i;
431
 
432
        secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
433
        for (i = 1; i < hdr->e_shnum; i++)
434
                if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
435
                        return &sechdrs[i];
436
        return NULL;
437
}
438
 
439
int module_finalize(const Elf_Ehdr *hdr,
440
                const Elf_Shdr *sechdrs, struct module *me)
441
{
442
        const Elf_Shdr *sect;
443
        int err;
444
 
445
        err = module_bug_finalize(hdr, sechdrs, me);
446
        if (err)
447
                return err;
448
 
449
        /* Apply feature fixups */
450
        sect = find_section(hdr, sechdrs, "__ftr_fixup");
451
        if (sect != NULL)
452
                do_feature_fixups(cur_cpu_spec->cpu_features,
453
                                  (void *)sect->sh_addr,
454
                                  (void *)sect->sh_addr + sect->sh_size);
455
 
456
        sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
457
        if (sect != NULL)
458
                do_feature_fixups(powerpc_firmware_features,
459
                                  (void *)sect->sh_addr,
460
                                  (void *)sect->sh_addr + sect->sh_size);
461
 
462
        return 0;
463
}
464
 
465
void module_arch_cleanup(struct module *mod)
466
{
467
        module_bug_cleanup(mod);
468
}
469
 
470
struct bug_entry *module_find_bug(unsigned long bugaddr)
471
{
472
        struct mod_arch_specific *mod;
473
        unsigned int i;
474
        struct bug_entry *bug;
475
 
476
        list_for_each_entry(mod, &module_bug_list, bug_list) {
477
                bug = mod->bug_table;
478
                for (i = 0; i < mod->num_bugs; ++i, ++bug)
479
                        if (bugaddr == bug->bug_addr)
480
                                return bug;
481
        }
482
        return NULL;
483
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.