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 ATOMIC_FUNCS_ARE_SYSCALLS
17
18/*
19 * NOTE: These functions are _intentionally_ not using spinlocks, unlike
20 * the 64 bit versions. The reason for this is that they are used by the
21 * spinlock code itself, and therefore would deadlock.
22 *
23 * Since these are only really needed for ARMv5, which is not SMP anyway,
24 * this is an acceptable compromise.
25 */
26
27void
28atomic_set(int32 *value, int32 newValue)
29{
30	InterruptsLocker locker;
31	*value = newValue;
32}
33
34int32
35atomic_get_and_set(int32 *value, int32 newValue)
36{
37	InterruptsLocker locker;
38	int32 oldValue = *value;
39	atomic_set(value, newValue);
40	return oldValue;
41}
42
43int32
44atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst)
45{
46	InterruptsLocker locker;
47
48	int32 oldValue = *value;
49	if (oldValue == testAgainst)
50		*value = newValue;
51	return oldValue;
52}
53
54int32
55atomic_add(int32 *value, int32 addValue)
56{
57	InterruptsLocker locker;
58
59	int32 oldValue = *value;
60	*value += addValue;
61	return oldValue;
62}
63
64int32
65atomic_and(int32 *value, int32 andValue)
66{
67	InterruptsLocker locker;
68
69	int32 oldValue = *value;
70	*value &= andValue;
71	return oldValue;
72}
73
74int32
75atomic_or(int32 *value, int32 orValue)
76{
77	InterruptsLocker locker;
78
79	int32 oldValue = *value;
80	*value |= orValue;
81	return oldValue;
82}
83
84int32
85atomic_get(int32 *value)
86{
87	InterruptsLocker locker;
88
89	int32 oldValue = *value;
90	return oldValue;
91}
92
93void
94_user_atomic_set(int32 *value, int32 newValue)
95{
96	if (IS_USER_ADDRESS(value)
97		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
98		atomic_set(value, newValue);
99		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
100		return;
101	}
102
103access_violation:
104	// XXX kill application
105	return;
106}
107
108int32
109_user_atomic_get_and_set(int32 *value, int32 newValue)
110{
111	if (IS_USER_ADDRESS(value)
112		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
113		int32 oldValue = atomic_get_and_set(value, newValue);
114		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
115		return oldValue;
116	}
117
118access_violation:
119	// XXX kill application
120	return -1;
121}
122
123int32
124_user_atomic_test_and_set(int32 *value, int32 newValue, int32 testAgainst)
125{
126	if (IS_USER_ADDRESS(value)
127		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
128		int32 oldValue = atomic_test_and_set((int32*)value, newValue, testAgainst);
129		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
130		return oldValue;
131	}
132
133access_violation:
134	// XXX kill application
135	return -1;
136}
137
138int32
139_user_atomic_add(int32 *value, int32 addValue)
140{
141	if (IS_USER_ADDRESS(value)
142		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
143		int32 oldValue = atomic_add(value, addValue);
144		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
145		return oldValue;
146	}
147
148access_violation:
149	// XXX kill application
150	return -1;
151}
152
153int32
154_user_atomic_and(int32 *value, int32 andValue)
155{
156	if (IS_USER_ADDRESS(value)
157		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
158		int32 oldValue = atomic_and(value, andValue);
159		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
160		return oldValue;
161	}
162
163access_violation:
164	// XXX kill application
165	return -1;
166}
167
168int32
169_user_atomic_or(int32 *value, int32 orValue)
170{
171	if (IS_USER_ADDRESS(value)
172		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
173		int32 oldValue = atomic_or(value, orValue);
174		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
175		return oldValue;
176	}
177
178access_violation:
179	// XXX kill application
180	return -1;
181}
182
183int32
184_user_atomic_get(int32 *value)
185{
186	if (IS_USER_ADDRESS(value)
187		&& lock_memory((void *)value, sizeof(int32), B_READ_DEVICE) == B_OK) {
188		int32 oldValue = atomic_get(value);
189		unlock_memory((void *)value, sizeof(int32), B_READ_DEVICE);
190		return oldValue;
191	}
192
193access_violation:
194	// XXX kill application
195	return -1;
196}
197
198#endif /* ATOMIC_FUNCS_ARE_SYSCALLS */
199