Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. #ifndef _ASM_X86_ALTERNATIVE_H
  2. #define _ASM_X86_ALTERNATIVE_H
  3.  
  4. #include <linux/types.h>
  5. #include <linux/stddef.h>
  6. #include <linux/stringify.h>
  7. #include <asm/asm.h>
  8.  
  9. /*
  10.  * Alternative inline assembly for SMP.
  11.  *
  12.  * The LOCK_PREFIX macro defined here replaces the LOCK and
  13.  * LOCK_PREFIX macros used everywhere in the source tree.
  14.  *
  15.  * SMP alternatives use the same data structures as the other
  16.  * alternatives and the X86_FEATURE_UP flag to indicate the case of a
  17.  * UP system running a SMP kernel.  The existing apply_alternatives()
  18.  * works fine for patching a SMP kernel for UP.
  19.  *
  20.  * The SMP alternative tables can be kept after boot and contain both
  21.  * UP and SMP versions of the instructions to allow switching back to
  22.  * SMP at runtime, when hotplugging in a new CPU, which is especially
  23.  * useful in virtualized environments.
  24.  *
  25.  * The very common lock prefix is handled as special case in a
  26.  * separate table which is a pure address list without replacement ptr
  27.  * and size information.  That keeps the table sizes small.
  28.  */
  29.  
  30. #ifdef CONFIG_SMP
  31. #define LOCK_PREFIX \
  32.                 ".section .smp_locks,\"a\"\n"   \
  33.                 _ASM_ALIGN "\n"                 \
  34.                 _ASM_PTR "661f\n" /* address */ \
  35.                 ".previous\n"                   \
  36.                 "661:\n\tlock; "
  37.  
  38. #else /* ! CONFIG_SMP */
  39. #define LOCK_PREFIX ""
  40. #endif
  41.  
  42. /* This must be included *after* the definition of LOCK_PREFIX */
  43. #include <asm/cpufeature.h>
  44.  
  45. struct alt_instr {
  46.         u8 *instr;              /* original instruction */
  47.         u8 *replacement;
  48.         u8  cpuid;              /* cpuid bit set for replacement */
  49.         u8  instrlen;           /* length of original instruction */
  50.         u8  replacementlen;     /* length of new instruction, <= instrlen */
  51.         u8  pad1;
  52. #ifdef CONFIG_X86_64
  53.         u32 pad2;
  54. #endif
  55. };
  56.  
  57. extern void alternative_instructions(void);
  58. extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
  59.  
  60. struct module;
  61.  
  62. #ifdef CONFIG_SMP
  63. extern void alternatives_smp_module_add(struct module *mod, char *name,
  64.                                         void *locks, void *locks_end,
  65.                                         void *text, void *text_end);
  66. extern void alternatives_smp_module_del(struct module *mod);
  67. extern void alternatives_smp_switch(int smp);
  68. #else
  69. static inline void alternatives_smp_module_add(struct module *mod, char *name,
  70.                                                void *locks, void *locks_end,
  71.                                                void *text, void *text_end) {}
  72. static inline void alternatives_smp_module_del(struct module *mod) {}
  73. static inline void alternatives_smp_switch(int smp) {}
  74. #endif  /* CONFIG_SMP */
  75.  
  76. /* alternative assembly primitive: */
  77. #define ALTERNATIVE(oldinstr, newinstr, feature)                        \
  78.                                                                         \
  79.       "661:\n\t" oldinstr "\n662:\n"                                    \
  80.       ".section .altinstructions,\"a\"\n"                               \
  81.       _ASM_ALIGN "\n"                                                   \
  82.       _ASM_PTR "661b\n"                         /* label           */   \
  83.       _ASM_PTR "663f\n"                         /* new instruction */   \
  84.       "  .byte " __stringify(feature) "\n"      /* feature bit     */   \
  85.       "  .byte 662b-661b\n"                     /* sourcelen       */   \
  86.       "  .byte 664f-663f\n"                     /* replacementlen  */   \
  87.       "  .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */   \
  88.       ".previous\n"                                                     \
  89.       ".section .altinstr_replacement, \"ax\"\n"                        \
  90.       "663:\n\t" newinstr "\n664:\n"            /* replacement     */   \
  91.       ".previous"
  92.  
  93. /*
  94.  * Alternative instructions for different CPU types or capabilities.
  95.  *
  96.  * This allows to use optimized instructions even on generic binary
  97.  * kernels.
  98.  *
  99.  * length of oldinstr must be longer or equal the length of newinstr
  100.  * It can be padded with nops as needed.
  101.  *
  102.  * For non barrier like inlines please define new variants
  103.  * without volatile and memory clobber.
  104.  */
  105. #define alternative(oldinstr, newinstr, feature)                        \
  106.         asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
  107.  
  108. /*
  109.  * Alternative inline assembly with input.
  110.  *
  111.  * Pecularities:
  112.  * No memory clobber here.
  113.  * Argument numbers start with 1.
  114.  * Best is to use constraints that are fixed size (like (%1) ... "r")
  115.  * If you use variable sized constraints like "m" or "g" in the
  116.  * replacement make sure to pad to the worst case length.
  117.  * Leaving an unused argument 0 to keep API compatibility.
  118.  */
  119. #define alternative_input(oldinstr, newinstr, feature, input...)        \
  120.         asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)          \
  121.                 : : "i" (0), ## input)
  122.  
  123. /* Like alternative_input, but with a single output argument */
  124. #define alternative_io(oldinstr, newinstr, feature, output, input...)   \
  125.         asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)          \
  126.                 : output : "i" (0), ## input)
  127.  
  128. /*
  129.  * use this macro(s) if you need more than one output parameter
  130.  * in alternative_io
  131.  */
  132. #define ASM_OUTPUT2(a, b) a, b
  133.  
  134. struct paravirt_patch_site;
  135. #ifdef CONFIG_PARAVIRT
  136. void apply_paravirt(struct paravirt_patch_site *start,
  137.                     struct paravirt_patch_site *end);
  138. #else
  139. static inline void apply_paravirt(struct paravirt_patch_site *start,
  140.                                   struct paravirt_patch_site *end)
  141. {}
  142. #define __parainstructions      NULL
  143. #define __parainstructions_end  NULL
  144. #endif
  145.  
  146. /*
  147.  * Clear and restore the kernel write-protection flag on the local CPU.
  148.  * Allows the kernel to edit read-only pages.
  149.  * Side-effect: any interrupt handler running between save and restore will have
  150.  * the ability to write to read-only pages.
  151.  *
  152.  * Warning:
  153.  * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and
  154.  * no thread can be preempted in the instructions being modified (no iret to an
  155.  * invalid instruction possible) or if the instructions are changed from a
  156.  * consistent state to another consistent state atomically.
  157.  * More care must be taken when modifying code in the SMP case because of
  158.  * Intel's errata.
  159.  * On the local CPU you need to be protected again NMI or MCE handlers seeing an
  160.  * inconsistent instruction while you patch.
  161.  */
  162. extern void *text_poke(void *addr, const void *opcode, size_t len);
  163.  
  164. #endif /* _ASM_X86_ALTERNATIVE_H */
  165.