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
30static spinlock atomic_lock = B_SPINLOCK_INITIALIZER;
31
32
33void
34atomic_set64(int64 *value, int64 newValue)
35{
36	SpinLocker locker(&atomic_lock);
37
38	*value = newValue;
39}
40
41
42int64
43atomic_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
53int64
54atomic_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
65int64
66atomic_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
76int64
77atomic_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
87int64
88atomic_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
98int64
99atomic_get64(int64 *value)
100{
101	SpinLocker locker(&atomic_lock);
102	return *value;
103}
104
105
106int64
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
116access_violation:
117	// XXX kill application
118	return -1;
119}
120
121
122void
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
132access_violation:
133	// XXX kill application
134	return;
135}
136
137
138int64
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
148access_violation:
149	// XXX kill application
150	return -1;
151}
152
153
154int64
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
164access_violation:
165	// XXX kill application
166	return -1;
167}
168
169
170int64
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
180access_violation:
181	// XXX kill application
182	return -1;
183}
184
185
186int64
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
196access_violation:
197	// XXX kill application
198	return -1;
199}
200
201
202int64
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
212access_violation:
213	// XXX kill application
214	return -1;
215}
216
217#endif /* ATOMIC64_FUNCS_ARE_SYSCALLS */
218