2006-03-23 02:59:32 -08:00
# ifndef _I386_ALTERNATIVE_H
# define _I386_ALTERNATIVE_H
# ifdef __KERNEL__
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 ;
} ;
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 ) { }
# endif
2006-03-23 02:59:32 -08:00
# endif
/*
* 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 )
/*
* 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
2006-12-07 02:14:08 +01:00
struct paravirt_patch ;
# ifdef CONFIG_PARAVIRT
void apply_paravirt ( struct paravirt_patch * start , struct paravirt_patch * end ) ;
# else
static inline void
apply_paravirt ( struct paravirt_patch * start , struct paravirt_patch * end )
{ }
# define __start_parainstructions NULL
# define __stop_parainstructions NULL
# endif
2006-03-23 02:59:32 -08:00
# endif /* _I386_ALTERNATIVE_H */