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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [arch/] [s390/] [kernel/] [module.c] - Blame information for rev 63

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 63 marcus.erl
/*
2
 *  arch/s390/kernel/module.c - Kernel module help for s390.
3
 *
4
 *  S390 version
5
 *    Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
6
 *                             IBM Corporation
7
 *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
8
 *               Martin Schwidefsky (schwidefsky@de.ibm.com)
9
 *
10
 *  based on i386 version
11
 *    Copyright (C) 2001 Rusty Russell.
12
 *
13
 *  This program is free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 2 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  This program is distributed in the hope that it will be useful,
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 *  GNU General Public License for more details.
22
 *
23
 *  You should have received a copy of the GNU General Public License
24
 *  along with this program; if not, write to the Free Software
25
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27
#include <linux/module.h>
28
#include <linux/elf.h>
29
#include <linux/vmalloc.h>
30
#include <linux/fs.h>
31
#include <linux/string.h>
32
#include <linux/kernel.h>
33
#include <linux/moduleloader.h>
34
#include <linux/bug.h>
35
 
36
#if 0
37
#define DEBUGP printk
38
#else
39
#define DEBUGP(fmt , ...)
40
#endif
41
 
42
#ifndef CONFIG_64BIT
43
#define PLT_ENTRY_SIZE 12
44
#else /* CONFIG_64BIT */
45
#define PLT_ENTRY_SIZE 20
46
#endif /* CONFIG_64BIT */
47
 
48
void *module_alloc(unsigned long size)
49
{
50
        if (size == 0)
51
                return NULL;
52
        return vmalloc(size);
53
}
54
 
55
/* Free memory returned from module_alloc */
56
void module_free(struct module *mod, void *module_region)
57
{
58
        vfree(module_region);
59
        /* FIXME: If module_region == mod->init_region, trim exception
60
           table entries. */
61
}
62
 
63
static void
64
check_rela(Elf_Rela *rela, struct module *me)
65
{
66
        struct mod_arch_syminfo *info;
67
 
68
        info = me->arch.syminfo + ELF_R_SYM (rela->r_info);
69
        switch (ELF_R_TYPE (rela->r_info)) {
70
        case R_390_GOT12:       /* 12 bit GOT offset.  */
71
        case R_390_GOT16:       /* 16 bit GOT offset.  */
72
        case R_390_GOT20:       /* 20 bit GOT offset.  */
73
        case R_390_GOT32:       /* 32 bit GOT offset.  */
74
        case R_390_GOT64:       /* 64 bit GOT offset.  */
75
        case R_390_GOTENT:      /* 32 bit PC rel. to GOT entry shifted by 1. */
76
        case R_390_GOTPLT12:    /* 12 bit offset to jump slot.  */
77
        case R_390_GOTPLT16:    /* 16 bit offset to jump slot.  */
78
        case R_390_GOTPLT20:    /* 20 bit offset to jump slot.  */
79
        case R_390_GOTPLT32:    /* 32 bit offset to jump slot.  */
80
        case R_390_GOTPLT64:    /* 64 bit offset to jump slot.  */
81
        case R_390_GOTPLTENT:   /* 32 bit rel. offset to jump slot >> 1. */
82
                if (info->got_offset == -1UL) {
83
                        info->got_offset = me->arch.got_size;
84
                        me->arch.got_size += sizeof(void*);
85
                }
86
                break;
87
        case R_390_PLT16DBL:    /* 16 bit PC rel. PLT shifted by 1.  */
88
        case R_390_PLT32DBL:    /* 32 bit PC rel. PLT shifted by 1.  */
89
        case R_390_PLT32:       /* 32 bit PC relative PLT address.  */
90
        case R_390_PLT64:       /* 64 bit PC relative PLT address.  */
91
        case R_390_PLTOFF16:    /* 16 bit offset from GOT to PLT. */
92
        case R_390_PLTOFF32:    /* 32 bit offset from GOT to PLT. */
93
        case R_390_PLTOFF64:    /* 16 bit offset from GOT to PLT. */
94
                if (info->plt_offset == -1UL) {
95
                        info->plt_offset = me->arch.plt_size;
96
                        me->arch.plt_size += PLT_ENTRY_SIZE;
97
                }
98
                break;
99
        case R_390_COPY:
100
        case R_390_GLOB_DAT:
101
        case R_390_JMP_SLOT:
102
        case R_390_RELATIVE:
103
                /* Only needed if we want to support loading of
104
                   modules linked with -shared. */
105
                break;
106
        }
107
}
108
 
109
/*
110
 * Account for GOT and PLT relocations. We can't add sections for
111
 * got and plt but we can increase the core module size.
112
 */
113
int
114
module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
115
                          char *secstrings, struct module *me)
116
{
117
        Elf_Shdr *symtab;
118
        Elf_Sym *symbols;
119
        Elf_Rela *rela;
120
        char *strings;
121
        int nrela, i, j;
122
 
123
        /* Find symbol table and string table. */
124
        symtab = NULL;
125
        for (i = 0; i < hdr->e_shnum; i++)
126
                switch (sechdrs[i].sh_type) {
127
                case SHT_SYMTAB:
128
                        symtab = sechdrs + i;
129
                        break;
130
                }
131
        if (!symtab) {
132
                printk(KERN_ERR "module %s: no symbol table\n", me->name);
133
                return -ENOEXEC;
134
        }
135
 
136
        /* Allocate one syminfo structure per symbol. */
137
        me->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
138
        me->arch.syminfo = vmalloc(me->arch.nsyms *
139
                                   sizeof(struct mod_arch_syminfo));
140
        if (!me->arch.syminfo)
141
                return -ENOMEM;
142
        symbols = (void *) hdr + symtab->sh_offset;
143
        strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset;
144
        for (i = 0; i < me->arch.nsyms; i++) {
145
                if (symbols[i].st_shndx == SHN_UNDEF &&
146
                    strcmp(strings + symbols[i].st_name,
147
                           "_GLOBAL_OFFSET_TABLE_") == 0)
148
                        /* "Define" it as absolute. */
149
                        symbols[i].st_shndx = SHN_ABS;
150
                me->arch.syminfo[i].got_offset = -1UL;
151
                me->arch.syminfo[i].plt_offset = -1UL;
152
                me->arch.syminfo[i].got_initialized = 0;
153
                me->arch.syminfo[i].plt_initialized = 0;
154
        }
155
 
156
        /* Search for got/plt relocations. */
157
        me->arch.got_size = me->arch.plt_size = 0;
158
        for (i = 0; i < hdr->e_shnum; i++) {
159
                if (sechdrs[i].sh_type != SHT_RELA)
160
                        continue;
161
                nrela = sechdrs[i].sh_size / sizeof(Elf_Rela);
162
                rela = (void *) hdr + sechdrs[i].sh_offset;
163
                for (j = 0; j < nrela; j++)
164
                        check_rela(rela + j, me);
165
        }
166
 
167
        /* Increase core size by size of got & plt and set start
168
           offsets for got and plt. */
169
        me->core_size = ALIGN(me->core_size, 4);
170
        me->arch.got_offset = me->core_size;
171
        me->core_size += me->arch.got_size;
172
        me->arch.plt_offset = me->core_size;
173
        me->core_size += me->arch.plt_size;
174
        return 0;
175
}
176
 
177
int
178
apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
179
               unsigned int relsec, struct module *me)
180
{
181
        printk(KERN_ERR "module %s: RELOCATION unsupported\n",
182
               me->name);
183
        return -ENOEXEC;
184
}
185
 
186
static int
187
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
188
           struct module *me)
189
{
190
        struct mod_arch_syminfo *info;
191
        Elf_Addr loc, val;
192
        int r_type, r_sym;
193
 
194
        /* This is where to make the change */
195
        loc = base + rela->r_offset;
196
        /* This is the symbol it is referring to.  Note that all
197
           undefined symbols have been resolved.  */
198
        r_sym = ELF_R_SYM(rela->r_info);
199
        r_type = ELF_R_TYPE(rela->r_info);
200
        info = me->arch.syminfo + r_sym;
201
        val = symtab[r_sym].st_value;
202
 
203
        switch (r_type) {
204
        case R_390_8:           /* Direct 8 bit.   */
205
        case R_390_12:          /* Direct 12 bit.  */
206
        case R_390_16:          /* Direct 16 bit.  */
207
        case R_390_20:          /* Direct 20 bit.  */
208
        case R_390_32:          /* Direct 32 bit.  */
209
        case R_390_64:          /* Direct 64 bit.  */
210
                val += rela->r_addend;
211
                if (r_type == R_390_8)
212
                        *(unsigned char *) loc = val;
213
                else if (r_type == R_390_12)
214
                        *(unsigned short *) loc = (val & 0xfff) |
215
                                (*(unsigned short *) loc & 0xf000);
216
                else if (r_type == R_390_16)
217
                        *(unsigned short *) loc = val;
218
                else if (r_type == R_390_20)
219
                        *(unsigned int *) loc =
220
                                (*(unsigned int *) loc & 0xf00000ff) |
221
                                (val & 0xfff) << 16 | (val & 0xff000) >> 4;
222
                else if (r_type == R_390_32)
223
                        *(unsigned int *) loc = val;
224
                else if (r_type == R_390_64)
225
                        *(unsigned long *) loc = val;
226
                break;
227
        case R_390_PC16:        /* PC relative 16 bit.  */
228
        case R_390_PC16DBL:     /* PC relative 16 bit shifted by 1.  */
229
        case R_390_PC32DBL:     /* PC relative 32 bit shifted by 1.  */
230
        case R_390_PC32:        /* PC relative 32 bit.  */
231
        case R_390_PC64:        /* PC relative 64 bit.  */
232
                val += rela->r_addend - loc;
233
                if (r_type == R_390_PC16)
234
                        *(unsigned short *) loc = val;
235
                else if (r_type == R_390_PC16DBL)
236
                        *(unsigned short *) loc = val >> 1;
237
                else if (r_type == R_390_PC32DBL)
238
                        *(unsigned int *) loc = val >> 1;
239
                else if (r_type == R_390_PC32)
240
                        *(unsigned int *) loc = val;
241
                else if (r_type == R_390_PC64)
242
                        *(unsigned long *) loc = val;
243
                break;
244
        case R_390_GOT12:       /* 12 bit GOT offset.  */
245
        case R_390_GOT16:       /* 16 bit GOT offset.  */
246
        case R_390_GOT20:       /* 20 bit GOT offset.  */
247
        case R_390_GOT32:       /* 32 bit GOT offset.  */
248
        case R_390_GOT64:       /* 64 bit GOT offset.  */
249
        case R_390_GOTENT:      /* 32 bit PC rel. to GOT entry shifted by 1. */
250
        case R_390_GOTPLT12:    /* 12 bit offset to jump slot.  */
251
        case R_390_GOTPLT20:    /* 20 bit offset to jump slot.  */
252
        case R_390_GOTPLT16:    /* 16 bit offset to jump slot.  */
253
        case R_390_GOTPLT32:    /* 32 bit offset to jump slot.  */
254
        case R_390_GOTPLT64:    /* 64 bit offset to jump slot.  */
255
        case R_390_GOTPLTENT:   /* 32 bit rel. offset to jump slot >> 1. */
256
                if (info->got_initialized == 0) {
257
                        Elf_Addr *gotent;
258
 
259
                        gotent = me->module_core + me->arch.got_offset +
260
                                info->got_offset;
261
                        *gotent = val;
262
                        info->got_initialized = 1;
263
                }
264
                val = info->got_offset + rela->r_addend;
265
                if (r_type == R_390_GOT12 ||
266
                    r_type == R_390_GOTPLT12)
267
                        *(unsigned short *) loc = (val & 0xfff) |
268
                                (*(unsigned short *) loc & 0xf000);
269
                else if (r_type == R_390_GOT16 ||
270
                         r_type == R_390_GOTPLT16)
271
                        *(unsigned short *) loc = val;
272
                else if (r_type == R_390_GOT20 ||
273
                         r_type == R_390_GOTPLT20)
274
                        *(unsigned int *) loc =
275
                                (*(unsigned int *) loc & 0xf00000ff) |
276
                                (val & 0xfff) << 16 | (val & 0xff000) >> 4;
277
                else if (r_type == R_390_GOT32 ||
278
                         r_type == R_390_GOTPLT32)
279
                        *(unsigned int *) loc = val;
280
                else if (r_type == R_390_GOTENT ||
281
                         r_type == R_390_GOTPLTENT)
282
                        *(unsigned int *) loc =
283
                                (val + (Elf_Addr) me->module_core - loc) >> 1;
284
                else if (r_type == R_390_GOT64 ||
285
                         r_type == R_390_GOTPLT64)
286
                        *(unsigned long *) loc = val;
287
                break;
288
        case R_390_PLT16DBL:    /* 16 bit PC rel. PLT shifted by 1.  */
289
        case R_390_PLT32DBL:    /* 32 bit PC rel. PLT shifted by 1.  */
290
        case R_390_PLT32:       /* 32 bit PC relative PLT address.  */
291
        case R_390_PLT64:       /* 64 bit PC relative PLT address.  */
292
        case R_390_PLTOFF16:    /* 16 bit offset from GOT to PLT. */
293
        case R_390_PLTOFF32:    /* 32 bit offset from GOT to PLT. */
294
        case R_390_PLTOFF64:    /* 16 bit offset from GOT to PLT. */
295
                if (info->plt_initialized == 0) {
296
                        unsigned int *ip;
297
                        ip = me->module_core + me->arch.plt_offset +
298
                                info->plt_offset;
299
#ifndef CONFIG_64BIT
300
                        ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */
301
                        ip[1] = 0x100607f1;
302
                        ip[2] = val;
303
#else /* CONFIG_64BIT */
304
                        ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
305
                        ip[1] = 0x100a0004;
306
                        ip[2] = 0x07f10000;
307
                        ip[3] = (unsigned int) (val >> 32);
308
                        ip[4] = (unsigned int) val;
309
#endif /* CONFIG_64BIT */
310
                        info->plt_initialized = 1;
311
                }
312
                if (r_type == R_390_PLTOFF16 ||
313
                    r_type == R_390_PLTOFF32
314
                    || r_type == R_390_PLTOFF64
315
                        )
316
                        val = me->arch.plt_offset - me->arch.got_offset +
317
                                info->plt_offset + rela->r_addend;
318
                else
319
                        val =  (Elf_Addr) me->module_core +
320
                                me->arch.plt_offset + info->plt_offset +
321
                                rela->r_addend - loc;
322
                if (r_type == R_390_PLT16DBL)
323
                        *(unsigned short *) loc = val >> 1;
324
                else if (r_type == R_390_PLTOFF16)
325
                        *(unsigned short *) loc = val;
326
                else if (r_type == R_390_PLT32DBL)
327
                        *(unsigned int *) loc = val >> 1;
328
                else if (r_type == R_390_PLT32 ||
329
                         r_type == R_390_PLTOFF32)
330
                        *(unsigned int *) loc = val;
331
                else if (r_type == R_390_PLT64 ||
332
                         r_type == R_390_PLTOFF64)
333
                        *(unsigned long *) loc = val;
334
                break;
335
        case R_390_GOTOFF16:    /* 16 bit offset to GOT.  */
336
        case R_390_GOTOFF32:    /* 32 bit offset to GOT.  */
337
        case R_390_GOTOFF64:    /* 64 bit offset to GOT. */
338
                val = val + rela->r_addend -
339
                        ((Elf_Addr) me->module_core + me->arch.got_offset);
340
                if (r_type == R_390_GOTOFF16)
341
                        *(unsigned short *) loc = val;
342
                else if (r_type == R_390_GOTOFF32)
343
                        *(unsigned int *) loc = val;
344
                else if (r_type == R_390_GOTOFF64)
345
                        *(unsigned long *) loc = val;
346
                break;
347
        case R_390_GOTPC:       /* 32 bit PC relative offset to GOT. */
348
        case R_390_GOTPCDBL:    /* 32 bit PC rel. off. to GOT shifted by 1. */
349
                val = (Elf_Addr) me->module_core + me->arch.got_offset +
350
                        rela->r_addend - loc;
351
                if (r_type == R_390_GOTPC)
352
                        *(unsigned int *) loc = val;
353
                else if (r_type == R_390_GOTPCDBL)
354
                        *(unsigned int *) loc = val >> 1;
355
                break;
356
        case R_390_COPY:
357
        case R_390_GLOB_DAT:    /* Create GOT entry.  */
358
        case R_390_JMP_SLOT:    /* Create PLT entry.  */
359
        case R_390_RELATIVE:    /* Adjust by program base.  */
360
                /* Only needed if we want to support loading of
361
                   modules linked with -shared. */
362
                break;
363
        default:
364
                printk(KERN_ERR "module %s: Unknown relocation: %u\n",
365
                       me->name, r_type);
366
                return -ENOEXEC;
367
        }
368
        return 0;
369
}
370
 
371
int
372
apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
373
                   unsigned int symindex, unsigned int relsec,
374
                   struct module *me)
375
{
376
        Elf_Addr base;
377
        Elf_Sym *symtab;
378
        Elf_Rela *rela;
379
        unsigned long i, n;
380
        int rc;
381
 
382
        DEBUGP("Applying relocate section %u to %u\n",
383
               relsec, sechdrs[relsec].sh_info);
384
        base = sechdrs[sechdrs[relsec].sh_info].sh_addr;
385
        symtab = (Elf_Sym *) sechdrs[symindex].sh_addr;
386
        rela = (Elf_Rela *) sechdrs[relsec].sh_addr;
387
        n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
388
 
389
        for (i = 0; i < n; i++, rela++) {
390
                rc = apply_rela(rela, base, symtab, me);
391
                if (rc)
392
                        return rc;
393
        }
394
        return 0;
395
}
396
 
397
int module_finalize(const Elf_Ehdr *hdr,
398
                    const Elf_Shdr *sechdrs,
399
                    struct module *me)
400
{
401
        vfree(me->arch.syminfo);
402
        return module_bug_finalize(hdr, sechdrs, me);
403
}
404
 
405
void module_arch_cleanup(struct module *mod)
406
{
407
        module_bug_cleanup(mod);
408
}

powered by: WebSVN 2.1.0

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