1/* 2 * linux/arch/unicore32/kernel/module.c 3 * 4 * Code specific to PKUnity SoC and UniCore ISA 5 * 6 * Copyright (C) 2001-2010 GUAN Xue-tao 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12#include <linux/module.h> 13#include <linux/moduleloader.h> 14#include <linux/kernel.h> 15#include <linux/mm.h> 16#include <linux/elf.h> 17#include <linux/vmalloc.h> 18#include <linux/fs.h> 19#include <linux/string.h> 20#include <linux/gfp.h> 21 22#include <asm/pgtable.h> 23#include <asm/sections.h> 24 25void *module_alloc(unsigned long size) 26{ 27 return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 28 GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, 29 __builtin_return_address(0)); 30} 31 32int 33apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, 34 unsigned int relindex, struct module *module) 35{ 36 Elf32_Shdr *symsec = sechdrs + symindex; 37 Elf32_Shdr *relsec = sechdrs + relindex; 38 Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; 39 Elf32_Rel *rel = (void *)relsec->sh_addr; 40 unsigned int i; 41 42 for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { 43 unsigned long loc; 44 Elf32_Sym *sym; 45 s32 offset; 46 47 offset = ELF32_R_SYM(rel->r_info); 48 if (offset < 0 || offset > 49 (symsec->sh_size / sizeof(Elf32_Sym))) { 50 printk(KERN_ERR "%s: bad relocation, " 51 "section %d reloc %d\n", 52 module->name, relindex, i); 53 return -ENOEXEC; 54 } 55 56 sym = ((Elf32_Sym *)symsec->sh_addr) + offset; 57 58 if (rel->r_offset < 0 || rel->r_offset > 59 dstsec->sh_size - sizeof(u32)) { 60 printk(KERN_ERR "%s: out of bounds relocation, " 61 "section %d reloc %d offset %d size %d\n", 62 module->name, relindex, i, rel->r_offset, 63 dstsec->sh_size); 64 return -ENOEXEC; 65 } 66 67 loc = dstsec->sh_addr + rel->r_offset; 68 69 switch (ELF32_R_TYPE(rel->r_info)) { 70 case R_UNICORE_NONE: 71 /* ignore */ 72 break; 73 74 case R_UNICORE_ABS32: 75 *(u32 *)loc += sym->st_value; 76 break; 77 78 case R_UNICORE_PC24: 79 case R_UNICORE_CALL: 80 case R_UNICORE_JUMP24: 81 offset = (*(u32 *)loc & 0x00ffffff) << 2; 82 if (offset & 0x02000000) 83 offset -= 0x04000000; 84 85 offset += sym->st_value - loc; 86 if (offset & 3 || 87 offset <= (s32)0xfe000000 || 88 offset >= (s32)0x02000000) { 89 printk(KERN_ERR 90 "%s: relocation out of range, section " 91 "%d reloc %d sym '%s'\n", module->name, 92 relindex, i, strtab + sym->st_name); 93 return -ENOEXEC; 94 } 95 96 offset >>= 2; 97 98 *(u32 *)loc &= 0xff000000; 99 *(u32 *)loc |= offset & 0x00ffffff; 100 break; 101 102 default: 103 printk(KERN_ERR "%s: unknown relocation: %u\n", 104 module->name, ELF32_R_TYPE(rel->r_info)); 105 return -ENOEXEC; 106 } 107 } 108 return 0; 109} 110