Show
Ignore:
Timestamp:
06/30/2009 05:02:18 PM (9 months ago)
Author:
BrainSlayer
Message:

latest adm5120 update incl. remap patch

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/linux/adm5120/linux-2.6.23/arch/mips/kernel/module.c

    r10172 r12415  
    3030#include <linux/module.h> 
    3131#include <linux/spinlock.h> 
     32#include <linux/mm.h> 
    3233#include <asm/pgtable.h>        /* MODULE_START */ 
    3334 
     
    4344static DEFINE_SPINLOCK(dbe_lock); 
    4445 
     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 
    4581void *module_alloc(unsigned long size) 
    4682{ 
     
    5894        return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); 
    5995#else 
     96        unsigned addr; 
     97        void *ptr; 
     98 
     99        size = PAGE_ALIGN(size); 
    60100        if (size == 0) 
    61101                return NULL; 
    62         return vmalloc(size); 
     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; 
    63124#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); 
    64131} 
    65132 
     
    67134void module_free(struct module *mod, void *module_region) 
    68135{ 
     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 
    69146        vfree(module_region); 
    70147        /* FIXME: If module_region == mod->init_region, trim exception 
     
    78155} 
    79156 
     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 
    80251static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) 
    81252{ 
     
    94265        *location = v; 
    95266 
     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        } 
    96305        return 0; 
    97306} 
     
    105314 
    106315        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { 
     316                v = add_plt_entry(me, location, 
     317                                  v + ((*location & 0x03ffffff) << 2)); 
     318                if (v == 0) { 
    107319                printk(KERN_ERR 
    108320                       "module %s: relocation overflow\n", 
     
    110322                return -ENOEXEC; 
    111323        } 
     324                *location = (*location & ~0x03ffffff) | 
     325                            ((v >> 2) & 0x03ffffff); 
     326                return 0; 
     327        } 
    112328 
    113329        *location = (*location & ~0x03ffffff) | 
     
    125341 
    126342        if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { 
     343                v = add_plt_entry(me, location, v); 
     344                if (v == 0) { 
    127345                printk(KERN_ERR 
    128346                       "module %s: relocation overflow\n", 
    129347                       me->name); 
    130348                return -ENOEXEC; 
     349        } 
    131350        } 
    132351 
     
    400619                spin_unlock_irq(&dbe_lock); 
    401620        } 
     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        } 
    402629        return 0; 
    403630}