| // Copyright Microsoft and CHERIoT Contributors. | |
| // SPDX-License-Identifier: MIT | |
| #include <compartment.h> | |
| #include <stdint.h> | |
| /** | |
| * The helper functions need to expose an unmangled name because the compiler | |
| * inserts calls to them. Declare them using the asm label extension. | |
| */ | |
| #define DECLARE_ATOMIC_LIBCALL(name, ret, ...) \ | |
| [[cheri::interrupt_state(disabled)]] __cheri_libcall ret name( \ | |
| __VA_ARGS__) asm(#name); | |
| /** | |
| * Macro that defines a library function to implement an atomic load for the | |
| * specified size, using the specified type. | |
| * | |
| * Ideally the compiler should know that a system with a single core can do a | |
| * single load for most cases of this, rather than needing a cross-library | |
| * call, so eventually this will go away. | |
| */ | |
| #define DEFINE_ATOMIC_LOAD(size, type) \ | |
| DECLARE_ATOMIC_LIBCALL(__atomic_load_##size, type, const type *, int); \ | |
| type __atomic_load_##size(const type *ptr, int) \ | |
| { \ | |
| static_assert(sizeof(type) == size, "Invalid type for size"); \ | |
| return *ptr; \ | |
| } | |
| /** | |
| * Macro that defines a library function to implement an atomic store for the | |
| * specified size, using the specified type. | |
| * | |
| * Ideally the compiler should know that a system with a single core can do a | |
| * single store for most cases of this, rather than needing a cross-library | |
| * call, so eventually this will go away. | |
| */ | |
| #define DEFINE_ATOMIC_STORE(size, type) \ | |
| DECLARE_ATOMIC_LIBCALL(__atomic_store_##size, void, type *, type, int); \ | |
| void __atomic_store_##size(type *ptr, type value, int) \ | |
| { \ | |
| static_assert(sizeof(type) == size, "Invalid type for size"); \ | |
| *ptr = value; \ | |
| } | |
| /** | |
| * Macro that defines a library function to implement an atomic | |
| * fetch-and-something for the specified size, using the specified type. The | |
| * name is the name of the operation and `op` is the C++ operator that | |
| * implements it. | |
| */ | |
| #define DEFINE_ATOMIC_FETCH_OP(size, type, name, op) \ | |
| DECLARE_ATOMIC_LIBCALL( \ | |
| __atomic_fetch_##name##_##size, type, type *, type, int); \ | |
| type __atomic_fetch_##name##_##size(type *ptr, type value, int) \ | |
| { \ | |
| static_assert(sizeof(type) == size, "Invalid type for size"); \ | |
| type tmp = *ptr; \ | |
| *ptr = tmp op value; \ | |
| return tmp; \ | |
| } | |
| /** | |
| * Helper macro that defines all of the cases of atomic operations. | |
| */ | |
| #define DEFINE_ATOMIC_FETCH_OPS(size, type) \ | |
| DEFINE_ATOMIC_FETCH_OP(size, type, add, +) \ | |
| DEFINE_ATOMIC_FETCH_OP(size, type, sub, -) \ | |
| DEFINE_ATOMIC_FETCH_OP(size, type, and, &) \ | |
| DEFINE_ATOMIC_FETCH_OP(size, type, or, |) \ | |
| DEFINE_ATOMIC_FETCH_OP(size, type, xor, ^) | |
| /** | |
| * Macro that defines a library function to implement an atomic exchange for the | |
| * specified size, using the specified type. | |
| */ | |
| #define DEFINE_ATOMIC_EXCHANGE(size, type) \ | |
| DECLARE_ATOMIC_LIBCALL(__atomic_exchange_##size, type, type *, type, int); \ | |
| type __atomic_exchange_##size(type *ptr, type value, int) \ | |
| { \ | |
| static_assert(sizeof(type) == size, "Invalid type for size"); \ | |
| type tmp = *ptr; \ | |
| *ptr = value; \ | |
| return tmp; \ | |
| } | |
| /** | |
| * Macro that defines a library function to implement an atomic compare and | |
| * exchange for the specified size, using the specified type. | |
| */ | |
| #define DEFINE_ATOMIC_COMPARE_EXCHANGE(size, type) \ | |
| DECLARE_ATOMIC_LIBCALL( \ | |
| __atomic_compare_exchange_##size, int, type *, type *, type, int, int); \ | |
| int __atomic_compare_exchange_##size( \ | |
| type *ptr, type *expected, type desired, int, int) \ | |
| { \ | |
| static_assert(sizeof(type) == size, "Invalid type for size"); \ | |
| if (*ptr == *expected) \ | |
| { \ | |
| *ptr = desired; \ | |
| return 1; \ | |
| } \ | |
| *expected = *ptr; \ | |
| return 0; \ | |
| } | |
| #define DEFINE_ALL_ATOMIC_OPS(size, type) \ | |
| DEFINE_ATOMIC_LOAD(size, type) \ | |
| DEFINE_ATOMIC_STORE(size, type) \ | |
| DEFINE_ATOMIC_EXCHANGE(size, type) \ | |
| DEFINE_ATOMIC_COMPARE_EXCHANGE(size, type) \ | |
| DEFINE_ATOMIC_FETCH_OPS(size, type) |