187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao/* 287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * linux/arch/unicore32/kernel/module.c 387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * 487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * Code specific to PKUnity SoC and UniCore ISA 587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * 687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * Copyright (C) 2001-2010 GUAN Xue-tao 787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * 887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * This program is free software; you can redistribute it and/or modify 987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * it under the terms of the GNU General Public License version 2 as 1087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao * published by the Free Software Foundation. 1187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao */ 1287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/module.h> 1387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/moduleloader.h> 1487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/kernel.h> 1587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/mm.h> 1687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/elf.h> 1787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/vmalloc.h> 1887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/fs.h> 1987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/string.h> 2087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <linux/gfp.h> 2187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 2287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <asm/pgtable.h> 2387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao#include <asm/sections.h> 2487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 2587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetaovoid *module_alloc(unsigned long size) 2687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao{ 27df8e4c7d8d756d93da676b532c39f8d1d9ceab77Chen Gang return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, 28df8e4c7d8d756d93da676b532c39f8d1d9ceab77Chen Gang GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE, 29df8e4c7d8d756d93da676b532c39f8d1d9ceab77Chen Gang __builtin_return_address(0)); 3087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao} 3187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 3287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetaoint 3387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetaoapply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, 3487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao unsigned int relindex, struct module *module) 3587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao{ 3687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao Elf32_Shdr *symsec = sechdrs + symindex; 3787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao Elf32_Shdr *relsec = sechdrs + relindex; 3887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; 3987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao Elf32_Rel *rel = (void *)relsec->sh_addr; 4087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao unsigned int i; 4187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 4287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { 4387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao unsigned long loc; 4487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao Elf32_Sym *sym; 4587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao s32 offset; 4687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 4787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset = ELF32_R_SYM(rel->r_info); 4887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao if (offset < 0 || offset > 4987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao (symsec->sh_size / sizeof(Elf32_Sym))) { 5087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao printk(KERN_ERR "%s: bad relocation, " 5187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao "section %d reloc %d\n", 5287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao module->name, relindex, i); 5387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao return -ENOEXEC; 5487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao } 5587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 5687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao sym = ((Elf32_Sym *)symsec->sh_addr) + offset; 5787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 5887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao if (rel->r_offset < 0 || rel->r_offset > 5987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao dstsec->sh_size - sizeof(u32)) { 6087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao printk(KERN_ERR "%s: out of bounds relocation, " 6187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao "section %d reloc %d offset %d size %d\n", 6287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao module->name, relindex, i, rel->r_offset, 6387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao dstsec->sh_size); 6487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao return -ENOEXEC; 6587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao } 6687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 6787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao loc = dstsec->sh_addr + rel->r_offset; 6887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 6987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao switch (ELF32_R_TYPE(rel->r_info)) { 7087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao case R_UNICORE_NONE: 7187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao /* ignore */ 7287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao break; 7387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 7487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao case R_UNICORE_ABS32: 7587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao *(u32 *)loc += sym->st_value; 7687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao break; 7787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 7887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao case R_UNICORE_PC24: 7987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao case R_UNICORE_CALL: 8087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao case R_UNICORE_JUMP24: 8187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset = (*(u32 *)loc & 0x00ffffff) << 2; 8287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao if (offset & 0x02000000) 8387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset -= 0x04000000; 8487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 8587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset += sym->st_value - loc; 8687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao if (offset & 3 || 8787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset <= (s32)0xfe000000 || 8887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset >= (s32)0x02000000) { 8987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao printk(KERN_ERR 9087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao "%s: relocation out of range, section " 9187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao "%d reloc %d sym '%s'\n", module->name, 9287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao relindex, i, strtab + sym->st_name); 9387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao return -ENOEXEC; 9487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao } 9587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 9687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao offset >>= 2; 9787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 9887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao *(u32 *)loc &= 0xff000000; 9987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao *(u32 *)loc |= offset & 0x00ffffff; 10087c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao break; 10187c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao 10287c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao default: 10387c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao printk(KERN_ERR "%s: unknown relocation: %u\n", 10487c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao module->name, ELF32_R_TYPE(rel->r_info)); 10587c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao return -ENOEXEC; 10687c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao } 10787c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao } 10887c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao return 0; 10987c1a3fb7c07322dfd63a63dd6d42339ad52ddeeGuanXuetao} 110