2006-03-23 02:59:32 -08:00
# ifndef _I386_ALTERNATIVE_H
# define _I386_ALTERNATIVE_H
2006-06-23 02:04:33 -07:00
# include <asm/types.h>
2006-12-07 02:14:08 +01:00
# include <linux/stddef.h>
2006-06-26 13:56:16 +02:00
# include <linux/types.h>
2006-03-23 02:59:32 -08:00
struct alt_instr {
u8 * instr ; /* original instruction */
u8 * replacement ;
u8 cpuid ; /* cpuid bit set for replacement */
u8 instrlen ; /* length of original instruction */
u8 replacementlen ; /* length of new instruction, <= instrlen */
u8 pad ;
} ;
2007-05-02 19:27:12 +02:00
extern void alternative_instructions ( void ) ;
2006-03-23 02:59:32 -08:00
extern void apply_alternatives ( struct alt_instr * start , struct alt_instr * end ) ;
struct module ;
2006-07-01 04:36:18 -07:00
# ifdef CONFIG_SMP
2006-03-23 02:59:32 -08:00
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 ) ;
extern void alternatives_smp_switch ( int smp ) ;
2006-07-01 04:36:18 -07:00
# else
static inline void alternatives_smp_module_add ( struct module * mod , char * name ,
void * locks , void * locks_end ,
void * text , void * text_end ) { }
static inline void alternatives_smp_module_del ( struct module * mod ) { }
static inline void alternatives_smp_switch ( int smp ) { }
2007-05-02 19:27:13 +02:00
# endif /* CONFIG_SMP */
2006-03-23 02:59:32 -08: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) \
asm volatile ( " 661: \n \t " oldinstr " \n 662: \n " \
" .section .altinstructions, \" a \" \n " \
" .align 4 \n " \
" .long 661b \n " /* label */ \
" .long 663f \n " /* new instruction */ \
" .byte %c0 \n " /* feature bit */ \
" .byte 662b-661b \n " /* sourcelen */ \
" .byte 664f-663f \n " /* replacementlen */ \
" .previous \n " \
" .section .altinstr_replacement, \" ax \" \n " \
" 663: \n \t " newinstr " \n 664: \n " /* replacement */ \
" .previous " : : " i " ( feature ) : " memory " )
/*
* 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 maake sure to pad to the worst case length .
*/
# define alternative_input(oldinstr, newinstr, feature, input...) \
asm volatile ( " 661: \n \t " oldinstr " \n 662: \n " \
" .section .altinstructions, \" a \" \n " \
" .align 4 \n " \
" .long 661b \n " /* label */ \
" .long 663f \n " /* new instruction */ \
" .byte %c0 \n " /* feature bit */ \
" .byte 662b-661b \n " /* sourcelen */ \
" .byte 664f-663f \n " /* replacementlen */ \
" .previous \n " \
" .section .altinstr_replacement, \" ax \" \n " \
" 663: \n \t " newinstr " \n 664: \n " /* replacement */ \
" .previous " : : " i " ( feature ) , # # input )
2007-05-02 19:27:20 +02:00
/* Like alternative_input, but with a single output argument */
# define alternative_io(oldinstr, newinstr, feature, output, input...) \
asm volatile ( " 661: \n \t " oldinstr " \n 662: \n " \
" .section .altinstructions, \" a \" \n " \
" .align 4 \n " \
" .long 661b \n " /* label */ \
" .long 663f \n " /* new instruction */ \
" .byte %c[feat] \n " /* feature bit */ \
" .byte 662b-661b \n " /* sourcelen */ \
" .byte 664f-663f \n " /* replacementlen */ \
" .previous \n " \
" .section .altinstr_replacement, \" ax \" \n " \
" 663: \n \t " newinstr " \n 664: \n " /* replacement */ \
" .previous " : output : [ feat ] " i " ( feature ) , # # input )
2007-05-10 22:22:14 -07:00
/*
* use this macro ( s ) if you need more than one output parameter
* in alternative_io
*/
# define ASM_OUTPUT2(a, b) a, b
2006-03-23 02:59:32 -08:00
/*
* 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
# define LOCK_PREFIX \
" .section .smp_locks, \" a \" \n " \
" .align 4 \n " \
" .long 661f \n " /* address */ \
" .previous \n " \
" 661: \n \t lock; "
# else /* ! CONFIG_SMP */
# define LOCK_PREFIX ""
# endif
2007-05-02 19:27:14 +02:00
struct paravirt_patch_site ;
2006-12-07 02:14:08 +01:00
# ifdef CONFIG_PARAVIRT
2007-05-02 19:27:14 +02:00
void apply_paravirt ( struct paravirt_patch_site * start ,
struct paravirt_patch_site * end ) ;
2006-12-07 02:14:08 +01:00
# else
static inline void
2007-05-02 19:27:14 +02:00
apply_paravirt ( struct paravirt_patch_site * start ,
struct paravirt_patch_site * end )
2006-12-07 02:14:08 +01:00
{ }
2007-05-02 19:27:16 +02:00
# define __parainstructions NULL
# define __parainstructions_end NULL
2006-12-07 02:14:08 +01:00
# endif
2007-07-22 11:12:31 +02:00
extern void text_poke ( void * addr , unsigned char * opcode , int len ) ;
2006-03-23 02:59:32 -08:00
# endif /* _I386_ALTERNATIVE_H */