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 8066f67c6aSlogin #define arch_try_cmpxchg(ptr, old_ptr, new_ptr) \ 8166f67c6aSlogin __raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr)) 82*61de2cdcSlogin 83*61de2cdcSlogin bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr);