hc
2023-10-25 6c2073b7aa40e29d0eca7d571dd7bc590c7ecaa7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef TOOLS_ASM_X86_CMPXCHG_H
#define TOOLS_ASM_X86_CMPXCHG_H
 
#include <linux/compiler.h>
 
/*
 * Non-existant functions to indicate usage errors at link time
 * (or compile-time if the compiler implements __compiletime_error().
 */
extern void __cmpxchg_wrong_size(void)
   __compiletime_error("Bad argument size for cmpxchg");
 
/*
 * Constants for operation sizes. On 32-bit, the 64-bit size it set to
 * -1 because sizeof will never return -1, thereby making those switch
 * case statements guaranteeed dead code which the compiler will
 * eliminate, and allowing the "missing symbol in the default case" to
 * indicate a usage error.
 */
#define __X86_CASE_B    1
#define __X86_CASE_W    2
#define __X86_CASE_L    4
#ifdef __x86_64__
#define __X86_CASE_Q    8
#else
#define    __X86_CASE_Q    -1        /* sizeof will never return -1 */
#endif
 
/*
 * Atomic compare and exchange.  Compare OLD with MEM, if identical,
 * store NEW in MEM.  Return the initial value in MEM.  Success is
 * indicated by comparing RETURN with OLD.
 */
#define __raw_cmpxchg(ptr, old, new, size, lock)            \
({                                    \
   __typeof__(*(ptr)) __ret;                    \
   __typeof__(*(ptr)) __old = (old);                \
   __typeof__(*(ptr)) __new = (new);                \
   switch (size) {                            \
   case __X86_CASE_B:                        \
   {                                \
       volatile u8 *__ptr = (volatile u8 *)(ptr);        \
       asm volatile(lock "cmpxchgb %2,%1"            \
                : "=a" (__ret), "+m" (*__ptr)        \
                : "q" (__new), "0" (__old)            \
                : "memory");                \
       break;                            \
   }                                \
   case __X86_CASE_W:                        \
   {                                \
       volatile u16 *__ptr = (volatile u16 *)(ptr);        \
       asm volatile(lock "cmpxchgw %2,%1"            \
                : "=a" (__ret), "+m" (*__ptr)        \
                : "r" (__new), "0" (__old)            \
                : "memory");                \
       break;                            \
   }                                \
   case __X86_CASE_L:                        \
   {                                \
       volatile u32 *__ptr = (volatile u32 *)(ptr);        \
       asm volatile(lock "cmpxchgl %2,%1"            \
                : "=a" (__ret), "+m" (*__ptr)        \
                : "r" (__new), "0" (__old)            \
                : "memory");                \
       break;                            \
   }                                \
   case __X86_CASE_Q:                        \
   {                                \
       volatile u64 *__ptr = (volatile u64 *)(ptr);        \
       asm volatile(lock "cmpxchgq %2,%1"            \
                : "=a" (__ret), "+m" (*__ptr)        \
                : "r" (__new), "0" (__old)            \
                : "memory");                \
       break;                            \
   }                                \
   default:                            \
       __cmpxchg_wrong_size();                    \
   }                                \
   __ret;                                \
})
 
#define __cmpxchg(ptr, old, new, size)                    \
   __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
 
#define cmpxchg(ptr, old, new)                        \
   __cmpxchg(ptr, old, new, sizeof(*(ptr)))
 
 
#endif    /* TOOLS_ASM_X86_CMPXCHG_H */