1 /* Copyright 2019 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
7 #include <metal/memory.h>
8 #include <metal/compiler.h>
12 * @brief An API for creating and using a software lock/mutex
15 /* TODO: How can we make the exception code platform-independant? */
16 #define _METAL_STORE_AMO_ACCESS_FAULT 7
19 * @def METAL_LOCK_DECLARE
20 * @brief Declare a lock
22 * Locks must be declared with METAL_LOCK_DECLARE to ensure that the lock
23 * is linked into a memory region which supports atomic memory operations.
25 #define METAL_LOCK_DECLARE(name) \
26 __attribute__((section(".data.locks"))) \
27 struct metal_lock name
30 * @brief A handle for a lock
37 * @brief Initialize a lock
38 * @param lock The handle for a lock
39 * @return 0 if the lock is successfully initialized. A non-zero code indicates failure.
41 * If the lock cannot be initialized, attempts to take or give the lock
42 * will result in a Store/AMO access fault.
44 inline int metal_lock_init(struct metal_lock *lock) {
46 /* Get a handle for the memory which holds the lock state */
47 struct metal_memory *lock_mem = metal_get_memory_from_address((uintptr_t) &(lock->_state));
52 /* If the memory doesn't support atomics, report an error */
53 if(!metal_memory_supports_atomics(lock_mem)) {
67 * @param lock The handle for a lock
68 * @return 0 if the lock is successfully taken
70 * If the lock initialization failed, attempts to take a lock will result in
71 * a Store/AMO access fault.
73 inline int metal_lock_take(struct metal_lock *lock) {
79 __asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
81 : [new] "r" (new), [state] "r" (&(lock->_state))
87 /* Store the memory address in mtval like a normal store/amo access fault */
88 __asm__ ("csrw mtval, %[state]"
89 :: [state] "r" (&(lock->_state)));
91 /* Trigger a Store/AMO access fault */
92 _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
94 /* If execution returns, indicate failure */
100 * @brief Give back a held lock
101 * @param lock The handle for a lock
102 * @return 0 if the lock is successfully given
104 * If the lock initialization failed, attempts to give a lock will result in
105 * a Store/AMO access fault.
107 inline int metal_lock_give(struct metal_lock *lock) {
108 #ifdef __riscv_atomic
109 __asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
110 :: [state] "r" (&(lock->_state))
115 /* Store the memory address in mtval like a normal store/amo access fault */
116 __asm__ ("csrw mtval, %[state]"
117 :: [state] "r" (&(lock->_state)));
119 /* Trigger a Store/AMO access fault */
120 _metal_trap(_METAL_STORE_AMO_ACCESS_FAULT);
122 /* If execution returns, indicate failure */
127 #endif /* METAL__LOCK_H */