diff options
| -rw-r--r-- | arch/x86/include/asm/alternative.h | 74 | ||||
| -rw-r--r-- | arch/x86/include/asm/uaccess_64.h | 11 | ||||
| -rw-r--r-- | arch/x86/kernel/alternative.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/cleanup.c | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/generic.c | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/x8664_ksyms_64.c | 1 |
6 files changed, 75 insertions, 25 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 | */ |
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 8e796fbbf9c6..d8def8b3dba0 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | /* Handles exceptions in both to and from, but doesn't do access_ok */ | 18 | /* Handles exceptions in both to and from, but doesn't do access_ok */ |
| 19 | __must_check unsigned long | 19 | __must_check unsigned long |
| 20 | copy_user_enhanced_fast_string(void *to, const void *from, unsigned len); | ||
| 21 | __must_check unsigned long | ||
| 20 | copy_user_generic_string(void *to, const void *from, unsigned len); | 22 | copy_user_generic_string(void *to, const void *from, unsigned len); |
| 21 | __must_check unsigned long | 23 | __must_check unsigned long |
| 22 | copy_user_generic_unrolled(void *to, const void *from, unsigned len); | 24 | copy_user_generic_unrolled(void *to, const void *from, unsigned len); |
| @@ -26,9 +28,16 @@ copy_user_generic(void *to, const void *from, unsigned len) | |||
| 26 | { | 28 | { |
| 27 | unsigned ret; | 29 | unsigned ret; |
| 28 | 30 | ||
| 29 | alternative_call(copy_user_generic_unrolled, | 31 | /* |
| 32 | * If CPU has ERMS feature, use copy_user_enhanced_fast_string. | ||
| 33 | * Otherwise, if CPU has rep_good feature, use copy_user_generic_string. | ||
| 34 | * Otherwise, use copy_user_generic_unrolled. | ||
| 35 | */ | ||
| 36 | alternative_call_2(copy_user_generic_unrolled, | ||
| 30 | copy_user_generic_string, | 37 | copy_user_generic_string, |
| 31 | X86_FEATURE_REP_GOOD, | 38 | X86_FEATURE_REP_GOOD, |
| 39 | copy_user_enhanced_fast_string, | ||
| 40 | X86_FEATURE_ERMS, | ||
| 32 | ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), | 41 | ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), |
| 33 | "=d" (len)), | 42 | "=d" (len)), |
| 34 | "1" (to), "2" (from), "3" (len) | 43 | "1" (to), "2" (from), "3" (len) |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 1f84794f0759..53231a045d3d 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
| @@ -664,7 +664,7 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
| 664 | struct text_poke_param *p; | 664 | struct text_poke_param *p; |
| 665 | int i; | 665 | int i; |
| 666 | 666 | ||
| 667 | if (atomic_dec_and_test(&stop_machine_first)) { | 667 | if (atomic_xchg(&stop_machine_first, 0)) { |
| 668 | for (i = 0; i < tpp->nparams; i++) { | 668 | for (i = 0; i < tpp->nparams; i++) { |
| 669 | p = &tpp->params[i]; | 669 | p = &tpp->params[i]; |
| 670 | text_poke(p->addr, p->opcode, p->len); | 670 | text_poke(p->addr, p->opcode, p->len); |
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index bdda2e6c673b..35ffda5d0727 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c | |||
| @@ -258,11 +258,11 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk, | |||
| 258 | 258 | ||
| 259 | /* Compute the maximum size with which we can make a range: */ | 259 | /* Compute the maximum size with which we can make a range: */ |
| 260 | if (range_startk) | 260 | if (range_startk) |
| 261 | max_align = ffs(range_startk) - 1; | 261 | max_align = __ffs(range_startk); |
| 262 | else | 262 | else |
| 263 | max_align = 32; | 263 | max_align = BITS_PER_LONG - 1; |
| 264 | 264 | ||
| 265 | align = fls(range_sizek) - 1; | 265 | align = __fls(range_sizek); |
| 266 | if (align > max_align) | 266 | if (align > max_align) |
| 267 | align = max_align; | 267 | align = max_align; |
| 268 | 268 | ||
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 75772ae6c65f..e9fe907cd249 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c | |||
| @@ -361,11 +361,7 @@ static void __init print_mtrr_state(void) | |||
| 361 | } | 361 | } |
| 362 | pr_debug("MTRR variable ranges %sabled:\n", | 362 | pr_debug("MTRR variable ranges %sabled:\n", |
| 363 | mtrr_state.enabled & 2 ? "en" : "dis"); | 363 | mtrr_state.enabled & 2 ? "en" : "dis"); |
| 364 | if (size_or_mask & 0xffffffffUL) | 364 | high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4; |
| 365 | high_width = ffs(size_or_mask & 0xffffffffUL) - 1; | ||
| 366 | else | ||
| 367 | high_width = ffs(size_or_mask>>32) + 32 - 1; | ||
| 368 | high_width = (high_width - (32 - PAGE_SHIFT) + 3) / 4; | ||
| 369 | 365 | ||
| 370 | for (i = 0; i < num_var_ranges; ++i) { | 366 | for (i = 0; i < num_var_ranges; ++i) { |
| 371 | if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) | 367 | if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) |
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index 9796c2f3d074..6020f6f5927c 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c | |||
| @@ -28,6 +28,7 @@ EXPORT_SYMBOL(__put_user_8); | |||
| 28 | 28 | ||
| 29 | EXPORT_SYMBOL(copy_user_generic_string); | 29 | EXPORT_SYMBOL(copy_user_generic_string); |
| 30 | EXPORT_SYMBOL(copy_user_generic_unrolled); | 30 | EXPORT_SYMBOL(copy_user_generic_unrolled); |
| 31 | EXPORT_SYMBOL(copy_user_enhanced_fast_string); | ||
| 31 | EXPORT_SYMBOL(__copy_user_nocache); | 32 | EXPORT_SYMBOL(__copy_user_nocache); |
| 32 | EXPORT_SYMBOL(_copy_from_user); | 33 | EXPORT_SYMBOL(_copy_from_user); |
| 33 | EXPORT_SYMBOL(_copy_to_user); | 34 | EXPORT_SYMBOL(_copy_to_user); |
