source: src/linux/ar531x/linux-2.6.23/arch/mips/kernel/module.c @ 12400

Last change on this file since 12400 was 12400, checked in by BrainSlayer, 4 years ago

more flexible EOC5610 partition layout, small performance increase by module remapping, lzma decoder speed improvements

File size: 15.3 KB
Line 
1/*
2 *  This program is free software; you can redistribute it and/or modify
3 *  it under the terms of the GNU General Public License as published by
4 *  the Free Software Foundation; either version 2 of the License, or
5 *  (at your option) any later version.
6 *
7 *  This program is distributed in the hope that it will be useful,
8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *  GNU General Public License for more details.
11 *
12 *  You should have received a copy of the GNU General Public License
13 *  along with this program; if not, write to the Free Software
14 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15 *
16 *  Copyright (C) 2001 Rusty Russell.
17 *  Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
18 *  Copyright (C) 2005 Thiemo Seufer
19 */
20
21#undef DEBUG
22
23#include <linux/moduleloader.h>
24#include <linux/elf.h>
25#include <linux/vmalloc.h>
26#include <linux/slab.h>
27#include <linux/fs.h>
28#include <linux/string.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/spinlock.h>
32#include <linux/mm.h>
33#include <asm/pgtable.h>        /* MODULE_START */
34
35struct mips_hi16 {
36        struct mips_hi16 *next;
37        Elf_Addr *addr;
38        Elf_Addr value;
39};
40
41static struct mips_hi16 *mips_hi16_list;
42
43static LIST_HEAD(dbe_list);
44static DEFINE_SPINLOCK(dbe_lock);
45
46static void *alloc_phys(unsigned long size)
47{
48        unsigned order;
49        struct page *page;
50        struct page *p;
51
52        size = PAGE_ALIGN(size);
53        order = get_order(size);
54
55        page = alloc_pages(
56                GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | __GFP_THISNODE,
57                order);
58        if (!page)
59                return 0;
60
61        split_page(page, order);
62
63        for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
64                __free_page(p);
65
66        return page_address(page);
67}
68
69static void free_phys(void *ptr, unsigned long size)
70{
71        struct page *page;
72        struct page *end;
73
74        page = virt_to_page(ptr);
75        end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);
76
77        for (; page < end; ++page)
78                __free_pages(page, 0);
79}
80
81void *module_alloc(unsigned long size)
82{
83#ifdef MODULE_START
84        struct vm_struct *area;
85
86        size = PAGE_ALIGN(size);
87        if (!size)
88                return NULL;
89
90        area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END);
91        if (!area)
92                return NULL;
93
94        return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
95#else
96        unsigned addr;
97        void *ptr;
98
99        size = PAGE_ALIGN(size);
100        if (size == 0)
101                return NULL;
102
103        ptr = alloc_phys(size);
104        if (ptr)
105                return ptr;
106
107        /* try to allocate contiguos chunk of memory not spanning 256Mb
108           range, so all jump instructions can work */
109        addr = VMALLOC_START;
110        while (addr < VMALLOC_END) {
111                unsigned end = ALIGN(addr + 1, 1u << 28);
112
113                if (addr + size <= end) {
114                        struct vm_struct *area
115                                = __get_vm_area(size, VM_ALLOC, addr, end);
116
117                        if (area)
118                                return __vmalloc_area(
119                                        area, GFP_KERNEL, PAGE_KERNEL);
120                }
121                addr = end;
122        }
123        return NULL;
124#endif
125}
126
127static inline int is_phys(void *ptr)
128{
129        unsigned addr = (unsigned) ptr;
130        return addr && (addr < VMALLOC_START || addr > VMALLOC_END);
131}
132
133/* Free memory returned from module_alloc */
134void module_free(struct module *mod, void *module_region)
135{
136        if (is_phys(module_region)) {
137                if (mod->module_init == module_region)
138                        free_phys(module_region, mod->init_size);
139                else if (mod->module_core == module_region)
140                        free_phys(module_region, mod->core_size);
141                else
142                    BUG();
143                return;
144        }
145
146        vfree(module_region);
147        /* FIXME: If module_region == mod->init_region, trim exception
148           table entries. */
149}
150
151int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
152                              char *secstrings, struct module *mod)
153{
154        return 0;
155}
156
157/* Get the potential trampolines size required of the init and
158   non-init sections */
159static unsigned get_plt_size(const Elf32_Ehdr *hdr,
160                             const Elf32_Shdr *sechdrs,
161                             const char *secstrings,
162                             unsigned symindex,
163                             int is_init)
164{
165        unsigned long ret = 0;
166        unsigned i, j;
167        Elf_Sym *syms;
168
169        /* Everything marked ALLOC (this includes the exported symbols) */
170        for (i = 1; i < hdr->e_shnum; ++i) {
171                unsigned int info = sechdrs[i].sh_info;
172
173                if (sechdrs[i].sh_type != SHT_REL
174                    && sechdrs[i].sh_type != SHT_RELA)
175                        continue;
176
177                /* Not a valid relocation section? */
178                if (info >= hdr->e_shnum)
179                        continue;
180
181                /* Don't bother with non-allocated sections */
182                if (!(sechdrs[info].sh_flags & SHF_ALLOC))
183                        continue;
184
185                /* If it's called *.init*, and we're not init, we're
186                   not interested */
187                if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
188                    != is_init)
189                        continue;
190
191                syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
192                if (sechdrs[i].sh_type == SHT_REL) {
193                        Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
194                        unsigned size = sechdrs[i].sh_size / sizeof(*rel);
195
196                        for (j = 0; j < size; ++j) {
197                                Elf_Sym *sym;
198
199                                if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
200                                        continue;
201                                sym = syms + ELF_MIPS_R_SYM(rel[j]);
202                                if (!is_init && sym->st_shndx != SHN_UNDEF)
203                                        continue;
204
205                                ret += sizeof(unsigned[4]);
206                        }
207                } else {
208                        Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
209                        unsigned size = sechdrs[i].sh_size / sizeof(*rela);
210
211                        for (j = 0; j < size; ++j) {
212                                Elf_Sym *sym;
213
214                                if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
215                                        continue;
216                                sym = syms + ELF_MIPS_R_SYM(rela[j]);
217                                if (!is_init && sym->st_shndx != SHN_UNDEF)
218                                        continue;
219
220                                ret += sizeof(unsigned[4]);
221                        }
222                }
223
224        }
225
226        return ret;
227}
228
229int module_relayout(Elf32_Ehdr *hdr,
230                    Elf32_Shdr *sechdrs,
231                    char *secstrings,
232                    unsigned symindex,
233                    struct module *me)
234{
235        unsigned core_plt_size = get_plt_size(
236            hdr, sechdrs, secstrings, symindex, 0);
237        unsigned init_plt_size = get_plt_size(
238            hdr, sechdrs, secstrings, symindex, 1);
239
240        if (core_plt_size > 0)
241                me->core_size = PAGE_ALIGN(me->core_size);
242        me->arch.core_plt_offset = me->core_size;
243        me->core_size = me->core_size + core_plt_size;
244
245        me->arch.init_plt_offset = me->init_size;
246        me->init_size = me->init_size + init_plt_size;
247
248        return 0;
249}
250
251static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
252{
253        return 0;
254}
255
256static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
257{
258        *location += v;
259
260        return 0;
261}
262
263static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
264{
265        *location = v;
266
267        return 0;
268}
269
270static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
271                                 void *start, unsigned size, Elf_Addr v)
272{
273        unsigned *tramp = start + *plt_offset;
274        if (*plt_offset == size) return 0;
275
276        *plt_offset += sizeof(unsigned[4]);
277
278        /* adjust carry for addiu */
279        if (v & 0x00008000)
280                v += 0x10000;
281       
282        tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
283        tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
284        tramp[2] = 0x03200008;                  /* jr t9 */
285        tramp[3] = 0x00000000;                  /* nop */
286       
287        return (Elf_Addr) tramp;
288}
289
290static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
291{
292        if (location >= me->module_core
293            && location < me->module_core + me->core_size) {
294                return add_plt_entry_to(&me->arch.core_plt_offset,
295                                        me->module_core, me->core_size, v);
296        } else if (location > me->module_init
297                   && location < me->module_init + me->init_size) {
298                return add_plt_entry_to(&me->arch.init_plt_offset,
299                                        me->module_init, me->init_size, v);
300        } else {
301                printk(KERN_ERR "module %s: "
302                       "relocation to unknown segment %u\n",
303                       me->name, v);
304        }
305        return 0;
306}
307
308static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
309{
310        if (v % 4) {
311                printk(KERN_ERR "module %s: dangerous relocation\n", me->name);
312                return -ENOEXEC;
313        }
314
315        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
316                v = add_plt_entry(me, location,
317                                  v + ((*location & 0x03ffffff) << 2));
318                if (v == 0) {
319                printk(KERN_ERR
320                       "module %s: relocation overflow\n",
321                       me->name);
322                return -ENOEXEC;
323        }
324                *location = (*location & ~0x03ffffff) |
325                            ((v >> 2) & 0x03ffffff);
326                return 0;
327        }
328
329        *location = (*location & ~0x03ffffff) |
330                    ((*location + (v >> 2)) & 0x03ffffff);
331
332        return 0;
333}
334
335static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
336{
337        if (v % 4) {
338                printk(KERN_ERR "module %s: dangerous relocation\n", me->name);
339                return -ENOEXEC;
340        }
341
342        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
343                v = add_plt_entry(me, location, v);
344                if (v == 0) {
345                printk(KERN_ERR
346                       "module %s: relocation overflow\n",
347                       me->name);
348                return -ENOEXEC;
349        }
350        }
351
352        *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
353
354        return 0;
355}
356
357static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
358{
359        struct mips_hi16 *n;
360
361        /*
362         * We cannot relocate this one now because we don't know the value of
363         * the carry we need to add.  Save the information, and let LO16 do the
364         * actual relocation.
365         */
366        n = kmalloc(sizeof *n, GFP_KERNEL);
367        if (!n)
368                return -ENOMEM;
369
370        n->addr = (Elf_Addr *)location;
371        n->value = v;
372        n->next = mips_hi16_list;
373        mips_hi16_list = n;
374
375        return 0;
376}
377
378static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
379{
380        *location = (*location & 0xffff0000) |
381                    ((((long long) v + 0x8000LL) >> 16) & 0xffff);
382
383        return 0;
384}
385
386static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
387{
388        unsigned long insnlo = *location;
389        Elf_Addr val, vallo;
390
391        /* Sign extend the addend we extract from the lo insn.  */
392        vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
393
394        if (mips_hi16_list != NULL) {
395                struct mips_hi16 *l;
396
397                l = mips_hi16_list;
398                while (l != NULL) {
399                        struct mips_hi16 *next;
400                        unsigned long insn;
401
402                        /*
403                         * The value for the HI16 had best be the same.
404                         */
405                        if (v != l->value)
406                                goto out_danger;
407
408                        /*
409                         * Do the HI16 relocation.  Note that we actually don't
410                         * need to know anything about the LO16 itself, except
411                         * where to find the low 16 bits of the addend needed
412                         * by the LO16.
413                         */
414                        insn = *l->addr;
415                        val = ((insn & 0xffff) << 16) + vallo;
416                        val += v;
417
418                        /*
419                         * Account for the sign extension that will happen in
420                         * the low bits.
421                         */
422                        val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
423
424                        insn = (insn & ~0xffff) | val;
425                        *l->addr = insn;
426
427                        next = l->next;
428                        kfree(l);
429                        l = next;
430                }
431
432                mips_hi16_list = NULL;
433        }
434
435        /*
436         * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
437         */
438        val = v + vallo;
439        insnlo = (insnlo & ~0xffff) | (val & 0xffff);
440        *location = insnlo;
441
442        return 0;
443
444out_danger:
445        printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name);
446
447        return -ENOEXEC;
448}
449
450static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
451{
452        *location = (*location & 0xffff0000) | (v & 0xffff);
453
454        return 0;
455}
456
457static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
458{
459        *(Elf_Addr *)location = v;
460
461        return 0;
462}
463
464static int apply_r_mips_higher_rela(struct module *me, u32 *location,
465                                    Elf_Addr v)
466{
467        *location = (*location & 0xffff0000) |
468                    ((((long long) v + 0x80008000LL) >> 32) & 0xffff);
469
470        return 0;
471}
472
473static int apply_r_mips_highest_rela(struct module *me, u32 *location,
474                                     Elf_Addr v)
475{
476        *location = (*location & 0xffff0000) |
477                    ((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
478
479        return 0;
480}
481
482static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
483                                Elf_Addr v) = {
484        [R_MIPS_NONE]           = apply_r_mips_none,
485        [R_MIPS_32]             = apply_r_mips_32_rel,
486        [R_MIPS_26]             = apply_r_mips_26_rel,
487        [R_MIPS_HI16]           = apply_r_mips_hi16_rel,
488        [R_MIPS_LO16]           = apply_r_mips_lo16_rel
489};
490
491static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
492                                Elf_Addr v) = {
493        [R_MIPS_NONE]           = apply_r_mips_none,
494        [R_MIPS_32]             = apply_r_mips_32_rela,
495        [R_MIPS_26]             = apply_r_mips_26_rela,
496        [R_MIPS_HI16]           = apply_r_mips_hi16_rela,
497        [R_MIPS_LO16]           = apply_r_mips_lo16_rela,
498        [R_MIPS_64]             = apply_r_mips_64_rela,
499        [R_MIPS_HIGHER]         = apply_r_mips_higher_rela,
500        [R_MIPS_HIGHEST]        = apply_r_mips_highest_rela
501};
502
503int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
504                   unsigned int symindex, unsigned int relsec,
505                   struct module *me)
506{
507        Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr;
508        Elf_Sym *sym;
509        u32 *location;
510        unsigned int i;
511        Elf_Addr v;
512        int res;
513
514        pr_debug("Applying relocate section %u to %u\n", relsec,
515               sechdrs[relsec].sh_info);
516
517        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
518                /* This is where to make the change */
519                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
520                        + rel[i].r_offset;
521                /* This is the symbol it is referring to */
522                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
523                        + ELF_MIPS_R_SYM(rel[i]);
524                if (!sym->st_value) {
525                        /* Ignore unresolved weak symbol */
526                        if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
527                                continue;
528                        printk(KERN_WARNING "%s: Unknown symbol %s\n",
529                               me->name, strtab + sym->st_name);
530                        return -ENOENT;
531                }
532
533                v = sym->st_value;
534
535                res = reloc_handlers_rel[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
536                if (res)
537                        return res;
538        }
539
540        return 0;
541}
542
543int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
544                       unsigned int symindex, unsigned int relsec,
545                       struct module *me)
546{
547        Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
548        Elf_Sym *sym;
549        u32 *location;
550        unsigned int i;
551        Elf_Addr v;
552        int res;
553
554        pr_debug("Applying relocate section %u to %u\n", relsec,
555               sechdrs[relsec].sh_info);
556
557        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
558                /* This is where to make the change */
559                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
560                        + rel[i].r_offset;
561                /* This is the symbol it is referring to */
562                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
563                        + ELF_MIPS_R_SYM(rel[i]);
564                if (!sym->st_value) {
565                        /* Ignore unresolved weak symbol */
566                        if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
567                                continue;
568                        printk(KERN_WARNING "%s: Unknown symbol %s\n",
569                               me->name, strtab + sym->st_name);
570                        return -ENOENT;
571                }
572
573                v = sym->st_value + rel[i].r_addend;
574
575                res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
576                if (res)
577                        return res;
578        }
579
580        return 0;
581}
582
583/* Given an address, look for it in the module exception tables. */
584const struct exception_table_entry *search_module_dbetables(unsigned long addr)
585{
586        unsigned long flags;
587        const struct exception_table_entry *e = NULL;
588        struct mod_arch_specific *dbe;
589
590        spin_lock_irqsave(&dbe_lock, flags);
591        list_for_each_entry(dbe, &dbe_list, dbe_list) {
592                e = search_extable(dbe->dbe_start, dbe->dbe_end - 1, addr);
593                if (e)
594                        break;
595        }
596        spin_unlock_irqrestore(&dbe_lock, flags);
597
598        /* Now, if we found one, we are running inside it now, hence
599           we cannot unload the module, hence no refcnt needed. */
600        return e;
601}
602
603/* Put in dbe list if neccessary. */
604int module_finalize(const Elf_Ehdr *hdr,
605                    const Elf_Shdr *sechdrs,
606                    struct module *me)
607{
608        const Elf_Shdr *s;
609        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
610
611        INIT_LIST_HEAD(&me->arch.dbe_list);
612        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
613                if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
614                        continue;
615                me->arch.dbe_start = (void *)s->sh_addr;
616                me->arch.dbe_end = (void *)s->sh_addr + s->sh_size;
617                spin_lock_irq(&dbe_lock);
618                list_add(&me->arch.dbe_list, &dbe_list);
619                spin_unlock_irq(&dbe_lock);
620        }
621
622        if (me->arch.core_plt_offset < me->core_size
623            && PAGE_ALIGN(me->arch.core_plt_offset) == me->arch.core_plt_offset
624            && is_phys(me->module_core)) {
625                free_phys(me->module_core + me->arch.core_plt_offset,
626                          me->core_size - me->arch.core_plt_offset);
627                me->core_size = me->arch.core_plt_offset;
628        }
629        return 0;
630}
631
632void module_arch_cleanup(struct module *mod)
633{
634        spin_lock_irq(&dbe_lock);
635        list_del(&mod->arch.dbe_list);
636        spin_unlock_irq(&dbe_lock);
637}
Note: See TracBrowser for help on using the repository browser.