xref: /DragonOS/kernel/src/arch/x86_64/include/asm/cmpxchg.h (revision 7cc4a02c7ff7bafd798b185beb7b0c2986b9f32f)
166f67c6aSlogin #pragma once
266f67c6aSlogin #include <common/compiler.h>
366f67c6aSlogin #include <asm/asm.h>
466f67c6aSlogin 
566f67c6aSlogin /**
666f67c6aSlogin  * @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。
766f67c6aSlogin  */
866f67c6aSlogin extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg");
966f67c6aSlogin 
1066f67c6aSlogin // 定义常量:操作符涉及到的字节数
1166f67c6aSlogin #define __X86_CASE_B 1
1266f67c6aSlogin #define __X86_CASE_W 2
1366f67c6aSlogin #define __X86_CASE_L 4
1466f67c6aSlogin #define __X86_CASE_Q 8
1566f67c6aSlogin 
1666f67c6aSlogin /**
1766f67c6aSlogin  * @brief lock cmpxchg指令的包装。
1866f67c6aSlogin  * 将_ptr指向的值与old_ptr指向的值做比较,如果相等,则将_new指向的值,加载到_ptr指向的值中。
1966f67c6aSlogin  */
2066f67c6aSlogin #define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size)               \
2166f67c6aSlogin     ({                                                              \
2266f67c6aSlogin         bool is_success = false;                                    \
2366f67c6aSlogin         typeof(_ptr) _old = (typeof(_ptr))(_old_ptr);               \
2466f67c6aSlogin         typeof(*(_ptr)) __old = *_old;                              \
2566f67c6aSlogin         typeof(*(_ptr)) __new = (_new);                             \
2666f67c6aSlogin         switch (size)                                               \
2766f67c6aSlogin         {                                                           \
2866f67c6aSlogin         case __X86_CASE_B:                                          \
2966f67c6aSlogin         {                                                           \
3066f67c6aSlogin             volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr);   \
3166f67c6aSlogin             asm volatile("lock cmpxchgb %[new], %[ptr]\n\t"         \
3266f67c6aSlogin                          : CC_OUT(z)(is_success),                   \
3366f67c6aSlogin                            [ptr] "+m"(*__ptr),                      \
3466f67c6aSlogin                            [old] "+a"(__old)                        \
3566f67c6aSlogin                          : [new] "q"(__new)                         \
3666f67c6aSlogin                          : "memory");                               \
3766f67c6aSlogin             break;                                                  \
3866f67c6aSlogin         }                                                           \
3966f67c6aSlogin         case __X86_CASE_W:                                          \
4066f67c6aSlogin         {                                                           \
4166f67c6aSlogin             volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \
4266f67c6aSlogin             asm volatile("lock cmpxchgw %[new], %[ptr]\n\t"         \
4366f67c6aSlogin                          : CC_OUT(z)(is_success),                   \
4466f67c6aSlogin                            [ptr] "+m"(*__ptr),                      \
4566f67c6aSlogin                            [old] "+a"(__old)                        \
4666f67c6aSlogin                          : [new] "q"(__new)                         \
4766f67c6aSlogin                          : "memory");                               \
4866f67c6aSlogin             break;                                                  \
4966f67c6aSlogin         }                                                           \
5066f67c6aSlogin         case __X86_CASE_L:                                          \
5166f67c6aSlogin         {                                                           \
5266f67c6aSlogin             volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \
5366f67c6aSlogin             asm volatile("lock cmpxchgl %[new], %[ptr]\n\t"         \
5466f67c6aSlogin                          : CC_OUT(z)(is_success),                   \
5566f67c6aSlogin                            [ptr] "+m"(*__ptr),                      \
5666f67c6aSlogin                            [old] "+a"(__old)                        \
5766f67c6aSlogin                          : [new] "q"(__new)                         \
5866f67c6aSlogin                          : "memory");                               \
5966f67c6aSlogin             break;                                                  \
6066f67c6aSlogin         }                                                           \
6166f67c6aSlogin         case __X86_CASE_Q:                                          \
6266f67c6aSlogin         {                                                           \
6366f67c6aSlogin             volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \
6466f67c6aSlogin             asm volatile("lock cmpxchgq %[new], %[ptr]\n\t"         \
6566f67c6aSlogin                          : CC_OUT(z)(is_success),                   \
6666f67c6aSlogin                            [ptr] "+m"(*__ptr),                      \
6766f67c6aSlogin                            [old] "+a"(__old)                        \
6866f67c6aSlogin                          : [new] "q"(__new)                         \
6966f67c6aSlogin                          : "memory");                               \
7066f67c6aSlogin             break;                                                  \
7166f67c6aSlogin         }                                                           \
7266f67c6aSlogin         default:                                                    \
7366f67c6aSlogin             __cmpxchg_wrong_size();                                 \
7466f67c6aSlogin         }                                                           \
7566f67c6aSlogin         if (unlikely(is_success == false))                          \
7666f67c6aSlogin             *_old = __old;                                          \
7766f67c6aSlogin         likely(is_success);                                         \
7866f67c6aSlogin     })
7966f67c6aSlogin 
80*7cc4a02cSzhaoyao73 #define arch_try_cmpxchg(ptr, old_ptr, new) \
81*7cc4a02cSzhaoyao73     __raw_try_cmpxchg((ptr), (old_ptr), (new), sizeof(*ptr))
8261de2cdcSlogin 
8361de2cdcSlogin bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr);
84