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_ptr) \ 81 __raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr)) 82