xref: /haiku/src/system/kernel/arch/arm/arch_atomic64.cpp (revision f73f5d4c42a01ece688cbb57b5d332cc0f68b2c6)
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 int64
34 atomic_set64(vint64 *value, int64 newValue)
35 {
36 	SpinLocker locker(&atomic_lock);
37 
38 	int64 oldValue = *value;
39 	*value = newValue;
40 	return oldValue;
41 }
42 
43 
44 int64
45 atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst)
46 {
47 	SpinLocker locker(&atomic_lock);
48 
49 	int64 oldValue = *value;
50 	if (oldValue == testAgainst)
51 		*value = newValue;
52 	return oldValue;
53 }
54 
55 
56 int64
57 atomic_add64(vint64 *value, int64 addValue)
58 {
59 	SpinLocker locker(&atomic_lock);
60 
61 	int64 oldValue = *value;
62 	*value += addValue;
63 	return oldValue;
64 }
65 
66 
67 int64
68 atomic_and64(vint64 *value, int64 andValue)
69 {
70 	SpinLocker locker(&atomic_lock);
71 
72 	int64 oldValue = *value;
73 	*value &= andValue;
74 	return oldValue;
75 }
76 
77 
78 int64
79 atomic_or64(vint64 *value, int64 orValue)
80 {
81 	SpinLocker locker(&atomic_lock);
82 
83 	int64 oldValue = *value;
84 	*value |= orValue;
85 	return oldValue;
86 }
87 
88 
89 int64
90 atomic_get64(vint64 *value)
91 {
92 	SpinLocker locker(&atomic_lock);
93 	return *value;
94 }
95 
96 
97 int64
98 _user_atomic_set64(vint64 *value, int64 newValue)
99 {
100 	if (IS_USER_ADDRESS(value)
101 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
102 		int64 oldValue = atomic_set64(value, newValue);
103 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
104 		return oldValue;
105 	}
106 
107 access_violation:
108 	// XXX kill application
109 	return -1;
110 }
111 
112 
113 int64
114 _user_atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst)
115 {
116 	if (IS_USER_ADDRESS(value)
117 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
118 		int64 oldValue = atomic_test_and_set64(value, newValue, testAgainst);
119 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
120 		return oldValue;
121 	}
122 
123 access_violation:
124 	// XXX kill application
125 	return -1;
126 }
127 
128 
129 int64
130 _user_atomic_add64(vint64 *value, int64 addValue)
131 {
132 	if (IS_USER_ADDRESS(value)
133 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
134 		int64 oldValue = atomic_add64(value, addValue);
135 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
136 		return oldValue;
137 	}
138 
139 access_violation:
140 	// XXX kill application
141 	return -1;
142 }
143 
144 
145 int64
146 _user_atomic_and64(vint64 *value, int64 andValue)
147 {
148 	if (IS_USER_ADDRESS(value)
149 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
150 		int64 oldValue = atomic_and64(value, andValue);
151 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
152 		return oldValue;
153 	}
154 
155 access_violation:
156 	// XXX kill application
157 	return -1;
158 }
159 
160 
161 int64
162 _user_atomic_or64(vint64 *value, int64 orValue)
163 {
164 	if (IS_USER_ADDRESS(value)
165 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
166 		int64 oldValue = atomic_or64(value, orValue);
167 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
168 		return oldValue;
169 	}
170 
171 access_violation:
172 	// XXX kill application
173 	return -1;
174 }
175 
176 
177 int64
178 _user_atomic_get64(vint64 *value)
179 {
180 	if (IS_USER_ADDRESS(value)
181 		&& lock_memory((void *)value, sizeof(int64), B_READ_DEVICE) == B_OK) {
182 		int64 oldValue = atomic_get64(value);
183 		unlock_memory((void *)value, sizeof(int64), B_READ_DEVICE);
184 		return oldValue;
185 	}
186 
187 access_violation:
188 	// XXX kill application
189 	return -1;
190 }
191 
192 #endif /* ATOMIC64_FUNCS_ARE_SYSCALLS */
193