| // Copyright Microsoft and CHERIoT Contributors. | |
| // SPDX-License-Identifier: MIT | |
| #include "atomic.hh" | |
| #include "string.h" | |
| /** | |
| * The variable-sized libcalls have the same names as builtins and clang | |
| * doesn't let us define functions with the same name as builtins, so we define | |
| * them without the `__` prefix and expose their assembly symbol as the expected | |
| * name. | |
| */ | |
| #define DECLARE_ATOMIC_LIBCALL_ALIAS(name, ret, ...) \ | |
| [[cheri::interrupt_state(disabled)]] __cheri_libcall ret name( \ | |
| __VA_ARGS__) asm("__" #name); | |
| /** | |
| * Atomically load a variable number of bytes from `src` and store them in | |
| * `dest`. | |
| */ | |
| DECLARE_ATOMIC_LIBCALL_ALIAS(atomic_load, void, int, const void *, void *, int) | |
| void atomic_load(int size, const void *src, void *dest, int) | |
| { | |
| memcpy(dest, src, size); | |
| } | |
| /** | |
| * Atomically load a variable number of bytes from `src` and store them in | |
| * `dest`. | |
| */ | |
| DECLARE_ATOMIC_LIBCALL_ALIAS(atomic_store, void, int, void *, const void *, int) | |
| void atomic_store(int size, void *dest, const void *src, int) | |
| { | |
| memcpy(dest, src, size); | |
| } | |
| /** | |
| * Atomically replace the value at `ptr` with the value at `val` and the return | |
| * the old value via `old`. All pointers point to at least `size` bytes. | |
| */ | |
| DECLARE_ATOMIC_LIBCALL_ALIAS(atomic_exchange, | |
| void, | |
| int, | |
| void *, | |
| void *, | |
| const void *, | |
| int) | |
| void atomic_exchange(int size, void *ptr, void *old, const void *val, int) | |
| { | |
| memcpy(old, ptr, size); | |
| memcpy(ptr, val, size); | |
| } | |
| /** | |
| * Attempt to atomically replace `size` bytes pointed to by `ptr` with those at | |
| * `desired`, if and only if they currently contain the same pattern pointed to | |
| * by `expected`. Returns 1 on success, 0 on failure. In case of failure, the | |
| * current object stored at `ptr` will be copied over `expected`. | |
| */ | |
| DECLARE_ATOMIC_LIBCALL_ALIAS(atomic_compare_exchange, | |
| int, | |
| int, | |
| void *, | |
| void *, | |
| const void *, | |
| int, | |
| int) | |
| int atomic_compare_exchange(int size, | |
| void *ptr, | |
| void *expected, | |
| const void *desired, | |
| int, | |
| int) | |
| { | |
| if (memcmp(ptr, expected, size) == 0) | |
| { | |
| memcpy(ptr, desired, size); | |
| return 1; | |
| } | |
| memcpy(expected, ptr, size); | |
| return 0; | |
| } |