diff options
| -rw-r--r-- | arch/x86/include/asm/cmpxchg_32.h | 30 | ||||
| -rw-r--r-- | arch/x86/kernel/i386_ksyms_32.c | 8 | ||||
| -rw-r--r-- | arch/x86/lib/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/lib/cmpxchg8b_emu.S | 57 |
4 files changed, 83 insertions, 14 deletions
diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h index 82ceb788a981..ee1931be6593 100644 --- a/arch/x86/include/asm/cmpxchg_32.h +++ b/arch/x86/include/asm/cmpxchg_32.h | |||
| @@ -312,19 +312,23 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, | |||
| 312 | 312 | ||
| 313 | extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64); | 313 | extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64); |
| 314 | 314 | ||
| 315 | #define cmpxchg64(ptr, o, n) \ | 315 | #define cmpxchg64(ptr, o, n) \ |
| 316 | ({ \ | 316 | ({ \ |
| 317 | __typeof__(*(ptr)) __ret; \ | 317 | __typeof__(*(ptr)) __ret; \ |
| 318 | if (likely(boot_cpu_data.x86 > 4)) \ | 318 | __typeof__(*(ptr)) __old = (o); \ |
| 319 | __ret = (__typeof__(*(ptr)))__cmpxchg64((ptr), \ | 319 | __typeof__(*(ptr)) __new = (n); \ |
| 320 | (unsigned long long)(o), \ | 320 | alternative_io("call cmpxchg8b_emu", \ |
| 321 | (unsigned long long)(n)); \ | 321 | "lock; cmpxchg8b (%%esi)" , \ |
| 322 | else \ | 322 | X86_FEATURE_CX8, \ |
| 323 | __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \ | 323 | "=A" (__ret), \ |
| 324 | (unsigned long long)(o), \ | 324 | "S" ((ptr)), "0" (__old), \ |
| 325 | (unsigned long long)(n)); \ | 325 | "b" ((unsigned int)__new), \ |
| 326 | __ret; \ | 326 | "c" ((unsigned int)(__new>>32)) \ |
| 327 | }) | 327 | : "memory"); \ |
| 328 | __ret; }) | ||
| 329 | |||
| 330 | |||
| 331 | |||
| 328 | #define cmpxchg64_local(ptr, o, n) \ | 332 | #define cmpxchg64_local(ptr, o, n) \ |
| 329 | ({ \ | 333 | ({ \ |
| 330 | __typeof__(*(ptr)) __ret; \ | 334 | __typeof__(*(ptr)) __ret; \ |
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c index 43cec6bdda63..1736c5a725aa 100644 --- a/arch/x86/kernel/i386_ksyms_32.c +++ b/arch/x86/kernel/i386_ksyms_32.c | |||
| @@ -10,6 +10,14 @@ | |||
| 10 | EXPORT_SYMBOL(mcount); | 10 | EXPORT_SYMBOL(mcount); |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | /* | ||
| 14 | * Note, this is a prototype to get at the symbol for | ||
| 15 | * the export, but dont use it from C code, it is used | ||
| 16 | * by assembly code and is not using C calling convention! | ||
| 17 | */ | ||
| 18 | extern void cmpxchg8b_emu(void); | ||
| 19 | EXPORT_SYMBOL(cmpxchg8b_emu); | ||
| 20 | |||
| 13 | /* Networking helper routines. */ | 21 | /* Networking helper routines. */ |
| 14 | EXPORT_SYMBOL(csum_partial_copy_generic); | 22 | EXPORT_SYMBOL(csum_partial_copy_generic); |
| 15 | 23 | ||
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 9e609206fac9..3e549b8ec8c9 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
| @@ -15,7 +15,7 @@ ifeq ($(CONFIG_X86_32),y) | |||
| 15 | obj-y += atomic64_32.o | 15 | obj-y += atomic64_32.o |
| 16 | lib-y += checksum_32.o | 16 | lib-y += checksum_32.o |
| 17 | lib-y += strstr_32.o | 17 | lib-y += strstr_32.o |
| 18 | lib-y += semaphore_32.o string_32.o | 18 | lib-y += semaphore_32.o string_32.o cmpxchg8b_emu.o |
| 19 | 19 | ||
| 20 | lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o | 20 | lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o |
| 21 | else | 21 | else |
diff --git a/arch/x86/lib/cmpxchg8b_emu.S b/arch/x86/lib/cmpxchg8b_emu.S new file mode 100644 index 000000000000..828cb710dec2 --- /dev/null +++ b/arch/x86/lib/cmpxchg8b_emu.S | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* | ||
| 2 | * This program is free software; you can redistribute it and/or | ||
| 3 | * modify it under the terms of the GNU General Public License | ||
| 4 | * as published by the Free Software Foundation; version 2 | ||
| 5 | * of the License. | ||
| 6 | * | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/linkage.h> | ||
| 10 | #include <asm/alternative-asm.h> | ||
| 11 | #include <asm/frame.h> | ||
| 12 | #include <asm/dwarf2.h> | ||
| 13 | |||
| 14 | |||
| 15 | .text | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Inputs: | ||
| 19 | * %esi : memory location to compare | ||
| 20 | * %eax : low 32 bits of old value | ||
| 21 | * %edx : high 32 bits of old value | ||
| 22 | * %ebx : low 32 bits of new value | ||
| 23 | * %ecx : high 32 bits of new value | ||
| 24 | */ | ||
| 25 | ENTRY(cmpxchg8b_emu) | ||
| 26 | CFI_STARTPROC | ||
| 27 | |||
| 28 | # | ||
| 29 | # Emulate 'cmpxchg8b (%esi)' on UP except we don't | ||
| 30 | # set the whole ZF thing (caller will just compare | ||
| 31 | # eax:edx with the expected value) | ||
| 32 | # | ||
| 33 | cmpxchg8b_emu: | ||
| 34 | pushfl | ||
| 35 | cli | ||
| 36 | |||
| 37 | cmpl (%esi), %eax | ||
| 38 | jne not_same | ||
| 39 | cmpl 4(%esi), %edx | ||
| 40 | jne half_same | ||
| 41 | |||
| 42 | movl %ebx, (%esi) | ||
| 43 | movl %ecx, 4(%esi) | ||
| 44 | |||
| 45 | popfl | ||
| 46 | ret | ||
| 47 | |||
| 48 | not_same: | ||
| 49 | movl (%esi), %eax | ||
| 50 | half_same: | ||
| 51 | movl 4(%esi), %edx | ||
| 52 | |||
| 53 | popfl | ||
| 54 | ret | ||
| 55 | |||
| 56 | CFI_ENDPROC | ||
| 57 | ENDPROC(cmpxchg8b_emu) | ||
