2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / kernel / module . c
*
* Copyright ( C ) 2002 Russell King .
2006-09-26 17:37:07 +09:00
* Modified for nommu by Hyok S . Choi
2005-04-16 15:20:36 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Module allocation method suggested by Andi Kleen .
*/
# include <linux/module.h>
2005-10-28 14:29:43 +01:00
# include <linux/moduleloader.h>
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/elf.h>
# include <linux/vmalloc.h>
# include <linux/slab.h>
# include <linux/fs.h>
# include <linux/string.h>
# include <asm/pgtable.h>
# ifdef CONFIG_XIP_KERNEL
/*
* The XIP kernel text is mapped in the module area for modules and
* some other stuff to work without any indirect relocations .
* MODULE_START is redefined here and not in asm / memory . h to avoid
* recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on / off .
*/
extern void _etext ;
# undef MODULE_START
# define MODULE_START (((unsigned long)&_etext + ~PGDIR_MASK) & PGDIR_MASK)
# endif
2006-09-26 17:37:07 +09:00
# ifdef CONFIG_MMU
2005-04-16 15:20:36 -07:00
void * module_alloc ( unsigned long size )
{
struct vm_struct * area ;
size = PAGE_ALIGN ( size ) ;
if ( ! size )
return NULL ;
area = __get_vm_area ( size , VM_ALLOC , MODULE_START , MODULE_END ) ;
if ( ! area )
return NULL ;
return __vmalloc_area ( area , GFP_KERNEL , PAGE_KERNEL ) ;
}
2006-09-26 17:37:07 +09:00
# else /* CONFIG_MMU */
void * module_alloc ( unsigned long size )
{
return size = = 0 ? NULL : vmalloc ( size ) ;
}
# endif /* !CONFIG_MMU */
2005-04-16 15:20:36 -07:00
void module_free ( struct module * module , void * region )
{
vfree ( region ) ;
}
int module_frob_arch_sections ( Elf_Ehdr * hdr ,
Elf_Shdr * sechdrs ,
char * secstrings ,
struct module * mod )
{
return 0 ;
}
int
apply_relocate ( Elf32_Shdr * sechdrs , const char * strtab , unsigned int symindex ,
unsigned int relindex , struct module * module )
{
Elf32_Shdr * symsec = sechdrs + symindex ;
Elf32_Shdr * relsec = sechdrs + relindex ;
Elf32_Shdr * dstsec = sechdrs + relsec - > sh_info ;
Elf32_Rel * rel = ( void * ) relsec - > sh_addr ;
unsigned int i ;
for ( i = 0 ; i < relsec - > sh_size / sizeof ( Elf32_Rel ) ; i + + , rel + + ) {
unsigned long loc ;
Elf32_Sym * sym ;
s32 offset ;
offset = ELF32_R_SYM ( rel - > r_info ) ;
if ( offset < 0 | | offset > ( symsec - > sh_size / sizeof ( Elf32_Sym ) ) ) {
printk ( KERN_ERR " %s: bad relocation, section %d reloc %d \n " ,
module - > name , relindex , i ) ;
return - ENOEXEC ;
}
sym = ( ( Elf32_Sym * ) symsec - > sh_addr ) + offset ;
if ( rel - > r_offset < 0 | | rel - > r_offset > dstsec - > sh_size - sizeof ( u32 ) ) {
printk ( KERN_ERR " %s: out of bounds relocation, "
" section %d reloc %d offset %d size %d \n " ,
module - > name , relindex , i , rel - > r_offset ,
dstsec - > sh_size ) ;
return - ENOEXEC ;
}
loc = dstsec - > sh_addr + rel - > r_offset ;
switch ( ELF32_R_TYPE ( rel - > r_info ) ) {
case R_ARM_ABS32 :
* ( u32 * ) loc + = sym - > st_value ;
break ;
case R_ARM_PC24 :
2005-12-14 22:04:22 +00:00
case R_ARM_CALL :
case R_ARM_JUMP24 :
2005-04-16 15:20:36 -07:00
offset = ( * ( u32 * ) loc & 0x00ffffff ) < < 2 ;
if ( offset & 0x02000000 )
offset - = 0x04000000 ;
offset + = sym - > st_value - loc ;
if ( offset & 3 | |
2007-05-08 22:05:25 +01:00
offset < = ( s32 ) 0xfe000000 | |
offset > = ( s32 ) 0x02000000 ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR
" %s: relocation out of range, section "
" %d reloc %d sym '%s' \n " , module - > name ,
relindex , i , strtab + sym - > st_name ) ;
return - ENOEXEC ;
}
offset > > = 2 ;
* ( u32 * ) loc & = 0xff000000 ;
* ( u32 * ) loc | = offset & 0x00ffffff ;
break ;
default :
printk ( KERN_ERR " %s: unknown relocation: %u \n " ,
module - > name , ELF32_R_TYPE ( rel - > r_info ) ) ;
return - ENOEXEC ;
}
}
return 0 ;
}
int
apply_relocate_add ( Elf32_Shdr * sechdrs , const char * strtab ,
unsigned int symindex , unsigned int relsec , struct module * module )
{
printk ( KERN_ERR " module %s: ADD RELOCATION unsupported \n " ,
module - > name ) ;
return - ENOEXEC ;
}
int
module_finalize ( const Elf32_Ehdr * hdr , const Elf_Shdr * sechdrs ,
struct module * module )
{
return 0 ;
}
void
module_arch_cleanup ( struct module * mod )
{
}