Merge branch 'x86-smap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-3.10.git] / arch / x86 / include / asm / alternative.h
index 23fb6d7..58ed6d9 100644 (file)
 
 #ifdef CONFIG_SMP
 #define LOCK_PREFIX_HERE \
-               ".section .smp_locks,\"a\"\n"   \
-               ".balign 4\n"                   \
-               ".long 671f - .\n" /* offset */ \
-               ".previous\n"                   \
+               ".pushsection .smp_locks,\"a\"\n"       \
+               ".balign 4\n"                           \
+               ".long 671f - .\n" /* offset */         \
+               ".popsection\n"                         \
                "671:"
 
 #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
@@ -48,9 +48,6 @@ struct alt_instr {
        u16 cpuid;              /* cpuid bit set for replacement */
        u8  instrlen;           /* length of original instruction */
        u8  replacementlen;     /* length of new instruction, <= instrlen */
-#ifdef CONFIG_X86_64
-       u32 pad2;
-#endif
 };
 
 extern void alternative_instructions(void);
@@ -63,7 +60,7 @@ 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);
+extern void alternatives_enable_smp(void);
 extern int alternatives_text_reserved(void *start, void *end);
 extern bool skip_smp_alternatives;
 #else
@@ -71,31 +68,61 @@ 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) {}
+static inline void alternatives_enable_smp(void) {}
 static inline int alternatives_text_reserved(void *start, void *end)
 {
        return 0;
 }
 #endif /* CONFIG_SMP */
 
+#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"
+
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)                       \
-                                                                       \
-      "661:\n\t" oldinstr "\n662:\n"                                   \
-      ".section .altinstructions,\"a\"\n"                              \
-      _ASM_ALIGN "\n"                                                  \
-      "         .long 661b - .\n"                      /* label           */   \
-      "         .long 663f - .\n"                      /* new instruction */   \
-      "         .word " __stringify(feature) "\n"      /* feature bit     */   \
-      "         .byte 662b-661b\n"                     /* sourcelen       */   \
-      "         .byte 664f-663f\n"                     /* replacementlen  */   \
-      ".previous\n"                                                    \
-      ".section .discard,\"aw\",@progbits\n"                           \
-      "         .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */   \
-      ".previous\n"                                                    \
-      ".section .altinstr_replacement, \"ax\"\n"                       \
-      "663:\n\t" newinstr "\n664:\n"           /* replacement     */   \
-      ".previous"
+       OLDINSTR(oldinstr)                                              \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(feature, 1)                                      \
+       ".popsection\n"                                                 \
+       ".pushsection .discard,\"aw\",@progbits\n"                      \
+       DISCARD_ENTRY(1)                                                \
+       ".popsection\n"                                                 \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(newinstr, feature, 1)                      \
+       ".popsection"
+
+#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
+       OLDINSTR(oldinstr)                                              \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(feature1, 1)                                     \
+       ALTINSTR_ENTRY(feature2, 2)                                     \
+       ".popsection\n"                                                 \
+       ".pushsection .discard,\"aw\",@progbits\n"                      \
+       DISCARD_ENTRY(1)                                                \
+       DISCARD_ENTRY(2)                                                \
+       ".popsection\n"                                                 \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)                    \
+       ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)                    \
+       ".popsection"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
@@ -144,11 +171,30 @@ static inline int alternatives_text_reserved(void *start, void *end)
                : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
 
 /*
+ * 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)
+
+/*
  * use this macro(s) if you need more than one output parameter
  * in alternative_io
  */
 #define ASM_OUTPUT2(a...) a
 
+/*
+ * use this macro if you need clobbers but no inputs in
+ * alternative_{input,io,call}()
+ */
+#define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
+
 struct paravirt_patch_site;
 #ifdef CONFIG_PARAVIRT
 void apply_paravirt(struct paravirt_patch_site *start,