2011-03-16 15:58:30 -04:00
/*
* Jump label s390 support
*
* Copyright IBM Corp . 2011
* Author ( s ) : Jan Glauber < jang @ linux . vnet . ibm . com >
*/
# include <linux/module.h>
# include <linux/uaccess.h>
# include <linux/stop_machine.h>
# include <linux/jump_label.h>
# include <asm/ipl.h>
# ifdef HAVE_JUMP_LABEL
struct insn {
u16 opcode ;
s32 offset ;
} __packed ;
struct insn_args {
2011-09-29 10:58:46 -07:00
struct jump_entry * entry ;
enum jump_label_type type ;
2011-03-16 15:58:30 -04:00
} ;
2011-09-29 10:58:46 -07:00
static void __jump_label_transform ( struct jump_entry * entry ,
enum jump_label_type type )
2011-03-16 15:58:30 -04:00
{
struct insn insn ;
2011-09-29 10:58:46 -07:00
int rc ;
2011-03-16 15:58:30 -04:00
if ( type = = JUMP_LABEL_ENABLE ) {
/* brcl 15,offset */
insn . opcode = 0xc0f4 ;
insn . offset = ( entry - > target - entry - > code ) > > 1 ;
} else {
/* brcl 0,0 */
insn . opcode = 0xc004 ;
insn . offset = 0 ;
}
2011-09-29 10:58:46 -07:00
rc = probe_kernel_write ( ( void * ) entry - > code , & insn , JUMP_LABEL_NOP_SIZE ) ;
WARN_ON_ONCE ( rc < 0 ) ;
}
2011-03-16 15:58:30 -04:00
2011-09-29 10:58:46 -07:00
static int __sm_arch_jump_label_transform ( void * data )
{
struct insn_args * args = data ;
__jump_label_transform ( args - > entry , args - > type ) ;
return 0 ;
}
void arch_jump_label_transform ( struct jump_entry * entry ,
enum jump_label_type type )
{
struct insn_args args ;
args . entry = entry ;
args . type = type ;
stop_machine ( __sm_arch_jump_label_transform , & args , NULL ) ;
}
void arch_jump_label_transform_static ( struct jump_entry * entry ,
enum jump_label_type type )
{
__jump_label_transform ( entry , type ) ;
2011-03-16 15:58:30 -04:00
}
# endif