2008-10-22 22:26:29 -07:00
# ifndef _ASM_X86_ALTERNATIVE_H
# define _ASM_X86_ALTERNATIVE_H
2008-01-30 13:30:30 +01:00
# include <linux/types.h>
# include <linux/stddef.h>
2009-04-28 11:13:46 -04:00
# include <linux/stringify.h>
2008-01-30 13:30:30 +01:00
# include <asm/asm.h>
/*
* Alternative inline assembly for SMP .
*
* The LOCK_PREFIX macro defined here replaces the LOCK and
* LOCK_PREFIX macros used everywhere in the source tree .
*
* SMP alternatives use the same data structures as the other
* alternatives and the X86_FEATURE_UP flag to indicate the case of a
* UP system running a SMP kernel . The existing apply_alternatives ( )
* works fine for patching a SMP kernel for UP .
*
* The SMP alternative tables can be kept after boot and contain both
* UP and SMP versions of the instructions to allow switching back to
* SMP at runtime , when hotplugging in a new CPU , which is especially
* useful in virtualized environments .
*
* The very common lock prefix is handled as special case in a
* separate table which is a pure address list without replacement ptr
* and size information . That keeps the table sizes small .
*/
# ifdef CONFIG_SMP
2010-02-24 10:54:22 +01:00
# define LOCK_PREFIX_HERE \
2012-09-21 12:43:08 -07:00
" .pushsection .smp_locks, \" a \" \n " \
" .balign 4 \n " \
" .long 671f - . \n " /* offset */ \
" .popsection \n " \
2010-02-24 10:54:22 +01:00
" 671: "
# define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
2008-01-30 13:30:30 +01:00
# else /* ! CONFIG_SMP */
2010-04-29 16:03:57 -07:00
# define LOCK_PREFIX_HERE ""
2008-01-30 13:30:30 +01:00
# define LOCK_PREFIX ""
# endif
struct alt_instr {
2011-07-13 09:24:10 -04:00
s32 instr_offset ; /* original instruction */
s32 repl_offset ; /* offset to replacement instruction */
2010-06-10 00:10:43 +00:00
u16 cpuid ; /* cpuid bit set for replacement */
2008-01-30 13:30:30 +01:00
u8 instrlen ; /* length of original instruction */
u8 replacementlen ; /* length of new instruction, <= instrlen */
} ;
extern void alternative_instructions ( void ) ;
extern void apply_alternatives ( struct alt_instr * start , struct alt_instr * end ) ;
struct module ;
# ifdef CONFIG_SMP
extern void alternatives_smp_module_add ( struct module * mod , char * name ,
void * locks , void * locks_end ,
void * text , void * text_end ) ;
extern void alternatives_smp_module_del ( struct module * mod ) ;
2012-08-06 17:29:49 +09:30
extern void alternatives_enable_smp ( void ) ;
2010-02-02 16:49:11 -05:00
extern int alternatives_text_reserved ( void * start , void * end ) ;
2010-11-23 16:11:40 -08:00
extern bool skip_smp_alternatives ;
2008-01-30 13:30:30 +01:00
# else
static inline void alternatives_smp_module_add ( struct module * mod , char * name ,
2008-03-23 01:01:37 -07:00
void * locks , void * locks_end ,
void * text , void * text_end ) { }
2008-01-30 13:30:30 +01:00
static inline void alternatives_smp_module_del ( struct module * mod ) { }
2012-08-06 17:29:49 +09:30
static inline void alternatives_enable_smp ( void ) { }
2010-02-02 16:49:11 -05:00
static inline int alternatives_text_reserved ( void * start , void * end )
{
return 0 ;
}
2008-01-30 13:30:30 +01:00
# endif /* CONFIG_SMP */
2012-05-24 18:19:45 -07:00
# define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n"
# define b_replacement(number) "663"#number
# define e_replacement(number) "664"#number
# define alt_slen "662b-661b"
# define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f"
# define ALTINSTR_ENTRY(feature, number) \
" .long 661b - . \n " /* label */ \
" .long " b_replacement ( number ) " f - . \n " /* new instruction */ \
" .word " __stringify ( feature ) " \n " /* feature bit */ \
" .byte " alt_slen " \n " /* source len */ \
" .byte " alt_rlen ( number ) " \n " /* replacement len */
# define DISCARD_ENTRY(number) /* rlen <= slen */ \
" .byte 0xff + ( " alt_rlen ( number ) " ) - ( " alt_slen " ) \n "
# define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \
b_replacement ( number ) " : \n \t " newinstr " \n " e_replacement ( number ) " : \n \t "
2009-04-28 11:13:46 -04:00
/* alternative assembly primitive: */
# define ALTERNATIVE(oldinstr, newinstr, feature) \
2012-05-24 18:19:45 -07:00
OLDINSTR ( oldinstr ) \
2012-09-21 12:43:08 -07:00
" .pushsection .altinstructions, \" a \" \n " \
2012-05-24 18:19:45 -07:00
ALTINSTR_ENTRY ( feature , 1 ) \
2012-09-21 12:43:08 -07:00
" .popsection \n " \
" .pushsection .discard, \" aw \" ,@progbits \n " \
2012-05-24 18:19:45 -07:00
DISCARD_ENTRY ( 1 ) \
2012-09-21 12:43:08 -07:00
" .popsection \n " \
" .pushsection .altinstr_replacement, \" ax \" \n " \
2012-05-24 18:19:45 -07:00
ALTINSTR_REPLACEMENT ( newinstr , feature , 1 ) \
2012-09-21 12:43:08 -07:00
" .popsection "
2012-05-24 18:19:45 -07:00
# define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
OLDINSTR ( oldinstr ) \
2012-09-21 12:43:08 -07:00
" .pushsection .altinstructions, \" a \" \n " \
2012-05-24 18:19:45 -07:00
ALTINSTR_ENTRY ( feature1 , 1 ) \
ALTINSTR_ENTRY ( feature2 , 2 ) \
2012-09-21 12:43:08 -07:00
" .popsection \n " \
" .pushsection .discard, \" aw \" ,@progbits \n " \
2012-05-24 18:19:45 -07:00
DISCARD_ENTRY ( 1 ) \
DISCARD_ENTRY ( 2 ) \
2012-09-21 12:43:08 -07:00
" .popsection \n " \
" .pushsection .altinstr_replacement, \" ax \" \n " \
2012-05-24 18:19:45 -07:00
ALTINSTR_REPLACEMENT ( newinstr1 , feature1 , 1 ) \
ALTINSTR_REPLACEMENT ( newinstr2 , feature2 , 2 ) \
2012-09-21 12:43:08 -07:00
" .popsection "
2009-04-28 11:13:46 -04:00
2010-03-05 17:34:46 +01:00
/*
* This must be included * after * the definition of ALTERNATIVE due to
* < asm / arch_hweight . h >
*/
# include <asm/cpufeature.h>
2008-01-30 13:30:30 +01:00
/*
* Alternative instructions for different CPU types or capabilities .
*
* This allows to use optimized instructions even on generic binary
* kernels .
*
* length of oldinstr must be longer or equal the length of newinstr
* It can be padded with nops as needed .
*
* For non barrier like inlines please define new variants
* without volatile and memory clobber .
*/
# define alternative(oldinstr, newinstr, feature) \
2009-04-28 11:13:46 -04:00
asm volatile ( ALTERNATIVE ( oldinstr , newinstr , feature ) : : : " memory " )
2008-01-30 13:30:30 +01:00
/*
* Alternative inline assembly with input .
*
* Pecularities :
* No memory clobber here .
* Argument numbers start with 1.
* Best is to use constraints that are fixed size ( like ( % 1 ) . . . " r " )
* If you use variable sized constraints like " m " or " g " in the
* replacement make sure to pad to the worst case length .
2009-04-28 11:13:46 -04:00
* Leaving an unused argument 0 to keep API compatibility .
2008-01-30 13:30:30 +01:00
*/
# define alternative_input(oldinstr, newinstr, feature, input...) \
2009-04-28 11:13:46 -04:00
asm volatile ( ALTERNATIVE ( oldinstr , newinstr , feature ) \
: : " i " ( 0 ) , # # input )
2008-01-30 13:30:30 +01:00
/* Like alternative_input, but with a single output argument */
# define alternative_io(oldinstr, newinstr, feature, output, input...) \
2009-04-28 11:13:46 -04:00
asm volatile ( ALTERNATIVE ( oldinstr , newinstr , feature ) \
: output : " i " ( 0 ) , # # input )
2008-01-30 13:30:30 +01:00
2009-12-18 16:12:56 +00:00
/* Like alternative_io, but for replacing a direct call with another one. */
# define alternative_call(oldfunc, newfunc, feature, output, input...) \
asm volatile ( ALTERNATIVE ( " call %P[old] " , " call %P[new] " , feature ) \
: output : [ old ] " i " ( oldfunc ) , [ new ] " i " ( newfunc ) , # # input )
2012-05-24 18:19:45 -07:00
/*
* Like alternative_call , but there are two features and respective functions .
* If CPU has feature2 , function2 is used .
* Otherwise , if CPU has feature1 , function1 is used .
* Otherwise , old function is used .
*/
# define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
output , input . . . ) \
asm volatile ( ALTERNATIVE_2 ( " call %P[old] " , " call %P[new1] " , feature1 , \
" call %P[new2] " , feature2 ) \
: output : [ old ] " i " ( oldfunc ) , [ new1 ] " i " ( newfunc1 ) , \
[ new2 ] " i " ( newfunc2 ) , # # input )
2008-01-30 13:30:30 +01:00
/*
* use this macro ( s ) if you need more than one output parameter
* in alternative_io
*/
2009-12-18 16:12:56 +00:00
# define ASM_OUTPUT2(a...) a
2008-01-30 13:30:30 +01:00
2012-01-20 16:21:41 +00:00
/*
* use this macro if you need clobbers but no inputs in
* alternative_ { input , io , call } ( )
*/
# define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
2008-01-30 13:30:30 +01:00
struct paravirt_patch_site ;
# ifdef CONFIG_PARAVIRT
void apply_paravirt ( struct paravirt_patch_site * start ,
struct paravirt_patch_site * end ) ;
2007-10-11 11:20:03 +02:00
# else
2008-03-23 01:01:37 -07:00
static inline void apply_paravirt ( struct paravirt_patch_site * start ,
struct paravirt_patch_site * end )
2008-01-30 13:30:30 +01:00
{ }
# define __parainstructions NULL
# define __parainstructions_end NULL
2007-10-11 11:20:03 +02:00
# endif
2008-01-30 13:30:30 +01:00
2010-09-17 11:08:56 -04:00
extern void * text_poke_early ( void * addr , const void * opcode , size_t len ) ;
2008-03-06 08:48:49 -05:00
/*
* Clear and restore the kernel write - protection flag on the local CPU .
* Allows the kernel to edit read - only pages .
* Side - effect : any interrupt handler running between save and restore will have
* the ability to write to read - only pages .
*
* Warning :
* Code patching in the UP case is safe if NMIs and MCE handlers are stopped and
* no thread can be preempted in the instructions being modified ( no iret to an
* invalid instruction possible ) or if the instructions are changed from a
* consistent state to another consistent state atomically .
* More care must be taken when modifying code in the SMP case because of
2010-02-25 08:34:38 -05:00
* Intel ' s errata . text_poke_smp ( ) takes care that errata , but still
* doesn ' t support NMI / MCE handler code modifying .
2008-03-06 08:48:49 -05:00
* On the local CPU you need to be protected again NMI or MCE handlers seeing an
* inconsistent instruction while you patch .
*/
2010-12-03 18:54:22 +09:00
struct text_poke_param {
void * addr ;
const void * opcode ;
size_t len ;
} ;
2008-03-06 08:48:49 -05:00
extern void * text_poke ( void * addr , const void * opcode , size_t len ) ;
2010-02-25 08:34:38 -05:00
extern void * text_poke_smp ( void * addr , const void * opcode , size_t len ) ;
2010-12-03 18:54:22 +09:00
extern void text_poke_smp_batch ( struct text_poke_param * params , int n ) ;
2008-01-30 13:30:30 +01:00
2008-10-22 22:26:29 -07:00
# endif /* _ASM_X86_ALTERNATIVE_H */