Home | History | Annotate | Download | only in asm-x86
      1 #ifndef _I386_ALTERNATIVE_H
      2 #define _I386_ALTERNATIVE_H
      3 
      4 #include <asm/types.h>
      5 #include <linux/stddef.h>
      6 #include <linux/types.h>
      7 
      8 struct alt_instr {
      9 	u8 *instr; 		/* original instruction */
     10 	u8 *replacement;
     11 	u8  cpuid;		/* cpuid bit set for replacement */
     12 	u8  instrlen;		/* length of original instruction */
     13 	u8  replacementlen; 	/* length of new instruction, <= instrlen */
     14 	u8  pad;
     15 };
     16 
     17 extern void alternative_instructions(void);
     18 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
     19 
     20 struct module;
     21 #ifdef CONFIG_SMP
     22 extern void alternatives_smp_module_add(struct module *mod, char *name,
     23 					void *locks, void *locks_end,
     24 					void *text, void *text_end);
     25 extern void alternatives_smp_module_del(struct module *mod);
     26 extern void alternatives_smp_switch(int smp);
     27 #else
     28 static inline void alternatives_smp_module_add(struct module *mod, char *name,
     29 					void *locks, void *locks_end,
     30 					void *text, void *text_end) {}
     31 static inline void alternatives_smp_module_del(struct module *mod) {}
     32 static inline void alternatives_smp_switch(int smp) {}
     33 #endif	/* CONFIG_SMP */
     34 
     35 /*
     36  * Alternative instructions for different CPU types or capabilities.
     37  *
     38  * This allows to use optimized instructions even on generic binary
     39  * kernels.
     40  *
     41  * length of oldinstr must be longer or equal the length of newinstr
     42  * It can be padded with nops as needed.
     43  *
     44  * For non barrier like inlines please define new variants
     45  * without volatile and memory clobber.
     46  */
     47 #define alternative(oldinstr, newinstr, feature)			\
     48 	asm volatile ("661:\n\t" oldinstr "\n662:\n" 			\
     49 		      ".section .altinstructions,\"a\"\n"		\
     50 		      "  .align 4\n"					\
     51 		      "  .long 661b\n"            /* label */		\
     52 		      "  .long 663f\n"		  /* new instruction */	\
     53 		      "  .byte %c0\n"             /* feature bit */	\
     54 		      "  .byte 662b-661b\n"       /* sourcelen */	\
     55 		      "  .byte 664f-663f\n"       /* replacementlen */	\
     56 		      ".previous\n"					\
     57 		      ".section .altinstr_replacement,\"ax\"\n"		\
     58 		      "663:\n\t" newinstr "\n664:\n"   /* replacement */\
     59 		      ".previous" :: "i" (feature) : "memory")
     60 
     61 /*
     62  * Alternative inline assembly with input.
     63  *
     64  * Pecularities:
     65  * No memory clobber here.
     66  * Argument numbers start with 1.
     67  * Best is to use constraints that are fixed size (like (%1) ... "r")
     68  * If you use variable sized constraints like "m" or "g" in the
     69  * replacement maake sure to pad to the worst case length.
     70  */
     71 #define alternative_input(oldinstr, newinstr, feature, input...)	\
     72 	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
     73 		      ".section .altinstructions,\"a\"\n"		\
     74 		      "  .align 4\n"					\
     75 		      "  .long 661b\n"            /* label */		\
     76 		      "  .long 663f\n"		  /* new instruction */ \
     77 		      "  .byte %c0\n"             /* feature bit */	\
     78 		      "  .byte 662b-661b\n"       /* sourcelen */	\
     79 		      "  .byte 664f-663f\n"       /* replacementlen */ 	\
     80 		      ".previous\n"					\
     81 		      ".section .altinstr_replacement,\"ax\"\n"		\
     82 		      "663:\n\t" newinstr "\n664:\n"   /* replacement */\
     83 		      ".previous" :: "i" (feature), ##input)
     84 
     85 /* Like alternative_input, but with a single output argument */
     86 #define alternative_io(oldinstr, newinstr, feature, output, input...) \
     87 	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
     88 		      ".section .altinstructions,\"a\"\n"		\
     89 		      "  .align 4\n"					\
     90 		      "  .long 661b\n"            /* label */		\
     91 		      "  .long 663f\n"		  /* new instruction */	\
     92 		      "  .byte %c[feat]\n"        /* feature bit */	\
     93 		      "  .byte 662b-661b\n"       /* sourcelen */	\
     94 		      "  .byte 664f-663f\n"       /* replacementlen */	\
     95 		      ".previous\n"					\
     96 		      ".section .altinstr_replacement,\"ax\"\n"		\
     97 		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
     98 		      ".previous" : output : [feat] "i" (feature), ##input)
     99 
    100 /*
    101  * use this macro(s) if you need more than one output parameter
    102  * in alternative_io
    103  */
    104 #define ASM_OUTPUT2(a, b) a, b
    105 
    106 /*
    107  * Alternative inline assembly for SMP.
    108  *
    109  * The LOCK_PREFIX macro defined here replaces the LOCK and
    110  * LOCK_PREFIX macros used everywhere in the source tree.
    111  *
    112  * SMP alternatives use the same data structures as the other
    113  * alternatives and the X86_FEATURE_UP flag to indicate the case of a
    114  * UP system running a SMP kernel.  The existing apply_alternatives()
    115  * works fine for patching a SMP kernel for UP.
    116  *
    117  * The SMP alternative tables can be kept after boot and contain both
    118  * UP and SMP versions of the instructions to allow switching back to
    119  * SMP at runtime, when hotplugging in a new CPU, which is especially
    120  * useful in virtualized environments.
    121  *
    122  * The very common lock prefix is handled as special case in a
    123  * separate table which is a pure address list without replacement ptr
    124  * and size information.  That keeps the table sizes small.
    125  */
    126 
    127 #ifdef CONFIG_SMP
    128 #define LOCK_PREFIX \
    129 		".section .smp_locks,\"a\"\n"	\
    130 		"  .align 4\n"			\
    131 		"  .long 661f\n" /* address */	\
    132 		".previous\n"			\
    133 	       	"661:\n\tlock; "
    134 
    135 #else /* ! CONFIG_SMP */
    136 #define LOCK_PREFIX ""
    137 #endif
    138 
    139 struct paravirt_patch_site;
    140 #ifdef CONFIG_PARAVIRT
    141 void apply_paravirt(struct paravirt_patch_site *start,
    142 		    struct paravirt_patch_site *end);
    143 #else
    144 static inline void
    145 apply_paravirt(struct paravirt_patch_site *start,
    146 	       struct paravirt_patch_site *end)
    147 {}
    148 #define __parainstructions	NULL
    149 #define __parainstructions_end	NULL
    150 #endif
    151 
    152 extern void text_poke(void *addr, unsigned char *opcode, int len);
    153 
    154 #endif /* _I386_ALTERNATIVE_H */
    155