diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/alternative.h | 7 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_64.h | 21 | ||||
-rw-r--r-- | arch/x86/kernel/alternative.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/x8664_ksyms_64.c | 3 | ||||
-rw-r--r-- | arch/x86/lib/copy_user_64.S | 6 |
5 files changed, 31 insertions, 10 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 69b74a7b877f..3b5b828767b6 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h | |||
@@ -125,11 +125,16 @@ static inline void alternatives_smp_switch(int smp) {} | |||
125 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ | 125 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
126 | : output : "i" (0), ## input) | 126 | : output : "i" (0), ## input) |
127 | 127 | ||
128 | /* Like alternative_io, but for replacing a direct call with another one. */ | ||
129 | #define alternative_call(oldfunc, newfunc, feature, output, input...) \ | ||
130 | asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \ | ||
131 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) | ||
132 | |||
128 | /* | 133 | /* |
129 | * use this macro(s) if you need more than one output parameter | 134 | * use this macro(s) if you need more than one output parameter |
130 | * in alternative_io | 135 | * in alternative_io |
131 | */ | 136 | */ |
132 | #define ASM_OUTPUT2(a, b) a, b | 137 | #define ASM_OUTPUT2(a...) a |
133 | 138 | ||
134 | struct paravirt_patch_site; | 139 | struct paravirt_patch_site; |
135 | #ifdef CONFIG_PARAVIRT | 140 | #ifdef CONFIG_PARAVIRT |
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 46324c6a4f6e..a78c40305447 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/prefetch.h> | 9 | #include <linux/prefetch.h> |
10 | #include <linux/lockdep.h> | 10 | #include <linux/lockdep.h> |
11 | #include <asm/alternative.h> | ||
12 | #include <asm/cpufeature.h> | ||
11 | #include <asm/page.h> | 13 | #include <asm/page.h> |
12 | 14 | ||
13 | /* | 15 | /* |
@@ -16,7 +18,24 @@ | |||
16 | 18 | ||
17 | /* Handles exceptions in both to and from, but doesn't do access_ok */ | 19 | /* Handles exceptions in both to and from, but doesn't do access_ok */ |
18 | __must_check unsigned long | 20 | __must_check unsigned long |
19 | copy_user_generic(void *to, const void *from, unsigned len); | 21 | copy_user_generic_string(void *to, const void *from, unsigned len); |
22 | __must_check unsigned long | ||
23 | copy_user_generic_unrolled(void *to, const void *from, unsigned len); | ||
24 | |||
25 | static __always_inline __must_check unsigned long | ||
26 | copy_user_generic(void *to, const void *from, unsigned len) | ||
27 | { | ||
28 | unsigned ret; | ||
29 | |||
30 | alternative_call(copy_user_generic_unrolled, | ||
31 | copy_user_generic_string, | ||
32 | X86_FEATURE_REP_GOOD, | ||
33 | ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), | ||
34 | "=d" (len)), | ||
35 | "1" (to), "2" (from), "3" (len) | ||
36 | : "memory", "rcx", "r8", "r9", "r10", "r11"); | ||
37 | return ret; | ||
38 | } | ||
20 | 39 | ||
21 | __must_check unsigned long | 40 | __must_check unsigned long |
22 | _copy_to_user(void __user *to, const void *from, unsigned len); | 41 | _copy_to_user(void __user *to, const void *from, unsigned len); |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index de7353c0ce9c..2589ea4c60ce 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -205,7 +205,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start, | |||
205 | struct alt_instr *end) | 205 | struct alt_instr *end) |
206 | { | 206 | { |
207 | struct alt_instr *a; | 207 | struct alt_instr *a; |
208 | char insnbuf[MAX_PATCH_LEN]; | 208 | u8 insnbuf[MAX_PATCH_LEN]; |
209 | 209 | ||
210 | DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); | 210 | DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); |
211 | for (a = start; a < end; a++) { | 211 | for (a = start; a < end; a++) { |
@@ -223,6 +223,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start, | |||
223 | } | 223 | } |
224 | #endif | 224 | #endif |
225 | memcpy(insnbuf, a->replacement, a->replacementlen); | 225 | memcpy(insnbuf, a->replacement, a->replacementlen); |
226 | if (*insnbuf == 0xe8 && a->replacementlen == 5) | ||
227 | *(s32 *)(insnbuf + 1) += a->replacement - a->instr; | ||
226 | add_nops(insnbuf + a->replacementlen, | 228 | add_nops(insnbuf + a->replacementlen, |
227 | a->instrlen - a->replacementlen); | 229 | a->instrlen - a->replacementlen); |
228 | text_poke_early(instr, insnbuf, a->instrlen); | 230 | text_poke_early(instr, insnbuf, a->instrlen); |
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index 619f7f88b8cc..693920b22496 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c | |||
@@ -26,7 +26,8 @@ EXPORT_SYMBOL(__put_user_2); | |||
26 | EXPORT_SYMBOL(__put_user_4); | 26 | EXPORT_SYMBOL(__put_user_4); |
27 | EXPORT_SYMBOL(__put_user_8); | 27 | EXPORT_SYMBOL(__put_user_8); |
28 | 28 | ||
29 | EXPORT_SYMBOL(copy_user_generic); | 29 | EXPORT_SYMBOL(copy_user_generic_string); |
30 | EXPORT_SYMBOL(copy_user_generic_unrolled); | ||
30 | EXPORT_SYMBOL(__copy_user_nocache); | 31 | EXPORT_SYMBOL(__copy_user_nocache); |
31 | EXPORT_SYMBOL(_copy_from_user); | 32 | EXPORT_SYMBOL(_copy_from_user); |
32 | EXPORT_SYMBOL(_copy_to_user); | 33 | EXPORT_SYMBOL(_copy_to_user); |
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index cf889d4e076a..71100c98e337 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S | |||
@@ -90,12 +90,6 @@ ENTRY(_copy_from_user) | |||
90 | CFI_ENDPROC | 90 | CFI_ENDPROC |
91 | ENDPROC(_copy_from_user) | 91 | ENDPROC(_copy_from_user) |
92 | 92 | ||
93 | ENTRY(copy_user_generic) | ||
94 | CFI_STARTPROC | ||
95 | ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string | ||
96 | CFI_ENDPROC | ||
97 | ENDPROC(copy_user_generic) | ||
98 | |||
99 | .section .fixup,"ax" | 93 | .section .fixup,"ax" |
100 | /* must zero dest */ | 94 | /* must zero dest */ |
101 | ENTRY(bad_from_user) | 95 | ENTRY(bad_from_user) |