diff options
Diffstat (limited to 'arch/x86/include/asm/alternative.h')
-rw-r--r-- | arch/x86/include/asm/alternative.h | 74 |
1 files changed, 59 insertions, 15 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 49331bedc158..70780689599a 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h | |||
@@ -75,23 +75,54 @@ static inline int alternatives_text_reserved(void *start, void *end) | |||
75 | } | 75 | } |
76 | #endif /* CONFIG_SMP */ | 76 | #endif /* CONFIG_SMP */ |
77 | 77 | ||
78 | #define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n" | ||
79 | |||
80 | #define b_replacement(number) "663"#number | ||
81 | #define e_replacement(number) "664"#number | ||
82 | |||
83 | #define alt_slen "662b-661b" | ||
84 | #define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f" | ||
85 | |||
86 | #define ALTINSTR_ENTRY(feature, number) \ | ||
87 | " .long 661b - .\n" /* label */ \ | ||
88 | " .long " b_replacement(number)"f - .\n" /* new instruction */ \ | ||
89 | " .word " __stringify(feature) "\n" /* feature bit */ \ | ||
90 | " .byte " alt_slen "\n" /* source len */ \ | ||
91 | " .byte " alt_rlen(number) "\n" /* replacement len */ | ||
92 | |||
93 | #define DISCARD_ENTRY(number) /* rlen <= slen */ \ | ||
94 | " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n" | ||
95 | |||
96 | #define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \ | ||
97 | b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t" | ||
98 | |||
78 | /* alternative assembly primitive: */ | 99 | /* alternative assembly primitive: */ |
79 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ | 100 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
80 | \ | 101 | OLDINSTR(oldinstr) \ |
81 | "661:\n\t" oldinstr "\n662:\n" \ | 102 | ".section .altinstructions,\"a\"\n" \ |
82 | ".section .altinstructions,\"a\"\n" \ | 103 | ALTINSTR_ENTRY(feature, 1) \ |
83 | " .long 661b - .\n" /* label */ \ | 104 | ".previous\n" \ |
84 | " .long 663f - .\n" /* new instruction */ \ | 105 | ".section .discard,\"aw\",@progbits\n" \ |
85 | " .word " __stringify(feature) "\n" /* feature bit */ \ | 106 | DISCARD_ENTRY(1) \ |
86 | " .byte 662b-661b\n" /* sourcelen */ \ | 107 | ".previous\n" \ |
87 | " .byte 664f-663f\n" /* replacementlen */ \ | 108 | ".section .altinstr_replacement, \"ax\"\n" \ |
88 | ".previous\n" \ | 109 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
89 | ".section .discard,\"aw\",@progbits\n" \ | 110 | ".previous" |
90 | " .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \ | 111 | |
91 | ".previous\n" \ | 112 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
92 | ".section .altinstr_replacement, \"ax\"\n" \ | 113 | OLDINSTR(oldinstr) \ |
93 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | 114 | ".section .altinstructions,\"a\"\n" \ |
94 | ".previous" | 115 | ALTINSTR_ENTRY(feature1, 1) \ |
116 | ALTINSTR_ENTRY(feature2, 2) \ | ||
117 | ".previous\n" \ | ||
118 | ".section .discard,\"aw\",@progbits\n" \ | ||
119 | DISCARD_ENTRY(1) \ | ||
120 | DISCARD_ENTRY(2) \ | ||
121 | ".previous\n" \ | ||
122 | ".section .altinstr_replacement, \"ax\"\n" \ | ||
123 | ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ | ||
124 | ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ | ||
125 | ".previous" | ||
95 | 126 | ||
96 | /* | 127 | /* |
97 | * This must be included *after* the definition of ALTERNATIVE due to | 128 | * This must be included *after* the definition of ALTERNATIVE due to |
@@ -140,6 +171,19 @@ static inline int alternatives_text_reserved(void *start, void *end) | |||
140 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) | 171 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) |
141 | 172 | ||
142 | /* | 173 | /* |
174 | * Like alternative_call, but there are two features and respective functions. | ||
175 | * If CPU has feature2, function2 is used. | ||
176 | * Otherwise, if CPU has feature1, function1 is used. | ||
177 | * Otherwise, old function is used. | ||
178 | */ | ||
179 | #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \ | ||
180 | output, input...) \ | ||
181 | asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\ | ||
182 | "call %P[new2]", feature2) \ | ||
183 | : output : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ | ||
184 | [new2] "i" (newfunc2), ## input) | ||
185 | |||
186 | /* | ||
143 | * use this macro(s) if you need more than one output parameter | 187 | * use this macro(s) if you need more than one output parameter |
144 | * in alternative_io | 188 | * in alternative_io |
145 | */ | 189 | */ |