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