2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-16 15:20:36 -07:00
/* Kernel module help for PPC.
Copyright ( C ) 2001 Rusty Russell .
*/
2014-09-17 14:39:35 +10:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/moduleloader.h>
# include <linux/elf.h>
# include <linux/vmalloc.h>
# include <linux/fs.h>
# include <linux/string.h>
# include <linux/kernel.h>
2008-11-15 02:39:05 -05:00
# include <linux/ftrace.h>
2005-04-16 15:20:36 -07:00
# include <linux/cache.h>
2006-12-08 03:30:41 -08:00
# include <linux/bug.h>
2007-11-14 03:24:04 +11:00
# include <linux/sort.h>
2013-10-28 09:20:51 -05:00
# include <asm/setup.h>
2021-12-20 16:38:09 +00:00
# include <asm/code-patching.h>
2006-10-20 11:47:19 +10:00
2005-04-16 15:20:36 -07:00
/* Count how many different relocations (different symbol, different
addend ) */
static unsigned int count_relocs ( const Elf32_Rela * rela , unsigned int num )
{
2007-11-14 03:24:04 +11:00
unsigned int i , r_info , r_addend , _count_relocs ;
_count_relocs = 0 ;
r_info = 0 ;
r_addend = 0 ;
for ( i = 0 ; i < num ; i + + )
/* Only count 24-bit relocs, others don't need stubs */
if ( ELF32_R_TYPE ( rela [ i ] . r_info ) = = R_PPC_REL24 & &
( r_info ! = ELF32_R_SYM ( rela [ i ] . r_info ) | |
r_addend ! = rela [ i ] . r_addend ) ) {
_count_relocs + + ;
r_info = ELF32_R_SYM ( rela [ i ] . r_info ) ;
r_addend = rela [ i ] . r_addend ;
2005-04-16 15:20:36 -07:00
}
2007-11-14 03:24:04 +11:00
2008-11-15 02:39:05 -05:00
# ifdef CONFIG_DYNAMIC_FTRACE
_count_relocs + + ; /* add one for ftrace_caller */
# endif
2007-11-14 03:24:04 +11:00
return _count_relocs ;
}
static int relacmp ( const void * _x , const void * _y )
{
const Elf32_Rela * x , * y ;
y = ( Elf32_Rela * ) _x ;
x = ( Elf32_Rela * ) _y ;
/* Compare the entire r_info (as opposed to ELF32_R_SYM(r_info) only) to
* make the comparison cheaper / faster . It won ' t affect the sorting or
* the counting algorithms ' performance
*/
if ( x - > r_info < y - > r_info )
return - 1 ;
else if ( x - > r_info > y - > r_info )
return 1 ;
else if ( x - > r_addend < y - > r_addend )
return - 1 ;
else if ( x - > r_addend > y - > r_addend )
return 1 ;
else
return 0 ;
}
2005-04-16 15:20:36 -07:00
/* Get the potential trampolines size required of the init and
non - init sections */
static unsigned long get_plt_size ( const Elf32_Ehdr * hdr ,
const Elf32_Shdr * sechdrs ,
const char * secstrings ,
int is_init )
{
unsigned long ret = 0 ;
unsigned i ;
/* Everything marked ALLOC (this includes the exported
symbols ) */
for ( i = 1 ; i < hdr - > e_shnum ; i + + ) {
/* If it's called *.init*, and we're not init, we're
not interested */
2018-04-13 20:41:43 +02:00
if ( ( strstr ( secstrings + sechdrs [ i ] . sh_name , " .init " ) ! = NULL )
2005-04-16 15:20:36 -07:00
! = is_init )
continue ;
/* We don't want to look at debug sections. */
2018-04-13 20:41:43 +02:00
if ( strstr ( secstrings + sechdrs [ i ] . sh_name , " .debug " ) )
2005-04-16 15:20:36 -07:00
continue ;
if ( sechdrs [ i ] . sh_type = = SHT_RELA ) {
2014-09-17 14:39:35 +10:00
pr_debug ( " Found relocations in section %u \n " , i ) ;
pr_debug ( " Ptr: %p. Number: %u \n " ,
2005-04-16 15:20:36 -07:00
( void * ) hdr + sechdrs [ i ] . sh_offset ,
sechdrs [ i ] . sh_size / sizeof ( Elf32_Rela ) ) ;
2007-11-14 03:24:04 +11:00
/* Sort the relocation information based on a symbol and
* addend key . This is a stable O ( n * log n ) complexity
2022-04-30 20:56:54 +02:00
* algorithm but it will reduce the complexity of
2007-11-14 03:24:04 +11:00
* count_relocs ( ) to linear complexity O ( n )
*/
sort ( ( void * ) hdr + sechdrs [ i ] . sh_offset ,
sechdrs [ i ] . sh_size / sizeof ( Elf32_Rela ) ,
2019-04-02 23:47:22 +03:00
sizeof ( Elf32_Rela ) , relacmp , NULL ) ;
2007-11-14 03:24:04 +11:00
2005-04-16 15:20:36 -07:00
ret + = count_relocs ( ( void * ) hdr
+ sechdrs [ i ] . sh_offset ,
sechdrs [ i ] . sh_size
/ sizeof ( Elf32_Rela ) )
* sizeof ( struct ppc_plt_entry ) ;
}
}
return ret ;
}
int module_frob_arch_sections ( Elf32_Ehdr * hdr ,
Elf32_Shdr * sechdrs ,
char * secstrings ,
struct module * me )
{
unsigned int i ;
/* Find .plt and .init.plt sections */
for ( i = 0 ; i < hdr - > e_shnum ; i + + ) {
if ( strcmp ( secstrings + sechdrs [ i ] . sh_name , " .init.plt " ) = = 0 )
me - > arch . init_plt_section = i ;
else if ( strcmp ( secstrings + sechdrs [ i ] . sh_name , " .plt " ) = = 0 )
me - > arch . core_plt_section = i ;
}
if ( ! me - > arch . core_plt_section | | ! me - > arch . init_plt_section ) {
2014-09-17 14:39:35 +10:00
pr_err ( " Module doesn't contain .plt or .init.plt sections. \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOEXEC ;
}
/* Override their sizes */
sechdrs [ me - > arch . core_plt_section ] . sh_size
= get_plt_size ( hdr , sechdrs , secstrings , 0 ) ;
sechdrs [ me - > arch . init_plt_section ] . sh_size
= get_plt_size ( hdr , sechdrs , secstrings , 1 ) ;
return 0 ;
}
static inline int entry_matches ( struct ppc_plt_entry * entry , Elf32_Addr val )
{
2021-05-20 10:23:04 +00:00
if ( entry - > jump [ 0 ] ! = PPC_RAW_LIS ( _R12 , PPC_HA ( val ) ) )
2019-05-03 06:40:16 +00:00
return 0 ;
2021-05-20 10:23:04 +00:00
if ( entry - > jump [ 1 ] ! = PPC_RAW_ADDI ( _R12 , _R12 , PPC_LO ( val ) ) )
2019-05-03 06:40:16 +00:00
return 0 ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
/* Set up a trampoline in the PLT to bounce us to the distant function */
static uint32_t do_plt_call ( void * location ,
Elf32_Addr val ,
2016-03-03 15:26:54 +11:00
const Elf32_Shdr * sechdrs ,
2005-04-16 15:20:36 -07:00
struct module * mod )
{
struct ppc_plt_entry * entry ;
2014-09-17 14:39:35 +10:00
pr_debug ( " Doing plt for call to 0x%x at 0x%x \n " , val , ( unsigned int ) location ) ;
2005-04-16 15:20:36 -07:00
/* Init, or core PLT? */
module: replace module_layout with module_memory
module_layout manages different types of memory (text, data, rodata, etc.)
in one allocation, which is problematic for some reasons:
1. It is hard to enable CONFIG_STRICT_MODULE_RWX.
2. It is hard to use huge pages in modules (and not break strict rwx).
3. Many archs uses module_layout for arch-specific data, but it is not
obvious how these data are used (are they RO, RX, or RW?)
Improve the scenario by replacing 2 (or 3) module_layout per module with
up to 7 module_memory per module:
MOD_TEXT,
MOD_DATA,
MOD_RODATA,
MOD_RO_AFTER_INIT,
MOD_INIT_TEXT,
MOD_INIT_DATA,
MOD_INIT_RODATA,
and allocating them separately. This adds slightly more entries to
mod_tree (from up to 3 entries per module, to up to 7 entries per
module). However, this at most adds a small constant overhead to
__module_address(), which is expected to be fast.
Various archs use module_layout for different data. These data are put
into different module_memory based on their location in module_layout.
IOW, data that used to go with text is allocated with MOD_MEM_TYPE_TEXT;
data that used to go with data is allocated with MOD_MEM_TYPE_DATA, etc.
module_memory simplifies quite some of the module code. For example,
ARCH_WANTS_MODULES_DATA_IN_VMALLOC is a lot cleaner, as it just uses a
different allocator for the data. kernel/module/strict_rwx.c is also
much cleaner with module_memory.
Signed-off-by: Song Liu <song@kernel.org>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
2023-02-06 16:28:02 -08:00
if ( within_module_core ( ( unsigned long ) location , mod ) )
2005-04-16 15:20:36 -07:00
entry = ( void * ) sechdrs [ mod - > arch . core_plt_section ] . sh_addr ;
else
entry = ( void * ) sechdrs [ mod - > arch . init_plt_section ] . sh_addr ;
/* Find this entry, or if that fails, the next avail. entry */
while ( entry - > jump [ 0 ] ) {
if ( entry_matches ( entry , val ) ) return ( uint32_t ) entry ;
entry + + ;
}
2021-12-20 16:38:09 +00:00
if ( patch_instruction ( & entry - > jump [ 0 ] , ppc_inst ( PPC_RAW_LIS ( _R12 , PPC_HA ( val ) ) ) ) )
return 0 ;
if ( patch_instruction ( & entry - > jump [ 1 ] , ppc_inst ( PPC_RAW_ADDI ( _R12 , _R12 , PPC_LO ( val ) ) ) ) )
return 0 ;
if ( patch_instruction ( & entry - > jump [ 2 ] , ppc_inst ( PPC_RAW_MTCTR ( _R12 ) ) ) )
return 0 ;
if ( patch_instruction ( & entry - > jump [ 3 ] , ppc_inst ( PPC_RAW_BCTR ( ) ) ) )
return 0 ;
2005-04-16 15:20:36 -07:00
2014-09-17 14:39:35 +10:00
pr_debug ( " Initialized plt for 0x%x at %p \n " , val , entry ) ;
2005-04-16 15:20:36 -07:00
return ( uint32_t ) entry ;
}
2021-12-20 16:38:09 +00:00
static int patch_location_16 ( uint32_t * loc , u16 value )
{
loc = PTR_ALIGN_DOWN ( loc , sizeof ( u32 ) ) ;
return patch_instruction ( loc , ppc_inst ( ( * loc & 0xffff0000 ) | value ) ) ;
}
2005-04-16 15:20:36 -07:00
int apply_relocate_add ( Elf32_Shdr * sechdrs ,
const char * strtab ,
unsigned int symindex ,
unsigned int relsec ,
struct module * module )
{
unsigned int i ;
Elf32_Rela * rela = ( void * ) sechdrs [ relsec ] . sh_addr ;
Elf32_Sym * sym ;
uint32_t * location ;
uint32_t value ;
2014-09-17 14:39:35 +10:00
pr_debug ( " Applying ADD relocate section %u to %u \n " , relsec ,
2005-04-16 15:20:36 -07:00
sechdrs [ relsec ] . sh_info ) ;
for ( i = 0 ; i < sechdrs [ relsec ] . sh_size / sizeof ( * rela ) ; i + + ) {
/* This is where to make the change */
location = ( void * ) sechdrs [ sechdrs [ relsec ] . sh_info ] . sh_addr
+ rela [ i ] . r_offset ;
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved . */
sym = ( Elf32_Sym * ) sechdrs [ symindex ] . sh_addr
+ ELF32_R_SYM ( rela [ i ] . r_info ) ;
/* `Everything is relative'. */
value = sym - > st_value + rela [ i ] . r_addend ;
switch ( ELF32_R_TYPE ( rela [ i ] . r_info ) ) {
case R_PPC_ADDR32 :
/* Simply set it */
* ( uint32_t * ) location = value ;
break ;
case R_PPC_ADDR16_LO :
/* Low half of the symbol */
2021-12-20 16:38:09 +00:00
if ( patch_location_16 ( location , PPC_LO ( value ) ) )
return - EFAULT ;
2005-04-16 15:20:36 -07:00
break ;
2007-01-03 07:49:56 +01:00
case R_PPC_ADDR16_HI :
/* Higher half of the symbol */
2021-12-20 16:38:09 +00:00
if ( patch_location_16 ( location , PPC_HI ( value ) ) )
return - EFAULT ;
2007-01-03 07:49:56 +01:00
break ;
2005-04-16 15:20:36 -07:00
case R_PPC_ADDR16_HA :
2021-12-20 16:38:09 +00:00
if ( patch_location_16 ( location , PPC_HA ( value ) ) )
return - EFAULT ;
2005-04-16 15:20:36 -07:00
break ;
case R_PPC_REL24 :
if ( ( int ) ( value - ( uint32_t ) location ) < - 0x02000000
2021-12-20 16:38:09 +00:00
| | ( int ) ( value - ( uint32_t ) location ) > = 0x02000000 ) {
2005-04-16 15:20:36 -07:00
value = do_plt_call ( location , value ,
sechdrs , module ) ;
2021-12-20 16:38:09 +00:00
if ( ! value )
return - EFAULT ;
}
2005-04-16 15:20:36 -07:00
/* Only replace bits 2 through 26 */
2014-09-17 14:39:35 +10:00
pr_debug ( " REL24 value = %08X. location = %08X \n " ,
2005-04-16 15:20:36 -07:00
value , ( uint32_t ) location ) ;
2014-09-17 14:39:35 +10:00
pr_debug ( " Location before: %08X. \n " ,
2005-04-16 15:20:36 -07:00
* ( uint32_t * ) location ) ;
2022-05-09 07:36:21 +02:00
value = ( * ( uint32_t * ) location & ~ PPC_LI_MASK ) |
PPC_LI ( value - ( uint32_t ) location ) ;
2021-12-20 16:38:09 +00:00
if ( patch_instruction ( location , ppc_inst ( value ) ) )
return - EFAULT ;
2014-09-17 14:39:35 +10:00
pr_debug ( " Location after: %08X. \n " ,
2005-04-16 15:20:36 -07:00
* ( uint32_t * ) location ) ;
2014-09-17 14:39:35 +10:00
pr_debug ( " ie. jump to %08X+%08X = %08X \n " ,
2022-05-09 07:36:21 +02:00
* ( uint32_t * ) PPC_LI ( ( uint32_t ) location ) , ( uint32_t ) location ,
( * ( uint32_t * ) PPC_LI ( ( uint32_t ) location ) ) + ( uint32_t ) location ) ;
2005-04-16 15:20:36 -07:00
break ;
case R_PPC_REL32 :
/* 32-bit relative jump. */
* ( uint32_t * ) location = value - ( uint32_t ) location ;
break ;
default :
2014-09-17 14:39:35 +10:00
pr_err ( " %s: unknown ADD relocation: %u \n " ,
2005-04-16 15:20:36 -07:00
module - > name ,
ELF32_R_TYPE ( rela [ i ] . r_info ) ) ;
return - ENOEXEC ;
}
}
2016-03-03 15:26:54 +11:00
return 0 ;
}
2008-11-15 02:39:05 -05:00
# ifdef CONFIG_DYNAMIC_FTRACE
2022-05-09 07:36:19 +02:00
notrace int module_trampoline_target ( struct module * mod , unsigned long addr ,
unsigned long * target )
2021-10-28 14:24:03 +02:00
{
2022-05-09 07:36:19 +02:00
ppc_inst_t jmp [ 4 ] ;
2021-10-28 14:24:03 +02:00
/* Find where the trampoline jumps to */
2022-05-09 07:36:19 +02:00
if ( copy_inst_from_kernel_nofault ( jmp , ( void * ) addr ) )
return - EFAULT ;
if ( __copy_inst_from_kernel_nofault ( jmp + 1 , ( void * ) addr + 4 ) )
return - EFAULT ;
if ( __copy_inst_from_kernel_nofault ( jmp + 2 , ( void * ) addr + 8 ) )
return - EFAULT ;
if ( __copy_inst_from_kernel_nofault ( jmp + 3 , ( void * ) addr + 12 ) )
2021-10-28 14:24:03 +02:00
return - EFAULT ;
/* verify that this is what we expect it to be */
2022-05-09 07:36:19 +02:00
if ( ( ppc_inst_val ( jmp [ 0 ] ) & 0xffff0000 ) ! = PPC_RAW_LIS ( _R12 , 0 ) )
return - EINVAL ;
if ( ( ppc_inst_val ( jmp [ 1 ] ) & 0xffff0000 ) ! = PPC_RAW_ADDI ( _R12 , _R12 , 0 ) )
return - EINVAL ;
if ( ppc_inst_val ( jmp [ 2 ] ) ! = PPC_RAW_MTCTR ( _R12 ) )
return - EINVAL ;
if ( ppc_inst_val ( jmp [ 3 ] ) ! = PPC_RAW_BCTR ( ) )
2021-10-28 14:24:03 +02:00
return - EINVAL ;
2022-05-09 07:36:19 +02:00
addr = ( ppc_inst_val ( jmp [ 1 ] ) & 0xffff ) | ( ( ppc_inst_val ( jmp [ 0 ] ) & 0xffff ) < < 16 ) ;
2021-10-28 14:24:03 +02:00
if ( addr & 0x8000 )
addr - = 0x10000 ;
* target = addr ;
return 0 ;
}
2016-03-03 15:26:54 +11:00
int module_finalize_ftrace ( struct module * module , const Elf_Shdr * sechdrs )
{
module: replace module_layout with module_memory
module_layout manages different types of memory (text, data, rodata, etc.)
in one allocation, which is problematic for some reasons:
1. It is hard to enable CONFIG_STRICT_MODULE_RWX.
2. It is hard to use huge pages in modules (and not break strict rwx).
3. Many archs uses module_layout for arch-specific data, but it is not
obvious how these data are used (are they RO, RX, or RW?)
Improve the scenario by replacing 2 (or 3) module_layout per module with
up to 7 module_memory per module:
MOD_TEXT,
MOD_DATA,
MOD_RODATA,
MOD_RO_AFTER_INIT,
MOD_INIT_TEXT,
MOD_INIT_DATA,
MOD_INIT_RODATA,
and allocating them separately. This adds slightly more entries to
mod_tree (from up to 3 entries per module, to up to 7 entries per
module). However, this at most adds a small constant overhead to
__module_address(), which is expected to be fast.
Various archs use module_layout for different data. These data are put
into different module_memory based on their location in module_layout.
IOW, data that used to go with text is allocated with MOD_MEM_TYPE_TEXT;
data that used to go with data is allocated with MOD_MEM_TYPE_DATA, etc.
module_memory simplifies quite some of the module code. For example,
ARCH_WANTS_MODULES_DATA_IN_VMALLOC is a lot cleaner, as it just uses a
different allocator for the data. kernel/module/strict_rwx.c is also
much cleaner with module_memory.
Signed-off-by: Song Liu <song@kernel.org>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
2023-02-06 16:28:02 -08:00
module - > arch . tramp = do_plt_call ( module - > mem [ MOD_TEXT ] . base ,
2016-03-03 15:26:54 +11:00
( unsigned long ) ftrace_caller ,
sechdrs , module ) ;
if ( ! module - > arch . tramp )
return - ENOENT ;
2021-10-28 14:24:04 +02:00
# ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
module: replace module_layout with module_memory
module_layout manages different types of memory (text, data, rodata, etc.)
in one allocation, which is problematic for some reasons:
1. It is hard to enable CONFIG_STRICT_MODULE_RWX.
2. It is hard to use huge pages in modules (and not break strict rwx).
3. Many archs uses module_layout for arch-specific data, but it is not
obvious how these data are used (are they RO, RX, or RW?)
Improve the scenario by replacing 2 (or 3) module_layout per module with
up to 7 module_memory per module:
MOD_TEXT,
MOD_DATA,
MOD_RODATA,
MOD_RO_AFTER_INIT,
MOD_INIT_TEXT,
MOD_INIT_DATA,
MOD_INIT_RODATA,
and allocating them separately. This adds slightly more entries to
mod_tree (from up to 3 entries per module, to up to 7 entries per
module). However, this at most adds a small constant overhead to
__module_address(), which is expected to be fast.
Various archs use module_layout for different data. These data are put
into different module_memory based on their location in module_layout.
IOW, data that used to go with text is allocated with MOD_MEM_TYPE_TEXT;
data that used to go with data is allocated with MOD_MEM_TYPE_DATA, etc.
module_memory simplifies quite some of the module code. For example,
ARCH_WANTS_MODULES_DATA_IN_VMALLOC is a lot cleaner, as it just uses a
different allocator for the data. kernel/module/strict_rwx.c is also
much cleaner with module_memory.
Signed-off-by: Song Liu <song@kernel.org>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
2023-02-06 16:28:02 -08:00
module - > arch . tramp_regs = do_plt_call ( module - > mem [ MOD_TEXT ] . base ,
2021-10-28 14:24:04 +02:00
( unsigned long ) ftrace_regs_caller ,
sechdrs , module ) ;
if ( ! module - > arch . tramp_regs )
return - ENOENT ;
# endif
2005-04-16 15:20:36 -07:00
return 0 ;
}
2016-03-03 15:26:54 +11:00
# endif