1 /* 2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> 3 * Copyright (C) 2007-2009 PetaLogix 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/moduleloader.h> 12 #include <linux/kernel.h> 13 #include <linux/elf.h> 14 #include <linux/vmalloc.h> 15 #include <linux/slab.h> 16 #include <linux/fs.h> 17 #include <linux/string.h> 18 19 #include <asm/pgtable.h> 20 21 void *module_alloc(unsigned long size) 22 { 23 void *ret; 24 ret = (size == 0) ? NULL : vmalloc(size); 25 pr_debug("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret); 26 return ret; 27 } 28 29 void module_free(struct module *module, void *region) 30 { 31 pr_debug("module_free(%s,%08lx)\n", module->name, 32 (unsigned long)region); 33 vfree(region); 34 } 35 36 int module_frob_arch_sections(Elf_Ehdr *hdr, 37 Elf_Shdr *sechdrs, 38 char *secstrings, 39 struct module *mod) 40 { 41 return 0; 42 } 43 44 int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, 45 unsigned int symindex, unsigned int relsec, struct module *module) 46 { 47 printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", 48 module->name); 49 return -ENOEXEC; 50 } 51 52 int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, 53 unsigned int symindex, unsigned int relsec, struct module *module) 54 { 55 56 unsigned int i; 57 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; 58 Elf32_Sym *sym; 59 unsigned long int *location; 60 unsigned long int locoffs; 61 unsigned long int value; 62 #if __GNUC__ < 4 63 unsigned long int old_value; 64 #endif 65 66 pr_debug("Applying add relocation section %u to %u\n", 67 relsec, sechdrs[relsec].sh_info); 68 69 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { 70 71 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + 72 rela[i].r_offset; 73 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + 74 ELF32_R_SYM(rela[i].r_info); 75 value = sym->st_value + rela[i].r_addend; 76 77 switch (ELF32_R_TYPE(rela[i].r_info)) { 78 79 /* 80 * Be careful! mb-gcc / mb-ld splits the relocs between the 81 * text and the reloc table. In general this means we must 82 * read the current contents of (*location), add any offset 83 * then store the result back in 84 */ 85 86 case R_MICROBLAZE_32: 87 #if __GNUC__ < 4 88 old_value = *location; 89 *location = value + old_value; 90 91 pr_debug("R_MICROBLAZE_32 (%08lx->%08lx)\n", 92 old_value, value); 93 #else 94 *location = value; 95 #endif 96 break; 97 98 case R_MICROBLAZE_64: 99 #if __GNUC__ < 4 100 /* Split relocs only required/used pre gcc4.1.1 */ 101 old_value = ((location[0] & 0x0000FFFF) << 16) | 102 (location[1] & 0x0000FFFF); 103 value += old_value; 104 #endif 105 location[0] = (location[0] & 0xFFFF0000) | 106 (value >> 16); 107 location[1] = (location[1] & 0xFFFF0000) | 108 (value & 0xFFFF); 109 #if __GNUC__ < 4 110 pr_debug("R_MICROBLAZE_64 (%08lx->%08lx)\n", 111 old_value, value); 112 #endif 113 break; 114 115 case R_MICROBLAZE_64_PCREL: 116 locoffs = (location[0] & 0xFFFF) << 16 | 117 (location[1] & 0xFFFF); 118 value -= (unsigned long int)(location) + 4 + 119 locoffs; 120 location[0] = (location[0] & 0xFFFF0000) | 121 (value >> 16); 122 location[1] = (location[1] & 0xFFFF0000) | 123 (value & 0xFFFF); 124 pr_debug("R_MICROBLAZE_64_PCREL (%08lx)\n", 125 value); 126 break; 127 128 case R_MICROBLAZE_NONE: 129 pr_debug("R_MICROBLAZE_NONE\n"); 130 break; 131 132 default: 133 printk(KERN_ERR "module %s: " 134 "Unknown relocation: %u\n", 135 module->name, 136 ELF32_R_TYPE(rela->r_info)); 137 return -ENOEXEC; 138 } 139 } 140 return 0; 141 } 142 143 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 144 struct module *module) 145 { 146 return 0; 147 } 148 149 void module_arch_cleanup(struct module *mod) 150 { 151 } 152