diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-06 11:45:46 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-06 11:45:46 -0500 |
| commit | 6ea98b4baa1c9089d7a035ebccb993e03d1ac57f (patch) | |
| tree | 095d5037d8f686517646c33a48658b0ae22d1431 | |
| parent | 45802da05e666a81b421422d3e302930c0e24e77 (diff) | |
| parent | 093ae8f9a86a974c920b613860f1f7fd5bbd70ab (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.h | 39 | ||||
| -rw-r--r-- | arch/x86/include/asm/msr.h | 16 | ||||
| -rw-r--r-- | arch/x86/kernel/alternative.c | 4 |
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 | */ |
| 218 | static __always_inline unsigned long long rdtsc_ordered(void) | 218 | static __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 | ||
| 235 | static inline unsigned long long native_read_pmc(int counter) | 247 | static 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); |
