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