2009-06-12 22:01:00 +08:00
/*
* arch / score / kernel / module . c
*
* Score Processor version .
*
* Copyright ( C ) 2009 Sunplus Core Technology Co . , Ltd .
* Chen Liqin < liqin . chen @ sunplusct . com >
* Lennox Wu < lennox . wu @ sunplusct . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see the file COPYING , or write
* to the Free Software Foundation , Inc . ,
* 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2009-06-27 14:50:51 +02:00
# include <linux/moduleloader.h>
2009-06-12 22:01:00 +08:00
# include <linux/module.h>
# include <linux/vmalloc.h>
int apply_relocate ( Elf_Shdr * sechdrs , const char * strtab ,
unsigned int symindex , unsigned int relindex ,
struct module * me )
{
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 ;
2009-06-27 14:46:35 +02:00
s32 r_offset ;
2009-06-12 22:01:00 +08:00
2009-06-27 14:46:35 +02:00
r_offset = ELF32_R_SYM ( rel - > r_info ) ;
if ( ( r_offset < 0 ) | |
( r_offset > ( symsec - > sh_size / sizeof ( Elf32_Sym ) ) ) ) {
2009-06-12 22:01:00 +08:00
printk ( KERN_ERR " %s: bad relocation, section %d reloc %d \n " ,
me - > name , relindex , i ) ;
return - ENOEXEC ;
}
2009-06-27 14:46:35 +02:00
sym = ( ( Elf32_Sym * ) symsec - > sh_addr ) + r_offset ;
2009-06-12 22:01:00 +08:00
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 " ,
me - > 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_SCORE_NONE :
break ;
case R_SCORE_ABS32 :
* ( unsigned long * ) loc + = sym - > st_value ;
break ;
case R_SCORE_HI16 :
break ;
case R_SCORE_LO16 : {
unsigned long hi16_offset , offset ;
unsigned long uvalue ;
unsigned long temp , temp_hi ;
temp_hi = * ( ( unsigned long * ) loc - 1 ) ;
temp = * ( unsigned long * ) loc ;
hi16_offset = ( ( ( ( ( temp_hi ) > > 16 ) & 0x3 ) < < 15 ) |
( ( temp_hi ) & 0x7fff ) ) > > 1 ;
offset = ( ( temp > > 16 & 0x03 ) < < 15 ) |
( ( temp & 0x7fff ) > > 1 ) ;
offset = ( hi16_offset < < 16 ) | ( offset & 0xffff ) ;
uvalue = sym - > st_value + offset ;
hi16_offset = ( uvalue > > 16 ) < < 1 ;
temp_hi = ( ( temp_hi ) & ( ~ ( 0x37fff ) ) ) |
( hi16_offset & 0x7fff ) |
( ( hi16_offset < < 1 ) & 0x30000 ) ;
* ( ( unsigned long * ) loc - 1 ) = temp_hi ;
offset = ( uvalue & 0xffff ) < < 1 ;
temp = ( temp & ( ~ ( 0x37fff ) ) ) | ( offset & 0x7fff ) |
( ( offset < < 1 ) & 0x30000 ) ;
* ( unsigned long * ) loc = temp ;
break ;
}
case R_SCORE_24 : {
unsigned long hi16_offset , offset ;
unsigned long uvalue ;
unsigned long temp ;
temp = * ( unsigned long * ) loc ;
offset = ( temp & 0x03FF7FFE ) ;
hi16_offset = ( offset & 0xFFFF0000 ) ;
offset = ( hi16_offset | ( ( offset & 0xFFFF ) < < 1 ) ) > > 2 ;
uvalue = ( sym - > st_value + offset ) > > 1 ;
uvalue = uvalue & 0x00ffffff ;
temp = ( temp & 0xfc008001 ) |
( ( uvalue < < 2 ) & 0x3ff0000 ) |
( ( uvalue & 0x3fff ) < < 1 ) ;
* ( unsigned long * ) loc = temp ;
break ;
}
default :
printk ( KERN_ERR " %s: unknown relocation: %u \n " ,
me - > name , ELF32_R_TYPE ( rel - > r_info ) ) ;
return - ENOEXEC ;
}
}
return 0 ;
}
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry * search_module_dbetables ( unsigned long addr )
{
2009-06-27 14:46:35 +02:00
return NULL ;
2009-06-12 22:01:00 +08:00
}