2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-02-21 10:45:09 +00:00
/*
*
* Copyright ( C ) 2001 Rusty Russell .
* Copyright ( C ) 2003 , 2004 Ralf Baechle ( ralf @ linux - mips . org )
* Copyright ( C ) 2005 Thiemo Seufer
*/
# undef DEBUG
2016-08-15 19:11:52 -04:00
# include <linux/extable.h>
2005-02-21 10:45:09 +00:00
# include <linux/moduleloader.h>
# include <linux/elf.h>
2008-07-23 21:28:13 -07:00
# include <linux/mm.h>
2013-09-18 14:54:37 +02:00
# include <linux/numa.h>
2005-02-21 10:45:09 +00:00
# include <linux/vmalloc.h>
# include <linux/slab.h>
# include <linux/fs.h>
# include <linux/string.h>
# include <linux/kernel.h>
2005-04-16 15:20:36 -07:00
# include <linux/spinlock.h>
2010-12-28 13:26:23 -08:00
# include <linux/jump_label.h>
2005-04-16 15:20:36 -07:00
2005-02-21 10:45:09 +00:00
struct mips_hi16 {
struct mips_hi16 * next ;
Elf_Addr * addr ;
Elf_Addr value ;
} ;
2005-04-16 15:20:36 -07:00
static LIST_HEAD ( dbe_list ) ;
static DEFINE_SPINLOCK ( dbe_lock ) ;
2011-06-30 21:22:12 +02:00
# ifdef MODULE_START
2005-02-21 10:45:09 +00:00
void * module_alloc ( unsigned long size )
{
2011-01-13 15:46:02 -08:00
return __vmalloc_node_range ( size , 1 , MODULE_START , MODULE_END ,
2015-02-13 14:40:07 -08:00
GFP_KERNEL , PAGE_KERNEL , 0 , NUMA_NO_NODE ,
2011-01-13 15:46:02 -08:00
__builtin_return_address ( 0 ) ) ;
2005-02-21 10:45:09 +00:00
}
2011-06-30 21:22:12 +02:00
# endif
2005-02-21 10:45:09 +00:00
2017-03-30 11:37:45 -07:00
static int apply_r_mips_none ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 10:45:09 +00:00
{
return 0 ;
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_32 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 10:45:09 +00:00
{
2017-03-30 11:37:45 -07:00
* location = base + v ;
2005-02-21 10:45:09 +00:00
return 0 ;
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_26 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 10:45:09 +00:00
{
if ( v % 4 ) {
2017-03-30 11:37:45 -07:00
pr_err ( " module %s: dangerous R_MIPS_26 relocation \n " ,
2009-08-03 10:50:19 +01:00
me - > name ) ;
2005-02-21 10:45:09 +00:00
return - ENOEXEC ;
}
if ( ( v & 0xf0000000 ) ! = ( ( ( unsigned long ) location + 4 ) & 0xf0000000 ) ) {
2016-02-04 13:05:03 +00:00
pr_err ( " module %s: relocation overflow \n " ,
2005-02-21 10:45:09 +00:00
me - > name ) ;
return - ENOEXEC ;
}
* location = ( * location & ~ 0x03ffffff ) |
2017-03-30 11:37:45 -07:00
( ( base + ( v > > 2 ) ) & 0x03ffffff ) ;
2005-02-21 10:45:09 +00:00
return 0 ;
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_hi16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 10:45:09 +00:00
{
struct mips_hi16 * n ;
2017-03-30 11:37:45 -07:00
if ( rela ) {
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x8000LL ) > > 16 ) & 0xffff ) ;
return 0 ;
}
2005-02-21 10:45:09 +00: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 16:59:43 +02:00
n - > next = me - > arch . r_mips_hi16_list ;
me - > arch . r_mips_hi16_list = n ;
2005-02-21 10:45:09 +00:00
return 0 ;
}
2012-08-14 00:34:18 +02: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 11:37:45 -07:00
static int apply_r_mips_lo16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2005-02-21 10:45:09 +00:00
{
2017-03-30 11:37:45 -07:00
unsigned long insnlo = base ;
2012-08-14 00:34:18 +02:00
struct mips_hi16 * l ;
2005-02-21 10:45:09 +00:00
Elf_Addr val , vallo ;
2017-03-30 11:37:45 -07:00
if ( rela ) {
* location = ( * location & 0xffff0000 ) | ( v & 0xffff ) ;
return 0 ;
}
2013-01-22 12:59:30 +01:00
/* Sign extend the addend we extract from the lo insn. */
2005-02-21 10:45:09 +00:00
vallo = ( ( insnlo & 0xffff ) ^ 0x8000 ) - 0x8000 ;
2012-08-08 16:59:43 +02:00
if ( me - > arch . r_mips_hi16_list ! = NULL ) {
l = me - > arch . r_mips_hi16_list ;
2005-02-21 10:45:09 +00:00
while ( l ! = NULL ) {
2012-08-14 00:34:18 +02:00
struct mips_hi16 * next ;
2005-02-21 10:45:09 +00: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 16:59:43 +02:00
me - > arch . r_mips_hi16_list = NULL ;
2005-02-21 10:45:09 +00:00
}
/*
2013-01-22 12:59:30 +01:00
* Ok , we ' re done with the HI16 relocs . Now deal with the LO16 .
2005-02-21 10:45:09 +00:00
*/
val = v + vallo ;
insnlo = ( insnlo & ~ 0xffff ) | ( val & 0xffff ) ;
* location = insnlo ;
return 0 ;
out_danger :
2012-08-14 00:34:18 +02:00
free_relocation_chain ( l ) ;
me - > arch . r_mips_hi16_list = NULL ;
2012-08-08 14:57:03 +02:00
2017-03-30 11:37:45 -07:00
pr_err ( " module %s: dangerous R_MIPS_LO16 relocation \n " , me - > name ) ;
2005-02-21 10:45:09 +00:00
return - ENOEXEC ;
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_pc ( struct module * me , u32 * location , u32 base ,
Elf_Addr v , unsigned int bits )
2016-02-04 13:05:05 +00:00
{
unsigned long mask = GENMASK ( bits - 1 , 0 ) ;
unsigned long se_bits ;
long offset ;
if ( v % 4 ) {
2017-03-30 11:37:45 -07:00
pr_err ( " module %s: dangerous R_MIPS_PC%u relocation \n " ,
2016-02-04 13:05:05 +00:00
me - > name , bits ) ;
return - ENOEXEC ;
}
2017-03-30 11:37:45 -07:00
/* retrieve & sign extend implicit addend if any */
offset = base & mask ;
2016-02-04 13:05:05 +00: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 11:37:45 -07:00
static int apply_r_mips_pc16 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
return apply_r_mips_pc ( me , location , base , v , 16 ) ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_pc21 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
return apply_r_mips_pc ( me , location , base , v , 21 ) ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_pc26 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
return apply_r_mips_pc ( me , location , base , v , 26 ) ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_64 ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* ( Elf_Addr * ) location = v ;
return 0 ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_higher ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x80008000LL ) > > 32 ) & 0xffff ) ;
return 0 ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07:00
static int apply_r_mips_highest ( struct module * me , u32 * location ,
u32 base , Elf_Addr v , bool rela )
2016-02-04 13:05:05 +00:00
{
2017-03-30 11:37:45 -07:00
if ( WARN_ON ( ! rela ) )
return - EINVAL ;
* location = ( * location & 0xffff0000 ) |
( ( ( ( long long ) v + 0x800080008000LL ) > > 48 ) & 0xffff ) ;
return 0 ;
2016-02-04 13:05:05 +00:00
}
2017-03-30 11:37:45 -07: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 10:45:09 +00:00
[ R_MIPS_NONE ] = apply_r_mips_none ,
2017-03-30 11:37:45 -07: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 10:45:09 +00:00
} ;
2017-03-30 11:37:45 -07: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 10:45:09 +00:00
{
2017-03-30 11:37:45 -07:00
union {
Elf_Mips_Rel * rel ;
Elf_Mips_Rela * rela ;
} r ;
reloc_handler handler ;
2005-02-21 10:45:09 +00:00
Elf_Sym * sym ;
2017-03-30 11:37:45 -07:00
u32 * location , base ;
2016-02-04 13:05:02 +00:00
unsigned int i , type ;
2005-02-21 10:45:09 +00:00
Elf_Addr v ;
2017-03-30 11:37:44 -07:00
int err = 0 ;
2017-03-30 11:37:45 -07:00
size_t reloc_sz ;
2005-02-21 10:45:09 +00:00
pr_debug ( " Applying relocate section %u to %u \n " , relsec ,
sechdrs [ relsec ] . sh_info ) ;
2017-03-30 11:37:45 -07:00
r . rel = ( void * ) sechdrs [ relsec ] . sh_addr ;
reloc_sz = rela ? sizeof ( * r . rela ) : sizeof ( * r . rel ) ;
2012-08-08 16:59:43 +02:00
me - > arch . r_mips_hi16_list = NULL ;
2017-03-30 11:37:45 -07:00
for ( i = 0 ; i < sechdrs [ relsec ] . sh_size / reloc_sz ; i + + ) {
2005-02-21 10:45:09 +00:00
/* This is where to make the change */
location = ( void * ) sechdrs [ sechdrs [ relsec ] . sh_info ] . sh_addr
2017-03-30 11:37:45 -07:00
+ r . rel - > r_offset ;
2005-02-21 10:45:09 +00:00
/* This is the symbol it is referring to */
sym = ( Elf_Sym * ) sechdrs [ symindex ] . sh_addr
2017-03-30 11:37:45 -07:00
+ ELF_MIPS_R_SYM ( * r . rel ) ;
2016-02-15 15:35:20 +01:00
if ( sym - > st_value > = - MAX_ERRNO ) {
2006-05-23 00:45:07 +09:00
/* Ignore unresolved weak symbol */
if ( ELF_ST_BIND ( sym - > st_info ) = = STB_WEAK )
continue ;
2016-02-04 13:05:03 +00:00
pr_warn ( " %s: Unknown symbol %s \n " ,
me - > name , strtab + sym - > st_name ) ;
2017-03-30 11:37:44 -07:00
err = - ENOENT ;
goto out ;
2005-02-21 10:45:09 +00:00
}
2017-03-30 11:37:45 -07:00
type = ELF_MIPS_R_TYPE ( * r . rel ) ;
if ( type < ARRAY_SIZE ( reloc_handlers ) )
handler = reloc_handlers [ type ] ;
2016-02-04 13:05:02 +00:00
else
handler = NULL ;
2005-02-21 10:45:09 +00:00
2016-02-04 13:05:02 +00:00
if ( ! handler ) {
pr_err ( " %s: Unknown relocation type %u \n " ,
me - > name , type ) ;
2017-03-30 11:37:44 -07:00
err = - EINVAL ;
goto out ;
2016-02-04 13:05:02 +00:00
}
2017-03-30 11:37:45 -07: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 11:37:44 -07:00
if ( err )
goto out ;
2005-02-21 10:45:09 +00:00
}
2017-03-30 11:37:44 -07:00
out :
2012-08-14 00:34:18 +02:00
/*
2017-03-30 11:37:44 -07:00
* Normally the hi16 list should be deallocated at this point . A
2012-08-14 00:34:18 +02:00
* malformed binary however could contain a series of R_MIPS_HI16
2017-03-30 11:37:44 -07: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 00:34:18 +02: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 11:37:44 -07:00
err = err ? : - ENOEXEC ;
2012-08-14 00:34:18 +02:00
}
2017-03-30 11:37:44 -07:00
return err ;
2005-02-21 10:45:09 +00:00
}
2017-03-30 11:37:45 -07: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 10:45:09 +00:00
}
2017-03-30 11:37:45 -07:00
# endif /* CONFIG_MODULES_USE_ELF_RELA */
2005-02-21 10:45:09 +00:00
2005-04-16 15:20:36 -07: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-10 15:51:58 -07:00
e = search_extable ( dbe - > dbe_start ,
dbe - > dbe_end - dbe - > dbe_start , addr ) ;
2005-04-16 15:20:36 -07: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 12:59:30 +01:00
we cannot unload the module , hence no refcnt needed . */
2005-04-16 15:20:36 -07:00
return e ;
}
2007-10-19 23:10:43 +02:00
/* Put in dbe list if necessary. */
2005-04-16 15:20:36 -07: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-28 13:26:23 -08:00
/* Make jump label nops. */
jump_label_apply_nops ( me ) ;
2005-04-16 15:20:36 -07: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 ) ;
}