xref: /DragonOS/kernel/src/arch/x86_64/include/asm/cmpxchg.h (revision 86ee1395de7c614865236ee15071c3603b794e44)
1 #pragma once
2 #include <common/compiler.h>
3 #include <asm/asm.h>
4 
5 /**
6  * @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。
7  */
8 extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg");
9 
10 // 定义常量:操作符涉及到的字节数
11 #define __X86_CASE_B 1
12 #define __X86_CASE_W 2
13 #define __X86_CASE_L 4
14 #define __X86_CASE_Q 8
15 
16 /**
17  * @brief lock cmpxchg指令的包装。
18  * 将_ptr指向的值与old_ptr指向的值做比较,如果相等,则将_new指向的值,加载到_ptr指向的值中。
19  */
20 #define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size)               \
21     ({                                                              \
22         bool is_success = false;                                    \
23         typeof(_ptr) _old = (typeof(_ptr))(_old_ptr);               \
24         typeof(*(_ptr)) __old = *_old;                              \
25         typeof(*(_ptr)) __new = (_new);                             \
26         switch (size)                                               \
27         {                                                           \
28         case __X86_CASE_B:                                          \
29         {                                                           \
30             volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr);   \
31             asm volatile("lock cmpxchgb %[new], %[ptr]\n\t"         \
32                          : CC_OUT(z)(is_success),                   \
33                            [ptr] "+m"(*__ptr),                      \
34                            [old] "+a"(__old)                        \
35                          : [new] "q"(__new)                         \
36                          : "memory");                               \
37             break;                                                  \
38         }                                                           \
39         case __X86_CASE_W:                                          \
40         {                                                           \
41             volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \
42             asm volatile("lock cmpxchgw %[new], %[ptr]\n\t"         \
43                          : CC_OUT(z)(is_success),                   \
44                            [ptr] "+m"(*__ptr),                      \
45                            [old] "+a"(__old)                        \
46                          : [new] "q"(__new)                         \
47                          : "memory");                               \
48             break;                                                  \
49         }                                                           \
50         case __X86_CASE_L:                                          \
51         {                                                           \
52             volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \
53             asm volatile("lock cmpxchgl %[new], %[ptr]\n\t"         \
54                          : CC_OUT(z)(is_success),                   \
55                            [ptr] "+m"(*__ptr),                      \
56                            [old] "+a"(__old)                        \
57                          : [new] "q"(__new)                         \
58                          : "memory");                               \
59             break;                                                  \
60         }                                                           \
61         case __X86_CASE_Q:                                          \
62         {                                                           \
63             volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \
64             asm volatile("lock cmpxchgq %[new], %[ptr]\n\t"         \
65                          : CC_OUT(z)(is_success),                   \
66                            [ptr] "+m"(*__ptr),                      \
67                            [old] "+a"(__old)                        \
68                          : [new] "q"(__new)                         \
69                          : "memory");                               \
70             break;                                                  \
71         }                                                           \
72         default:                                                    \
73             __cmpxchg_wrong_size();                                 \
74         }                                                           \
75         if (unlikely(is_success == false))                          \
76             *_old = __old;                                          \
77         likely(is_success);                                         \
78     })
79 
80 #define arch_try_cmpxchg(ptr, old_ptr, new) \
81     __raw_try_cmpxchg((ptr), (old_ptr), (new), sizeof(*ptr))
82 
83 bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr);
84