linux/arch/sparc/kernel/module.c
<<
>>
Prefs
   1/* Kernel module help for sparc64.
   2 *
   3 * Copyright (C) 2001 Rusty Russell.
   4 * Copyright (C) 2002 David S. Miller.
   5 */
   6
   7#include <linux/moduleloader.h>
   8#include <linux/kernel.h>
   9#include <linux/elf.h>
  10#include <linux/vmalloc.h>
  11#include <linux/fs.h>
  12#include <linux/string.h>
  13#include <linux/ctype.h>
  14#include <linux/slab.h>
  15#include <linux/mm.h>
  16
  17#include <asm/processor.h>
  18#include <asm/spitfire.h>
  19
  20#ifdef CONFIG_SPARC64
  21static void *module_map(unsigned long size)
  22{
  23        struct vm_struct *area;
  24
  25        size = PAGE_ALIGN(size);
  26        if (!size || size > MODULES_LEN)
  27                return NULL;
  28
  29        area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
  30        if (!area)
  31                return NULL;
  32
  33        return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
  34}
  35
  36static char *dot2underscore(char *name)
  37{
  38        return name;
  39}
  40#else
  41static void *module_map(unsigned long size)
  42{
  43        return vmalloc(size);
  44}
  45
  46/* Replace references to .func with _Func */
  47static char *dot2underscore(char *name)
  48{
  49        if (name[0] == '.') {
  50                name[0] = '_';
  51                name[1] = toupper(name[1]);
  52        }
  53        return name;
  54}
  55#endif /* CONFIG_SPARC64 */
  56
  57void *module_alloc(unsigned long size)
  58{
  59        void *ret;
  60
  61        /* We handle the zero case fine, unlike vmalloc */
  62        if (size == 0)
  63                return NULL;
  64
  65        ret = module_map(size);
  66        if (!ret)
  67                ret = ERR_PTR(-ENOMEM);
  68        else
  69                memset(ret, 0, size);
  70
  71        return ret;
  72}
  73
  74/* Free memory returned from module_core_alloc/module_init_alloc */
  75void module_free(struct module *mod, void *module_region)
  76{
  77        vfree(module_region);
  78}
  79
  80/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
  81int module_frob_arch_sections(Elf_Ehdr *hdr,
  82                              Elf_Shdr *sechdrs,
  83                              char *secstrings,
  84                              struct module *mod)
  85{
  86        unsigned int symidx;
  87        Elf_Sym *sym;
  88        char *strtab;
  89        int i;
  90
  91        for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
  92                if (symidx == hdr->e_shnum-1) {
  93                        printk("%s: no symtab found.\n", mod->name);
  94                        return -ENOEXEC;
  95                }
  96        }
  97        sym = (Elf_Sym *)sechdrs[symidx].sh_addr;
  98        strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
  99
 100        for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
 101                if (sym[i].st_shndx == SHN_UNDEF) {
 102                        if (ELF_ST_TYPE(sym[i].st_info) == STT_REGISTER) {
 103                                sym[i].st_shndx = SHN_ABS;
 104                        } else {
 105                                char *name = strtab + sym[i].st_name;
 106                                dot2underscore(name);
 107                        }
 108                }
 109        }
 110        return 0;
 111}
 112
 113int apply_relocate(Elf_Shdr *sechdrs,
 114                   const char *strtab,
 115                   unsigned int symindex,
 116                   unsigned int relsec,
 117                   struct module *me)
 118{
 119        printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n",
 120               me->name);
 121        return -ENOEXEC;
 122}
 123
 124int apply_relocate_add(Elf_Shdr *sechdrs,
 125                       const char *strtab,
 126                       unsigned int symindex,
 127                       unsigned int relsec,
 128                       struct module *me)
 129{
 130        unsigned int i;
 131        Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
 132        Elf_Sym *sym;
 133        u8 *location;
 134        u32 *loc32;
 135
 136        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 137                Elf_Addr v;
 138
 139                /* This is where to make the change */
 140                location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 141                        + rel[i].r_offset;
 142                loc32 = (u32 *) location;
 143
 144#ifdef CONFIG_SPARC64
 145                BUG_ON(((u64)location >> (u64)32) != (u64)0);
 146#endif /* CONFIG_SPARC64 */
 147
 148                /* This is the symbol it is referring to.  Note that all
 149                   undefined symbols have been resolved.  */
 150                sym = (Elf_Sym *)sechdrs[symindex].sh_addr
 151                        + ELF_R_SYM(rel[i].r_info);
 152                v = sym->st_value + rel[i].r_addend;
 153
 154                switch (ELF_R_TYPE(rel[i].r_info) & 0xff) {
 155#ifdef CONFIG_SPARC64
 156                case R_SPARC_64:
 157                        location[0] = v >> 56;
 158                        location[1] = v >> 48;
 159                        location[2] = v >> 40;
 160                        location[3] = v >> 32;
 161                        location[4] = v >> 24;
 162                        location[5] = v >> 16;
 163                        location[6] = v >>  8;
 164                        location[7] = v >>  0;
 165                        break;
 166
 167                case R_SPARC_DISP32:
 168                        v -= (Elf_Addr) location;
 169                        *loc32 = v;
 170                        break;
 171
 172                case R_SPARC_WDISP19:
 173                        v -= (Elf_Addr) location;
 174                        *loc32 = (*loc32 & ~0x7ffff) |
 175                                ((v >> 2) & 0x7ffff);
 176                        break;
 177
 178                case R_SPARC_OLO10:
 179                        *loc32 = (*loc32 & ~0x1fff) |
 180                                (((v & 0x3ff) +
 181                                  (ELF_R_TYPE(rel[i].r_info) >> 8))
 182                                 & 0x1fff);
 183                        break;
 184#endif /* CONFIG_SPARC64 */
 185
 186                case R_SPARC_32:
 187                case R_SPARC_UA32:
 188                        location[0] = v >> 24;
 189                        location[1] = v >> 16;
 190                        location[2] = v >>  8;
 191                        location[3] = v >>  0;
 192                        break;
 193
 194                case R_SPARC_WDISP30:
 195                        v -= (Elf_Addr) location;
 196                        *loc32 = (*loc32 & ~0x3fffffff) |
 197                                ((v >> 2) & 0x3fffffff);
 198                        break;
 199
 200                case R_SPARC_WDISP22:
 201                        v -= (Elf_Addr) location;
 202                        *loc32 = (*loc32 & ~0x3fffff) |
 203                                ((v >> 2) & 0x3fffff);
 204                        break;
 205
 206                case R_SPARC_LO10:
 207                        *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
 208                        break;
 209
 210                case R_SPARC_HI22:
 211                        *loc32 = (*loc32 & ~0x3fffff) |
 212                                ((v >> 10) & 0x3fffff);
 213                        break;
 214
 215                default:
 216                        printk(KERN_ERR "module %s: Unknown relocation: %x\n",
 217                               me->name,
 218                               (int) (ELF_R_TYPE(rel[i].r_info) & 0xff));
 219                        return -ENOEXEC;
 220                };
 221        }
 222        return 0;
 223}
 224
 225#ifdef CONFIG_SPARC64
 226int module_finalize(const Elf_Ehdr *hdr,
 227                    const Elf_Shdr *sechdrs,
 228                    struct module *me)
 229{
 230        /* Cheetah's I-cache is fully coherent.  */
 231        if (tlb_type == spitfire) {
 232                unsigned long va;
 233
 234                flushw_all();
 235                for (va =  0; va < (PAGE_SIZE << 1); va += 32)
 236                        spitfire_put_icache_tag(va, 0x0);
 237                __asm__ __volatile__("flush %g6");
 238        }
 239
 240        return 0;
 241}
 242#else
 243int module_finalize(const Elf_Ehdr *hdr,
 244                    const Elf_Shdr *sechdrs,
 245                    struct module *me)
 246{
 247        return 0;
 248}
 249#endif /* CONFIG_SPARC64 */
 250
 251void module_arch_cleanup(struct module *mod)
 252{
 253}
 254
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.