2008-05-14 09:06:59 +04:00
# include <linux/spinlock.h>
# include <linux/hardirq.h>
# include <linux/ftrace.h>
# include <linux/percpu.h>
# include <linux/init.h>
# include <linux/list.h>
2008-06-21 22:17:27 +04:00
# include <asm/ftrace.h>
2008-05-14 09:06:59 +04:00
static const u32 ftrace_nop = 0x01000000 ;
2008-10-23 17:33:08 +04:00
unsigned char * ftrace_nop_replace ( void )
2008-05-14 09:06:59 +04:00
{
return ( char * ) & ftrace_nop ;
}
2008-10-23 17:33:08 +04:00
unsigned char * ftrace_call_replace ( unsigned long ip , unsigned long addr )
2008-05-14 09:06:59 +04:00
{
static u32 call ;
s32 off ;
off = ( ( s32 ) addr - ( s32 ) ip ) ;
call = 0x40000000 | ( ( u32 ) off > > 2 ) ;
return ( unsigned char * ) & call ;
}
2008-10-23 17:33:08 +04:00
int
2008-05-14 09:06:59 +04:00
ftrace_modify_code ( unsigned long ip , unsigned char * old_code ,
unsigned char * new_code )
{
u32 old = * ( u32 * ) old_code ;
u32 new = * ( u32 * ) new_code ;
u32 replaced ;
int faulted ;
__asm__ __volatile__ (
" 1: cas [%[ip]], %[old], %[new] \n "
" flush %[ip] \n "
" mov 0, %[faulted] \n "
" 2: \n "
" .section .fixup,#alloc,#execinstr \n "
" .align 4 \n "
" 3: sethi %%hi(2b), %[faulted] \n "
" jmpl %[faulted] + %%lo(2b), %%g0 \n "
" mov 1, %[faulted] \n "
" .previous \n "
" .section __ex_table, \" a \" \n "
" .align 4 \n "
" .word 1b, 3b \n "
" .previous \n "
: " =r " ( replaced ) , [ faulted ] " =r " ( faulted )
: [ new ] " 0 " ( new ) , [ old ] " r " ( old ) , [ ip ] " r " ( ip )
: " memory " ) ;
if ( replaced ! = old & & replaced ! = new )
faulted = 2 ;
return faulted ;
}
2008-10-23 17:33:08 +04:00
int ftrace_update_ftrace_func ( ftrace_func_t func )
2008-05-14 09:06:59 +04:00
{
unsigned long ip = ( unsigned long ) ( & ftrace_call ) ;
2008-06-21 22:17:27 +04:00
unsigned char old [ MCOUNT_INSN_SIZE ] , * new ;
2008-05-14 09:06:59 +04:00
2008-06-21 22:17:27 +04:00
memcpy ( old , & ftrace_call , MCOUNT_INSN_SIZE ) ;
2008-05-14 09:06:59 +04:00
new = ftrace_call_replace ( ip , ( unsigned long ) func ) ;
return ftrace_modify_code ( ip , old , new ) ;
}
int __init ftrace_dyn_arch_init ( void * data )
{
ftrace_mcount_set ( data ) ;
return 0 ;
}