xref: /haiku/src/system/kernel/arch/arm/arch_atomic64.cpp (revision 18027fff34af4a666c1e62254b462cbaeae1859e)
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
34 atomic_set64(int64 *value, int64 newValue)
35 {
36 	SpinLocker locker(&atomic_lock);
37 
38 	*value = newValue;
39 }
40 
41 
42 int64
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
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
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
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
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
99 atomic_get64(int64 *value)
100 {
101 	SpinLocker locker(&atomic_lock);
102 	return *value;
103 }
104 
105 
106 int64
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
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
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
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
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
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
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