aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 11:45:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 11:45:46 -0500
commit6ea98b4baa1c9089d7a035ebccb993e03d1ac57f (patch)
tree095d5037d8f686517646c33a48658b0ae22d1431
parent45802da05e666a81b421422d3e302930c0e24e77 (diff)
parent093ae8f9a86a974c920b613860f1f7fd5bbd70ab (diff)
Merge branch 'x86-alternatives-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 alternative instruction updates from Ingo Molnar: "Small RDTSCP opimization, enabled by the newly added ALTERNATIVE_3(), and other small improvements" * 'x86-alternatives-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/TSC: Use RDTSCP x86/alternatives: Add an ALTERNATIVE_3() macro x86/alternatives: Print containing function x86/alternatives: Add macro comments
-rw-r--r--arch/x86/include/asm/alternative.h39
-rw-r--r--arch/x86/include/asm/msr.h16
-rw-r--r--arch/x86/kernel/alternative.c4
3 files changed, 48 insertions, 11 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 0660e14690c8..4c74073a19cc 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -94,13 +94,12 @@ static inline int alternatives_text_reserved(void *start, void *end)
94#define alt_total_slen alt_end_marker"b-661b" 94#define alt_total_slen alt_end_marker"b-661b"
95#define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f" 95#define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f"
96 96
97#define __OLDINSTR(oldinstr, num) \ 97#define OLDINSTR(oldinstr, num) \
98 "# ALT: oldnstr\n" \
98 "661:\n\t" oldinstr "\n662:\n" \ 99 "661:\n\t" oldinstr "\n662:\n" \
100 "# ALT: padding\n" \
99 ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \ 101 ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \
100 "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n" 102 "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n" \
101
102#define OLDINSTR(oldinstr, num) \
103 __OLDINSTR(oldinstr, num) \
104 alt_end_marker ":\n" 103 alt_end_marker ":\n"
105 104
106/* 105/*
@@ -116,11 +115,23 @@ static inline int alternatives_text_reserved(void *start, void *end)
116 * additionally longer than the first replacement alternative. 115 * additionally longer than the first replacement alternative.
117 */ 116 */
118#define OLDINSTR_2(oldinstr, num1, num2) \ 117#define OLDINSTR_2(oldinstr, num1, num2) \
118 "# ALT: oldinstr2\n" \
119 "661:\n\t" oldinstr "\n662:\n" \ 119 "661:\n\t" oldinstr "\n662:\n" \
120 "# ALT: padding2\n" \
120 ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \ 121 ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \
121 "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \ 122 "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \
122 alt_end_marker ":\n" 123 alt_end_marker ":\n"
123 124
125#define OLDINSTR_3(oldinsn, n1, n2, n3) \
126 "# ALT: oldinstr3\n" \
127 "661:\n\t" oldinsn "\n662:\n" \
128 "# ALT: padding3\n" \
129 ".skip -((" alt_max_short(alt_max_short(alt_rlen(n1), alt_rlen(n2)), alt_rlen(n3)) \
130 " - (" alt_slen ")) > 0) * " \
131 "(" alt_max_short(alt_max_short(alt_rlen(n1), alt_rlen(n2)), alt_rlen(n3)) \
132 " - (" alt_slen ")), 0x90\n" \
133 alt_end_marker ":\n"
134
124#define ALTINSTR_ENTRY(feature, num) \ 135#define ALTINSTR_ENTRY(feature, num) \
125 " .long 661b - .\n" /* label */ \ 136 " .long 661b - .\n" /* label */ \
126 " .long " b_replacement(num)"f - .\n" /* new instruction */ \ 137 " .long " b_replacement(num)"f - .\n" /* new instruction */ \
@@ -129,8 +140,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
129 " .byte " alt_rlen(num) "\n" /* replacement len */ \ 140 " .byte " alt_rlen(num) "\n" /* replacement len */ \
130 " .byte " alt_pad_len "\n" /* pad len */ 141 " .byte " alt_pad_len "\n" /* pad len */
131 142
132#define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \ 143#define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \
133 b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t" 144 "# ALT: replacement " #num "\n" \
145 b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n"
134 146
135/* alternative assembly primitive: */ 147/* alternative assembly primitive: */
136#define ALTERNATIVE(oldinstr, newinstr, feature) \ 148#define ALTERNATIVE(oldinstr, newinstr, feature) \
@@ -153,6 +165,19 @@ static inline int alternatives_text_reserved(void *start, void *end)
153 ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ 165 ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \
154 ".popsection\n" 166 ".popsection\n"
155 167
168#define ALTERNATIVE_3(oldinsn, newinsn1, feat1, newinsn2, feat2, newinsn3, feat3) \
169 OLDINSTR_3(oldinsn, 1, 2, 3) \
170 ".pushsection .altinstructions,\"a\"\n" \
171 ALTINSTR_ENTRY(feat1, 1) \
172 ALTINSTR_ENTRY(feat2, 2) \
173 ALTINSTR_ENTRY(feat3, 3) \
174 ".popsection\n" \
175 ".pushsection .altinstr_replacement, \"ax\"\n" \
176 ALTINSTR_REPLACEMENT(newinsn1, feat1, 1) \
177 ALTINSTR_REPLACEMENT(newinsn2, feat2, 2) \
178 ALTINSTR_REPLACEMENT(newinsn3, feat3, 3) \
179 ".popsection\n"
180
156/* 181/*
157 * Alternative instructions for different CPU types or capabilities. 182 * Alternative instructions for different CPU types or capabilities.
158 * 183 *
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 91e4cf189914..5cc3930cb465 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -217,6 +217,8 @@ static __always_inline unsigned long long rdtsc(void)
217 */ 217 */
218static __always_inline unsigned long long rdtsc_ordered(void) 218static __always_inline unsigned long long rdtsc_ordered(void)
219{ 219{
220 DECLARE_ARGS(val, low, high);
221
220 /* 222 /*
221 * The RDTSC instruction is not ordered relative to memory 223 * The RDTSC instruction is not ordered relative to memory
222 * access. The Intel SDM and the AMD APM are both vague on this 224 * access. The Intel SDM and the AMD APM are both vague on this
@@ -227,9 +229,19 @@ static __always_inline unsigned long long rdtsc_ordered(void)
227 * ordering guarantees as reading from a global memory location 229 * ordering guarantees as reading from a global memory location
228 * that some other imaginary CPU is updating continuously with a 230 * that some other imaginary CPU is updating continuously with a
229 * time stamp. 231 * time stamp.
232 *
233 * Thus, use the preferred barrier on the respective CPU, aiming for
234 * RDTSCP as the default.
230 */ 235 */
231 barrier_nospec(); 236 asm volatile(ALTERNATIVE_3("rdtsc",
232 return rdtsc(); 237 "mfence; rdtsc", X86_FEATURE_MFENCE_RDTSC,
238 "lfence; rdtsc", X86_FEATURE_LFENCE_RDTSC,
239 "rdtscp", X86_FEATURE_RDTSCP)
240 : EAX_EDX_RET(val, low, high)
241 /* RDTSCP clobbers ECX with MSR_TSC_AUX. */
242 :: "ecx");
243
244 return EAX_EDX_VAL(val, low, high);
233} 245}
234 246
235static inline unsigned long long native_read_pmc(int counter) 247static inline unsigned long long native_read_pmc(int counter)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index e8b628b1b279..9a79c7808f9c 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -394,10 +394,10 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
394 continue; 394 continue;
395 } 395 }
396 396
397 DPRINTK("feat: %d*32+%d, old: (%px len: %d), repl: (%px, len: %d), pad: %d", 397 DPRINTK("feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d), pad: %d",
398 a->cpuid >> 5, 398 a->cpuid >> 5,
399 a->cpuid & 0x1f, 399 a->cpuid & 0x1f,
400 instr, a->instrlen, 400 instr, instr, a->instrlen,
401 replacement, a->replacementlen, a->padlen); 401 replacement, a->replacementlen, a->padlen);
402 402
403 DUMP_BYTES(instr, a->instrlen, "%px: old_insn: ", instr); 403 DUMP_BYTES(instr, a->instrlen, "%px: old_insn: ", instr);