Path: blob/main/sys/contrib/ck/include/gcc/x86/ck_pr.h
48522 views
/*1* Copyright 2009-2015 Samy Al Bahra.2* Copyright 2011 Devon H. O'Dell <[email protected]>3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#ifndef CK_PR_X86_H28#define CK_PR_X86_H2930#ifndef CK_PR_H31#error Do not include this file directly, use ck_pr.h32#endif3334#include <ck_cc.h>35#include <ck_md.h>36#include <ck_stdint.h>3738/*39* The following represent supported atomic operations.40* These operations may be emulated.41*/42#include "ck_f_pr.h"4344/* Minimum requirements for the CK_PR interface are met. */45#define CK_F_PR4647/*48* Prevent speculative execution in busy-wait loops (P4 <=) or "predefined49* delay".50*/51CK_CC_INLINE static void52ck_pr_stall(void)53{54__asm__ __volatile__("pause" ::: "memory");55return;56}5758#ifdef CK_MD_UMP59#define CK_PR_LOCK_PREFIX60#define CK_PR_FENCE(T, I) \61CK_CC_INLINE static void \62ck_pr_fence_strict_##T(void) \63{ \64__asm__ __volatile__("" ::: "memory"); \65return; \66}67#else68#define CK_PR_LOCK_PREFIX "lock "69#define CK_PR_FENCE(T, I) \70CK_CC_INLINE static void \71ck_pr_fence_strict_##T(void) \72{ \73__asm__ __volatile__(I ::: "memory"); \74return; \75}76#endif /* CK_MD_UMP */7778#if defined(CK_MD_SSE_DISABLE)79/* If SSE is disabled, then use atomic operations for serialization. */80#define CK_MD_X86_MFENCE "lock addl $0, (%%esp)"81#define CK_MD_X86_SFENCE CK_MD_X86_MFENCE82#define CK_MD_X86_LFENCE CK_MD_X86_MFENCE83#else84#define CK_MD_X86_SFENCE "sfence"85#define CK_MD_X86_LFENCE "lfence"86#define CK_MD_X86_MFENCE "mfence"87#endif /* !CK_MD_SSE_DISABLE */8889CK_PR_FENCE(atomic, "")90CK_PR_FENCE(atomic_store, "")91CK_PR_FENCE(atomic_load, "")92CK_PR_FENCE(store_atomic, "")93CK_PR_FENCE(load_atomic, "")94CK_PR_FENCE(load, CK_MD_X86_LFENCE)95CK_PR_FENCE(load_store, CK_MD_X86_MFENCE)96CK_PR_FENCE(store, CK_MD_X86_SFENCE)97CK_PR_FENCE(store_load, CK_MD_X86_MFENCE)98CK_PR_FENCE(memory, CK_MD_X86_MFENCE)99CK_PR_FENCE(release, CK_MD_X86_MFENCE)100CK_PR_FENCE(acquire, CK_MD_X86_MFENCE)101CK_PR_FENCE(acqrel, CK_MD_X86_MFENCE)102CK_PR_FENCE(lock, CK_MD_X86_MFENCE)103CK_PR_FENCE(unlock, CK_MD_X86_MFENCE)104105#undef CK_PR_FENCE106107/*108* Atomic fetch-and-store operations.109*/110#define CK_PR_FAS(S, M, T, C, I) \111CK_CC_INLINE static T \112ck_pr_fas_##S(M *target, T v) \113{ \114__asm__ __volatile__(I " %0, %1" \115: "+m" (*(C *)target), \116"+q" (v) \117: \118: "memory"); \119return v; \120}121122CK_PR_FAS(ptr, void, void *, uint32_t, "xchgl")123124#define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I)125126CK_PR_FAS_S(char, char, "xchgb")127CK_PR_FAS_S(uint, unsigned int, "xchgl")128CK_PR_FAS_S(int, int, "xchgl")129CK_PR_FAS_S(32, uint32_t, "xchgl")130CK_PR_FAS_S(16, uint16_t, "xchgw")131CK_PR_FAS_S(8, uint8_t, "xchgb")132133#undef CK_PR_FAS_S134#undef CK_PR_FAS135136#define CK_PR_LOAD(S, M, T, C, I) \137CK_CC_INLINE static T \138ck_pr_md_load_##S(const M *target) \139{ \140T r; \141__asm__ __volatile__(I " %1, %0" \142: "=q" (r) \143: "m" (*(const C *)target) \144: "memory"); \145return (r); \146}147148CK_PR_LOAD(ptr, void, void *, uint32_t, "movl")149150#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I)151152CK_PR_LOAD_S(char, char, "movb")153CK_PR_LOAD_S(uint, unsigned int, "movl")154CK_PR_LOAD_S(int, int, "movl")155CK_PR_LOAD_S(32, uint32_t, "movl")156CK_PR_LOAD_S(16, uint16_t, "movw")157CK_PR_LOAD_S(8, uint8_t, "movb")158159#undef CK_PR_LOAD_S160#undef CK_PR_LOAD161162#define CK_PR_STORE(S, M, T, C, I) \163CK_CC_INLINE static void \164ck_pr_md_store_##S(M *target, T v) \165{ \166__asm__ __volatile__(I " %1, %0" \167: "=m" (*(C *)target) \168: CK_CC_IMM "q" (v) \169: "memory"); \170return; \171}172173CK_PR_STORE(ptr, void, const void *, uint32_t, "movl")174175#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I)176177CK_PR_STORE_S(char, char, "movb")178CK_PR_STORE_S(uint, unsigned int, "movl")179CK_PR_STORE_S(int, int, "movl")180CK_PR_STORE_S(32, uint32_t, "movl")181CK_PR_STORE_S(16, uint16_t, "movw")182CK_PR_STORE_S(8, uint8_t, "movb")183184#undef CK_PR_STORE_S185#undef CK_PR_STORE186187/*188* Atomic fetch-and-add operations.189*/190#define CK_PR_FAA(S, M, T, C, I) \191CK_CC_INLINE static T \192ck_pr_faa_##S(M *target, T d) \193{ \194__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \195: "+m" (*(C *)target), \196"+q" (d) \197: \198: "memory", "cc"); \199return (d); \200}201202CK_PR_FAA(ptr, void, uintptr_t, uint32_t, "xaddl")203204#define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I)205206CK_PR_FAA_S(char, char, "xaddb")207CK_PR_FAA_S(uint, unsigned int, "xaddl")208CK_PR_FAA_S(int, int, "xaddl")209CK_PR_FAA_S(32, uint32_t, "xaddl")210CK_PR_FAA_S(16, uint16_t, "xaddw")211CK_PR_FAA_S(8, uint8_t, "xaddb")212213#undef CK_PR_FAA_S214#undef CK_PR_FAA215216/*217* Atomic store-only unary operations.218*/219#define CK_PR_UNARY(K, S, T, C, I) \220CK_PR_UNARY_R(K, S, T, C, I) \221CK_PR_UNARY_V(K, S, T, C, I)222223#define CK_PR_UNARY_R(K, S, T, C, I) \224CK_CC_INLINE static void \225ck_pr_##K##_##S(T *target) \226{ \227__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0" \228: "+m" (*(C *)target) \229: \230: "memory", "cc"); \231return; \232}233234#define CK_PR_UNARY_V(K, S, T, C, I) \235CK_CC_INLINE static bool \236ck_pr_##K##_##S##_is_zero(T *target) \237{ \238bool ret; \239__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1" \240: "+m" (*(C *)target), \241"=qm" (ret) \242: \243: "memory", "cc"); \244return ret; \245}246247#define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I)248249#define CK_PR_GENERATE(K) \250CK_PR_UNARY(K, ptr, void, uint32_t, #K "l") \251CK_PR_UNARY_S(K, char, char, #K "b") \252CK_PR_UNARY_S(K, int, int, #K "l") \253CK_PR_UNARY_S(K, uint, unsigned int, #K "l") \254CK_PR_UNARY_S(K, 32, uint32_t, #K "l") \255CK_PR_UNARY_S(K, 16, uint16_t, #K "w") \256CK_PR_UNARY_S(K, 8, uint8_t, #K "b")257258CK_PR_GENERATE(inc)259CK_PR_GENERATE(dec)260CK_PR_GENERATE(neg)261262/* not does not affect condition flags. */263#undef CK_PR_UNARY_V264#define CK_PR_UNARY_V(a, b, c, d, e)265CK_PR_GENERATE(not)266267#undef CK_PR_GENERATE268#undef CK_PR_UNARY_S269#undef CK_PR_UNARY_V270#undef CK_PR_UNARY_R271#undef CK_PR_UNARY272273/*274* Atomic store-only binary operations.275*/276#define CK_PR_BINARY(K, S, M, T, C, I) \277CK_CC_INLINE static void \278ck_pr_##K##_##S(M *target, T d) \279{ \280__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \281: "+m" (*(C *)target) \282: CK_CC_IMM "q" (d) \283: "memory", "cc"); \284return; \285}286287#define CK_PR_BINARY_S(K, S, T, I) CK_PR_BINARY(K, S, T, T, T, I)288289#define CK_PR_GENERATE(K) \290CK_PR_BINARY(K, ptr, void, uintptr_t, uint32_t, #K "l") \291CK_PR_BINARY_S(K, char, char, #K "b") \292CK_PR_BINARY_S(K, int, int, #K "l") \293CK_PR_BINARY_S(K, uint, unsigned int, #K "l") \294CK_PR_BINARY_S(K, 32, uint32_t, #K "l") \295CK_PR_BINARY_S(K, 16, uint16_t, #K "w") \296CK_PR_BINARY_S(K, 8, uint8_t, #K "b")297298CK_PR_GENERATE(add)299CK_PR_GENERATE(sub)300CK_PR_GENERATE(and)301CK_PR_GENERATE(or)302CK_PR_GENERATE(xor)303304#undef CK_PR_GENERATE305#undef CK_PR_BINARY_S306#undef CK_PR_BINARY307308/*309* Atomic compare and swap, with a variant that sets *v to the old value of target.310*/311#ifdef __GCC_ASM_FLAG_OUTPUTS__312#define CK_PR_CAS(S, M, T, C, I) \313CK_CC_INLINE static bool \314ck_pr_cas_##S(M *target, T compare, T set) \315{ \316bool z; \317__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0" \318: "+m" (*(C *)target), \319"=@ccz" (z), \320/* RAX is clobbered by cmpxchg. */ \321"+a" (compare) \322: "q" (set) \323: "memory", "cc"); \324return z; \325} \326\327CK_CC_INLINE static bool \328ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \329{ \330bool z; \331__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0;" \332: "+m" (*(C *)target), \333"=@ccz" (z), \334"+a" (compare) \335: "q" (set) \336: "memory", "cc"); \337*(T *)v = compare; \338return z; \339}340#else341#define CK_PR_CAS(S, M, T, C, I) \342CK_CC_INLINE static bool \343ck_pr_cas_##S(M *target, T compare, T set) \344{ \345bool z; \346__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1" \347: "+m" (*(C *)target), \348"=a" (z) \349: "q" (set), \350"a" (compare) \351: "memory", "cc"); \352return z; \353} \354\355CK_CC_INLINE static bool \356ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \357{ \358bool z; \359__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0;" \360"setz %1;" \361: "+m" (*(C *)target), \362"=q" (z), \363"+a" (compare) \364: "q" (set) \365: "memory", "cc"); \366*(T *)v = compare; \367return z; \368}369#endif370371CK_PR_CAS(ptr, void, void *, uint32_t, "cmpxchgl")372373#define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I)374375CK_PR_CAS_S(char, char, "cmpxchgb")376CK_PR_CAS_S(int, int, "cmpxchgl")377CK_PR_CAS_S(uint, unsigned int, "cmpxchgl")378CK_PR_CAS_S(32, uint32_t, "cmpxchgl")379CK_PR_CAS_S(16, uint16_t, "cmpxchgw")380CK_PR_CAS_S(8, uint8_t, "cmpxchgb")381382#undef CK_PR_CAS_S383#undef CK_PR_CAS384385/*386* Atomic bit test operations.387*/388#define CK_PR_BT(K, S, T, P, C, I) \389CK_CC_INLINE static bool \390ck_pr_##K##_##S(T *target, unsigned int b) \391{ \392bool c; \393__asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1" \394: "+m" (*(C *)target), \395"=q" (c) \396: "q" ((P)b) \397: "memory", "cc"); \398return (bool)c; \399}400401#define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I)402403#define CK_PR_GENERATE(K) \404CK_PR_BT(K, ptr, void, uint32_t, uint32_t, #K "l %2, %0") \405CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0") \406CK_PR_BT_S(K, int, int, #K "l %2, %0") \407CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0") \408CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0")409410CK_PR_GENERATE(btc)411CK_PR_GENERATE(bts)412CK_PR_GENERATE(btr)413414#undef CK_PR_GENERATE415#undef CK_PR_BT416417#endif /* CK_PR_X86_H */418419420421