Fixed bug in RISC-V env_user_mem_free
[akaros.git] / kern / arch / riscv / atomic.h
1 #ifndef ROS_KERN_ARCH_ATOMIC_H
2 #define ROS_KERN_ARCH_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <arch/arch.h>
6
7 bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
8 bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
9 bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val, uint32_t new_val);
10
11 static inline void atomic_init(atomic_t *number, long val)
12 {
13   *(volatile long*)number = val;
14 }
15
16 static inline long atomic_read(atomic_t *number)
17 {
18   return *(volatile long*)number;
19 }
20
21 static inline void atomic_set(atomic_t *number, long val)
22 {
23   *(volatile long*)number = val;
24 }
25
26 /* Adds val to number, returning number's original value */
27 static inline long atomic_fetch_and_add(atomic_t *number, long val)
28 {
29         return __sync_fetch_and_add((long*)number, val);
30 }
31
32 static inline void atomic_add(atomic_t *number, long val)
33 {
34         atomic_fetch_and_add(number, val);
35 }
36
37 static inline void atomic_inc(atomic_t *number)
38 {
39         atomic_add(number, 1);
40 }
41
42 static inline void atomic_dec(atomic_t *number)
43 {
44         atomic_add(number, -1);
45 }
46
47 /* Adds val to number, so long as number was not zero.  Returns TRUE if the
48  * operation succeeded (added, not zero), returns FALSE if number is zero. */
49 static inline bool atomic_add_not_zero(atomic_t *number, long val)
50 {
51         long old_num, new_num;
52         do {
53                 old_num = atomic_read(number);
54                 if (!old_num)
55                         return FALSE;
56                 new_num = old_num + val;
57         } while (!atomic_cas(number, old_num, new_num));
58         return TRUE;
59 }
60
61 /* Subtraces val from number, returning True if the new value is 0. */
62 static inline bool atomic_sub_and_test(atomic_t *number, long val)
63 {
64         return __sync_fetch_and_sub((long*)number, val) == val;
65 }
66
67 static inline void atomic_and(atomic_t *number, long mask)
68 {
69         __sync_fetch_and_and(number, mask);
70 }
71
72 static inline void atomic_or(atomic_t *number, long mask)
73 {
74         __sync_fetch_and_or(number, mask);
75 }
76
77 static inline long atomic_swap(atomic_t *addr, long val)
78 {
79         return (long)__sync_lock_test_and_set(addr, val); // yes, really
80 }
81
82 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
83 {
84         return __sync_lock_test_and_set(addr, val); // yes, really
85 }
86
87 // RISC-V has atomic word ops, not byte ops, so we must manipulate addresses
88 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
89 {
90         uintptr_t offset = (uintptr_t)number & 3;
91         uint32_t wmask = (1<<(8*offset+8)) - (1<<(8*offset));
92         wmask = ~wmask | ((uint32_t)mask << (8*offset));
93
94         __sync_fetch_and_and((uint32_t*)((uintptr_t)number & ~3), wmask);
95 }
96
97 static inline void atomic_orb(volatile uint8_t* number, uint8_t mask)
98 {
99         uintptr_t offset = (uintptr_t)number & 3;
100         uint32_t wmask = (uint32_t)mask << (8*offset);
101
102         __sync_fetch_and_or((uint32_t*)((uintptr_t)number & ~3), wmask);
103 }
104
105 static inline bool spin_locked(spinlock_t* lock)
106 {
107         return lock->rlock;
108 }
109
110 static inline uint32_t spin_trylock(spinlock_t* lock)
111 {
112         return __sync_fetch_and_or(&lock->rlock, 1);
113 }
114
115 static inline void spin_lock(spinlock_t *lock)
116 {
117         while(spin_trylock(lock))
118                 while(lock->rlock);
119         mb();
120 }
121
122 static inline void spin_unlock(spinlock_t *lock)
123 {
124         mb();
125         lock->rlock = 0;
126 }
127
128 static inline void spinlock_init(spinlock_t *lock)
129 {
130         lock->rlock = 0;
131 }
132
133 static inline void spinlock_debug(spinlock_t* lock)
134 {
135 }
136
137 #endif /* ROS_KERN_ARCH_ATOMIC_H */