2005-02-21 13:45:09 +03:00
/*
* 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 , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* Copyright ( C ) 2001 Rusty Russell .
* Copyright ( C ) 2003 , 2004 Ralf Baechle ( ralf @ linux - mips . org )
* Copyright ( C ) 2005 Thiemo Seufer
*/
# undef DEBUG
2016-08-16 02:11:52 +03:00
# include <linux/extable.h>
2005-02-21 13:45:09 +03:00
# include <linux/moduleloader.h>
# include <linux/elf.h>
2008-07-24 08:28:13 +04:00
# include <linux/mm.h>
2013-09-18 16:54:37 +04:00
# include <linux/numa.h>
2005-02-21 13:45:09 +03:00
# include <linux/vmalloc.h>
# include <linux/slab.h>
# include <linux/fs.h>
# include <linux/string.h>
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
# include <linux/spinlock.h>
2010-12-29 00:26:23 +03:00
# include <linux/jump_label.h>
[MIPS] Load modules to CKSEG0 if CONFIG_BUILD_ELF64=n
This is a patch to load 64-bit modules to CKSEG0 so that can be
compiled with -msym32 option. This makes each module ~10% smaller.
* introduce MODULE_START and MODULE_END
* custom module_alloc()
* PGD for modules
* change XTLB refill handler synthesizer
* enable -msym32 for modules again
(revert ca78b1a5c6a6e70e052d3ea253828e49b5d07c8a)
New XTLB refill handler looks like this:
80000080 dmfc0 k0,C0_BADVADDR
80000084 bltz k0,800000e4 # goto l_module_alloc
80000088 lui k1,0x8046 # %high(pgd_current)
8000008c ld k1,24600(k1) # %low(pgd_current)
80000090 dsrl k0,k0,0x1b # l_vmalloc_done:
80000094 andi k0,k0,0x1ff8
80000098 daddu k1,k1,k0
8000009c dmfc0 k0,C0_BADVADDR
800000a0 ld k1,0(k1)
800000a4 dsrl k0,k0,0x12
800000a8 andi k0,k0,0xff8
800000ac daddu k1,k1,k0
800000b0 dmfc0 k0,C0_XCONTEXT
800000b4 ld k1,0(k1)
800000b8 andi k0,k0,0xff0
800000bc daddu k1,k1,k0
800000c0 ld k0,0(k1)
800000c4 ld k1,8(k1)
800000c8 dsrl k0,k0,0x6
800000cc mtc0 k0,C0_ENTRYLO0
800000d0 dsrl k1,k1,0x6
800000d4 mtc0 k1,C0_ENTRYL01
800000d8 nop
800000dc tlbwr
800000e0 eret
800000e4 dsll k1,k0,0x2 # l_module_alloc:
800000e8 bgez k1,80000008 # goto l_vmalloc
800000ec lui k1,0xc000
800000f0 dsubu k0,k0,k1
800000f4 lui k1,0x8046 # %high(module_pg_dir)
800000f8 beq zero,zero,80000000
800000fc nop
80000000 beq zero,zero,80000090 # goto l_vmalloc_done
80000004 daddiu k1,k1,0x4000
80000008 dsll32 k1,k1,0x0 # l_vmalloc:
8000000c dsubu k0,k0,k1
80000010 beq zero,zero,80000090 # goto l_vmalloc_done
80000014 lui k1,0x8046 # %high(swapper_pg_dir)
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2006-10-25 19:08:31 +04:00
# include <asm/pgtable.h> /* MODULE_START */
2005-04-17 02:20:36 +04:00
2005-02-21 13:45:09 +03:00
struct mips_hi16 {
struct mips_hi16 * next ;
Elf_Addr * addr ;
Elf_Addr value ;
} ;
2005-04-17 02:20:36 +04:00
static LIST_HEAD ( dbe_list ) ;
static DEFINE_SPINLOCK ( dbe_lock ) ;
2011-06-30 23:22:12 +04:00
# ifdef MODULE_START
2005-02-21 13:45:09 +03:00
void * module_alloc ( unsigned long size )
{
2011-01-14 02:46:02 +03:00
return __vmalloc_node_range ( size , 1 , MODULE_START , MODULE_END ,
2015-02-14 01:40:07 +03:00
GFP_KERNEL , PAGE_KERNEL , 0 , NUMA_NO_NODE ,
2011-01-14 02:46:02 +03:00
__builtin_return_address ( 0 ) ) ;
2005-02-21 13:45:09 +03:00
}
2011-06-30 23:22:12 +04:00
# endif
2005-02-21 13:45:09 +03:00
2017-03-30 21:37:45 +03:00
static int apply_r_mips_none ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 13:45:09 +03:00
{
return 0 ;
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_32 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 13:45:09 +03:00
{
2017-03-30 21:37:45 +03:00
* location = base + v ;
2005-02-21 13:45:09 +03:00
return 0 ;
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_26 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 13:45:09 +03:00
{
if ( v % 4 ) {
2017-03-30 21:37:45 +03:00
pr_err ( " module %s: dangerous R_MIPS_26 relocation \n " ,
2009-08-03 13:50:19 +04:00
me - > name ) ;
2005-02-21 13:45:09 +03:00
return - ENOEXEC ;
}
if ( ( v & 0xf0000000 ) ! = ( ( ( unsigned long ) location + 4 ) & 0xf0000000 ) ) {
2016-02-04 16:05:03 +03:00
pr_err ( " module %s: relocation overflow \n " ,
2005-02-21 13:45:09 +03:00
me - > name ) ;
return - ENOEXEC ;
}
* location = ( * location & ~ 0x03ffffff ) |
2017-03-30 21:37:45 +03:00
( ( base + ( v > > 2 ) ) & 0x03ffffff ) ;
2005-02-21 13:45:09 +03:00
return 0 ;
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_hi16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 13:45:09 +03:00
{
struct mips_hi16 * n ;
2017-03-30 21:37:45 +03:00
if ( rela ) {
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x8000LL ) > > 16 ) & 0xffff ) ;
return 0 ;
}
2005-02-21 13:45:09 +03:00
/*
* We cannot relocate this one now because we don ' t know the value of
* the carry we need to add . Save the information , and let LO16 do the
* actual relocation .
*/
n = kmalloc ( sizeof * n , GFP_KERNEL ) ;
if ( ! n )
return - ENOMEM ;
n - > addr = ( Elf_Addr * ) location ;
n - > value = v ;
2012-08-08 18:59:43 +04:00
n - > next = me - > arch . r_mips_hi16_list ;
me - > arch . r_mips_hi16_list = n ;
2005-02-21 13:45:09 +03:00
return 0 ;
}
2012-08-14 02:34:18 +04:00
static void free_relocation_chain ( struct mips_hi16 * l )
{
struct mips_hi16 * next ;
while ( l ) {
next = l - > next ;
kfree ( l ) ;
l = next ;
}
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_lo16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 13:45:09 +03:00
{
2017-03-30 21:37:45 +03:00
unsigned long insnlo = base ;
2012-08-14 02:34:18 +04:00
struct mips_hi16 * l ;
2005-02-21 13:45:09 +03:00
Elf_Addr val , vallo ;
2017-03-30 21:37:45 +03:00
if ( rela ) {
* location = ( * location & 0xffff0000 ) | ( v & 0xffff ) ;
return 0 ;
}
2013-01-22 15:59:30 +04:00
/* Sign extend the addend we extract from the lo insn. */
2005-02-21 13:45:09 +03:00
vallo = ( ( insnlo & 0xffff ) ^ 0x8000 ) - 0x8000 ;
2012-08-08 18:59:43 +04:00
if ( me - > arch . r_mips_hi16_list ! = NULL ) {
l = me - > arch . r_mips_hi16_list ;
2005-02-21 13:45:09 +03:00
while ( l ! = NULL ) {
2012-08-14 02:34:18 +04:00
struct mips_hi16 * next ;
2005-02-21 13:45:09 +03:00
unsigned long insn ;
/*
* The value for the HI16 had best be the same .
*/
if ( v ! = l - > value )
goto out_danger ;
/*
* Do the HI16 relocation . Note that we actually don ' t
* need to know anything about the LO16 itself , except
* where to find the low 16 bits of the addend needed
* by the LO16 .
*/
insn = * l - > addr ;
val = ( ( insn & 0xffff ) < < 16 ) + vallo ;
val + = v ;
/*
* Account for the sign extension that will happen in
* the low bits .
*/
val = ( ( val > > 16 ) + ( ( val & 0x8000 ) ! = 0 ) ) & 0xffff ;
insn = ( insn & ~ 0xffff ) | val ;
* l - > addr = insn ;
next = l - > next ;
kfree ( l ) ;
l = next ;
}
2012-08-08 18:59:43 +04:00
me - > arch . r_mips_hi16_list = NULL ;
2005-02-21 13:45:09 +03:00
}
/*
2013-01-22 15:59:30 +04:00
* Ok , we ' re done with the HI16 relocs . Now deal with the LO16 .
2005-02-21 13:45:09 +03:00
*/
val = v + vallo ;
insnlo = ( insnlo & ~ 0xffff ) | ( val & 0xffff ) ;
* location = insnlo ;
return 0 ;
out_danger :
2012-08-14 02:34:18 +04:00
free_relocation_chain ( l ) ;
me - > arch . r_mips_hi16_list = NULL ;
2012-08-08 16:57:03 +04:00
2017-03-30 21:37:45 +03:00
pr_err ( " module %s: dangerous R_MIPS_LO16 relocation \n " , me - > name ) ;
2005-02-21 13:45:09 +03:00
return - ENOEXEC ;
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_pc ( struct module * me , u32 * location , u32 base ,
Elf_Addr v , unsigned int bits )
2016-02-04 16:05:05 +03:00
{
unsigned long mask = GENMASK ( bits - 1 , 0 ) ;
unsigned long se_bits ;
long offset ;
if ( v % 4 ) {
2017-03-30 21:37:45 +03:00
pr_err ( " module %s: dangerous R_MIPS_PC%u relocation \n " ,
2016-02-04 16:05:05 +03:00
me - > name , bits ) ;
return - ENOEXEC ;
}
2017-03-30 21:37:45 +03:00
/* retrieve & sign extend implicit addend if any */
offset = base & mask ;
2016-02-04 16:05:05 +03:00
offset | = ( offset & BIT ( bits - 1 ) ) ? ~ mask : 0 ;
offset + = ( ( long ) v - ( long ) location ) > > 2 ;
/* check the sign bit onwards are identical - ie. we didn't overflow */
se_bits = ( offset & BIT ( bits - 1 ) ) ? ~ 0ul : 0 ;
if ( ( offset & ~ mask ) ! = ( se_bits & ~ mask ) ) {
pr_err ( " module %s: relocation overflow \n " , me - > name ) ;
return - ENOEXEC ;
}
* location = ( * location & ~ mask ) | ( offset & mask ) ;
return 0 ;
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_pc16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
return apply_r_mips_pc ( me , location , base , v , 16 ) ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_pc21 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
return apply_r_mips_pc ( me , location , base , v , 21 ) ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_pc26 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
return apply_r_mips_pc ( me , location , base , v , 26 ) ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_64 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* ( Elf_Addr * ) location = v ;
return 0 ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_higher ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x80008000LL ) > > 32 ) & 0xffff ) ;
return 0 ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
static int apply_r_mips_highest ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 16:05:05 +03:00
{
2017-03-30 21:37:45 +03:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x800080008000LL ) > > 48 ) & 0xffff ) ;
return 0 ;
2016-02-04 16:05:05 +03:00
}
2017-03-30 21:37:45 +03:00
/**
* reloc_handler ( ) - Apply a particular relocation to a module
* @ me : the module to apply the reloc to
* @ location : the address at which the reloc is to be applied
* @ base : the existing value at location for REL - style ; 0 for RELA - style
* @ v : the value of the reloc , with addend for RELA - style
*
* Each implemented reloc_handler function applies a particular type of
* relocation to the module @ me . Relocs that may be found in either REL or RELA
* variants can be handled by making use of the @ base & @ v parameters which are
* set to values which abstract the difference away from the particular reloc
* implementations .
*
* Return : 0 upon success , else - ERRNO
*/
typedef int ( * reloc_handler ) ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela ) ;
/* The handlers for known reloc types */
static reloc_handler reloc_handlers [ ] = {
2005-02-21 13:45:09 +03:00
[ R_MIPS_NONE ] = apply_r_mips_none ,
2017-03-30 21:37:45 +03:00
[ R_MIPS_32 ] = apply_r_mips_32 ,
[ R_MIPS_26 ] = apply_r_mips_26 ,
[ R_MIPS_HI16 ] = apply_r_mips_hi16 ,
[ R_MIPS_LO16 ] = apply_r_mips_lo16 ,
[ R_MIPS_PC16 ] = apply_r_mips_pc16 ,
[ R_MIPS_64 ] = apply_r_mips_64 ,
[ R_MIPS_HIGHER ] = apply_r_mips_higher ,
[ R_MIPS_HIGHEST ] = apply_r_mips_highest ,
[ R_MIPS_PC21_S2 ] = apply_r_mips_pc21 ,
[ R_MIPS_PC26_S2 ] = apply_r_mips_pc26 ,
2005-02-21 13:45:09 +03:00
} ;
2017-03-30 21:37:45 +03:00
static int __apply_relocate ( Elf_Shdr * sechdrs , const char * strtab ,
unsigned int symindex , unsigned int relsec ,
struct module * me , bool rela )
2005-02-21 13:45:09 +03:00
{
2017-03-30 21:37:45 +03:00
union {
Elf_Mips_Rel * rel ;
Elf_Mips_Rela * rela ;
} r ;
reloc_handler handler ;
2005-02-21 13:45:09 +03:00
Elf_Sym * sym ;
2017-03-30 21:37:45 +03:00
u32 * location , base ;
2016-02-04 16:05:02 +03:00
unsigned int i , type ;
2005-02-21 13:45:09 +03:00
Elf_Addr v ;
2017-03-30 21:37:44 +03:00
int err = 0 ;
2017-03-30 21:37:45 +03:00
size_t reloc_sz ;
2005-02-21 13:45:09 +03:00
pr_debug ( " Applying relocate section %u to %u \n " , relsec ,
sechdrs [ relsec ] . sh_info ) ;
2017-03-30 21:37:45 +03:00
r . rel = ( void * ) sechdrs [ relsec ] . sh_addr ;
reloc_sz = rela ? sizeof ( * r . rela ) : sizeof ( * r . rel ) ;
2012-08-08 18:59:43 +04:00
me - > arch . r_mips_hi16_list = NULL ;
2017-03-30 21:37:45 +03:00
for ( i = 0 ; i < sechdrs [ relsec ] . sh_size / reloc_sz ; i + + ) {
2005-02-21 13:45:09 +03:00
/* This is where to make the change */
location = ( void * ) sechdrs [ sechdrs [ relsec ] . sh_info ] . sh_addr
2017-03-30 21:37:45 +03:00
+ r . rel - > r_offset ;
2005-02-21 13:45:09 +03:00
/* This is the symbol it is referring to */
sym = ( Elf_Sym * ) sechdrs [ symindex ] . sh_addr
2017-03-30 21:37:45 +03:00
+ ELF_MIPS_R_SYM ( * r . rel ) ;
2016-02-15 17:35:20 +03:00
if ( sym - > st_value > = - MAX_ERRNO ) {
2006-05-22 19:45:07 +04:00
/* Ignore unresolved weak symbol */
if ( ELF_ST_BIND ( sym - > st_info ) = = STB_WEAK )
continue ;
2016-02-04 16:05:03 +03:00
pr_warn ( " %s: Unknown symbol %s \n " ,
me - > name , strtab + sym - > st_name ) ;
2017-03-30 21:37:44 +03:00
err = - ENOENT ;
goto out ;
2005-02-21 13:45:09 +03:00
}
2017-03-30 21:37:45 +03:00
type = ELF_MIPS_R_TYPE ( * r . rel ) ;
if ( type < ARRAY_SIZE ( reloc_handlers ) )
handler = reloc_handlers [ type ] ;
2016-02-04 16:05:02 +03:00
else
handler = NULL ;
2005-02-21 13:45:09 +03:00
2016-02-04 16:05:02 +03:00
if ( ! handler ) {
pr_err ( " %s: Unknown relocation type %u \n " ,
me - > name , type ) ;
2017-03-30 21:37:44 +03:00
err = - EINVAL ;
goto out ;
2016-02-04 16:05:02 +03:00
}
2017-03-30 21:37:45 +03:00
if ( rela ) {
v = sym - > st_value + r . rela - > r_addend ;
base = 0 ;
r . rela = & r . rela [ 1 ] ;
} else {
v = sym - > st_value ;
base = * location ;
r . rel = & r . rel [ 1 ] ;
}
err = handler ( me , location , base , v , rela ) ;
2017-03-30 21:37:44 +03:00
if ( err )
goto out ;
2005-02-21 13:45:09 +03:00
}
2017-03-30 21:37:44 +03:00
out :
2012-08-14 02:34:18 +04:00
/*
2017-03-30 21:37:44 +03:00
* Normally the hi16 list should be deallocated at this point . A
2012-08-14 02:34:18 +04:00
* malformed binary however could contain a series of R_MIPS_HI16
2017-03-30 21:37:44 +03:00
* relocations not followed by a R_MIPS_LO16 relocation , or if we hit
* an error processing a reloc we might have gotten here before
* reaching the R_MIPS_LO16 . In either case , free up the list and
* return an error .
2012-08-14 02:34:18 +04:00
*/
if ( me - > arch . r_mips_hi16_list ) {
free_relocation_chain ( me - > arch . r_mips_hi16_list ) ;
me - > arch . r_mips_hi16_list = NULL ;
2017-03-30 21:37:44 +03:00
err = err ? : - ENOEXEC ;
2012-08-14 02:34:18 +04:00
}
2017-03-30 21:37:44 +03:00
return err ;
2005-02-21 13:45:09 +03:00
}
2017-03-30 21:37:45 +03:00
int apply_relocate ( Elf_Shdr * sechdrs , const char * strtab ,
unsigned int symindex , unsigned int relsec ,
struct module * me )
{
return __apply_relocate ( sechdrs , strtab , symindex , relsec , me , false ) ;
}
# ifdef CONFIG_MODULES_USE_ELF_RELA
int apply_relocate_add ( Elf_Shdr * sechdrs , const char * strtab ,
unsigned int symindex , unsigned int relsec ,
struct module * me )
{
return __apply_relocate ( sechdrs , strtab , symindex , relsec , me , true ) ;
2005-02-21 13:45:09 +03:00
}
2017-03-30 21:37:45 +03:00
# endif /* CONFIG_MODULES_USE_ELF_RELA */
2005-02-21 13:45:09 +03:00
2005-04-17 02:20:36 +04:00
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry * search_module_dbetables ( unsigned long addr )
{
unsigned long flags ;
const struct exception_table_entry * e = NULL ;
struct mod_arch_specific * dbe ;
spin_lock_irqsave ( & dbe_lock , flags ) ;
list_for_each_entry ( dbe , & dbe_list , dbe_list ) {
2017-07-11 01:51:58 +03:00
e = search_extable ( dbe - > dbe_start ,
dbe - > dbe_end - dbe - > dbe_start , addr ) ;
2005-04-17 02:20:36 +04:00
if ( e )
break ;
}
spin_unlock_irqrestore ( & dbe_lock , flags ) ;
/* Now, if we found one, we are running inside it now, hence
2013-01-22 15:59:30 +04:00
we cannot unload the module , hence no refcnt needed . */
2005-04-17 02:20:36 +04:00
return e ;
}
2007-10-20 01:10:43 +04:00
/* Put in dbe list if necessary. */
2005-04-17 02:20:36 +04:00
int module_finalize ( const Elf_Ehdr * hdr ,
const Elf_Shdr * sechdrs ,
struct module * me )
{
const Elf_Shdr * s ;
char * secstrings = ( void * ) hdr + sechdrs [ hdr - > e_shstrndx ] . sh_offset ;
2010-12-29 00:26:23 +03:00
/* Make jump label nops. */
jump_label_apply_nops ( me ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & me - > arch . dbe_list ) ;
for ( s = sechdrs ; s < sechdrs + hdr - > e_shnum ; s + + ) {
if ( strcmp ( " __dbe_table " , secstrings + s - > sh_name ) ! = 0 )
continue ;
me - > arch . dbe_start = ( void * ) s - > sh_addr ;
me - > arch . dbe_end = ( void * ) s - > sh_addr + s - > sh_size ;
spin_lock_irq ( & dbe_lock ) ;
list_add ( & me - > arch . dbe_list , & dbe_list ) ;
spin_unlock_irq ( & dbe_lock ) ;
}
return 0 ;
}
void module_arch_cleanup ( struct module * mod )
{
spin_lock_irq ( & dbe_lock ) ;
list_del ( & mod - > arch . dbe_list ) ;
spin_unlock_irq ( & dbe_lock ) ;
}