1 /*
2 * Copyright 2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Ithamar R. Adema, ithamar@upgrade-android.com
7 */
8
9 #include <KernelExport.h>
10
11 #include <kernel.h>
12 #include <user_atomic.h>
13
14 #include <util/AutoLock.h>
15
16 #ifdef ATOMIC64_FUNCS_ARE_SYSCALLS
17
18 /*
19 * NOTE: Unlike their 32-bit counterparts, these functions can use
20 * spinlocks safely currently, as no atomic 64-bit operations are
21 * done in the spinlock code. If this ever changes, this code will
22 * have to change.
23 *
24 * This code is here for ARMv6, which cannot do proper 64-bit atomic
25 * operations. Anything newer is capable, and does therefore not
26 * depend on this code.
27 */
28
29
30 static spinlock atomic_lock = B_SPINLOCK_INITIALIZER;
31
32
33 void
atomic_set64(int64 * value,int64 newValue)34 atomic_set64(int64 *value, int64 newValue)
35 {
36 SpinLocker locker(&atomic_lock);
37
38 *value = newValue;
39 }
40
41
42 int64
atomic_get_and_set64(int64 * value,int64 newValue)43 atomic_get_and_set64(int64 *value, int64 newValue)
44 {
45 SpinLocker locker(&atomic_lock);
46
47 int64 oldValue = *value;
48 *value = newValue;
49 return oldValue;
50 }
51
52
53 int64
atomic_test_and_set64(int64 * value,int64 newValue,int64 testAgainst)54 atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst)
55 {
56 SpinLocker locker(&atomic_lock);
57
58 int64 oldValue = *value;
59 if (oldValue == testAgainst)
60 *value = newValue;
61 return oldValue;
62 }
63
64
65 int64
atomic_add64(int64 * value,int64 addValue)66 atomic_add64(int64 *value, int64 addValue)
67 {
68 SpinLocker locker(&atomic_lock);
69
70 int64 oldValue = *value;
71 *value += addValue;
72 return oldValue;
73 }
74
75
76 int64
atomic_and64(int64 * value,int64 andValue)77 atomic_and64(int64 *value, int64 andValue)
78 {
79 SpinLocker locker(&atomic_lock);
80
81 int64 oldValue = *value;
82 *value &= andValue;
83 return oldValue;
84 }
85
86
87 int64
atomic_or64(int64 * value,int64 orValue)88 atomic_or64(int64 *value, int64 orValue)
89 {
90 SpinLocker locker(&atomic_lock);
91
92 int64 oldValue = *value;
93 *value |= orValue;
94 return oldValue;
95 }
96
97
98 int64
atomic_get64(int64 * value)99 atomic_get64(int64 *value)
100 {
101 SpinLocker locker(&atomic_lock);
102 return *value;
103 }
104
105
106 int64
_user_atomic_get_and_set64(int64 * value,int64 newValue)107 _user_atomic_get_and_set64(int64 *value, int64 newValue)
108 {
109 if (IS_USER_ADDRESS(value)
110 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
111 int64 oldValue = atomic_get_and_set64(value, newValue);
112 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
113 return oldValue;
114 }
115
116 access_violation:
117 // XXX kill application
118 return -1;
119 }
120
121
122 void
_user_atomic_set64(int64 * value,int64 newValue)123 _user_atomic_set64(int64 *value, int64 newValue)
124 {
125 if (IS_USER_ADDRESS(value)
126 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
127 atomic_set64(value, newValue);
128 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
129 return;
130 }
131
132 access_violation:
133 // XXX kill application
134 return;
135 }
136
137
138 int64
_user_atomic_test_and_set64(int64 * value,int64 newValue,int64 testAgainst)139 _user_atomic_test_and_set64(int64 *value, int64 newValue, int64 testAgainst)
140 {
141 if (IS_USER_ADDRESS(value)
142 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
143 int64 oldValue = atomic_test_and_set64(value, newValue, testAgainst);
144 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
145 return oldValue;
146 }
147
148 access_violation:
149 // XXX kill application
150 return -1;
151 }
152
153
154 int64
_user_atomic_add64(int64 * value,int64 addValue)155 _user_atomic_add64(int64 *value, int64 addValue)
156 {
157 if (IS_USER_ADDRESS(value)
158 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
159 int64 oldValue = atomic_add64(value, addValue);
160 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
161 return oldValue;
162 }
163
164 access_violation:
165 // XXX kill application
166 return -1;
167 }
168
169
170 int64
_user_atomic_and64(int64 * value,int64 andValue)171 _user_atomic_and64(int64 *value, int64 andValue)
172 {
173 if (IS_USER_ADDRESS(value)
174 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
175 int64 oldValue = atomic_and64(value, andValue);
176 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
177 return oldValue;
178 }
179
180 access_violation:
181 // XXX kill application
182 return -1;
183 }
184
185
186 int64
_user_atomic_or64(int64 * value,int64 orValue)187 _user_atomic_or64(int64 *value, int64 orValue)
188 {
189 if (IS_USER_ADDRESS(value)
190 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
191 int64 oldValue = atomic_or64(value, orValue);
192 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
193 return oldValue;
194 }
195
196 access_violation:
197 // XXX kill application
198 return -1;
199 }
200
201
202 int64
_user_atomic_get64(int64 * value)203 _user_atomic_get64(int64 *value)
204 {
205 if (IS_USER_ADDRESS(value)
206 && lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
207 int64 oldValue = atomic_get64(value);
208 unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
209 return oldValue;
210 }
211
212 access_violation:
213 // XXX kill application
214 return -1;
215 }
216
217 #endif /* ATOMIC64_FUNCS_ARE_SYSCALLS */
218