1/*-
2 * Copyright (C) 2002 Benno Rice
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*/
25/*-
26 * Copyright (C) 1993 Wolfgang Solfrank.
27 * Copyright (C) 1993 TooLs GmbH.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in the
37 *    documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 *    must display the following acknowledgement:
40 *	This product includes software developed by TooLs GmbH.
41 * 4. The name of TooLs GmbH may not be used to endorse or promote products
42 *    derived from this software without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
49 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
52 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
53 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 */
55
56#include <sys/cdefs.h>
57__FBSDID("$FreeBSD$");
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/proc.h>
62
63#include <vm/vm.h>
64#include <vm/pmap.h>
65#include <vm/vm_map.h>
66
67#include <machine/pcb.h>
68#include <machine/vmparam.h>
69
70
71int	setfault(faultbuf);	/* defined in locore.S */
72
73static int
74is_uaddr(const void *addr)
75{
76	int rv = ((vm_offset_t)addr <= VM_MAXUSER_ADDRESS) ? 1 : 0;
77
78	return rv;
79}
80
81int
82copyout(const void *kaddr, void *udaddr, size_t len)
83{
84	struct		thread *td;
85	faultbuf	env;
86
87	if (!is_uaddr(udaddr))
88		return (EFAULT);
89
90	td = curthread;
91
92	if (setfault(env)) {
93		td->td_pcb->pcb_onfault = NULL;
94		return (EFAULT);
95	}
96
97	bcopy(kaddr, udaddr, len);
98
99	td->td_pcb->pcb_onfault = NULL;
100	return (0);
101}
102
103int
104copyin(const void *udaddr, void *kaddr, size_t len)
105{
106	struct		thread *td;
107	faultbuf	env;
108
109	if (!is_uaddr(udaddr) || is_uaddr(kaddr))
110		return (EFAULT);
111
112	td = curthread;
113
114	if (setfault(env)) {
115		td->td_pcb->pcb_onfault = NULL;
116		return (EFAULT);
117	}
118
119	bcopy(udaddr, kaddr, len);
120
121	td->td_pcb->pcb_onfault = NULL;
122	return (0);
123}
124
125int
126copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
127{
128	struct		thread *td;
129	faultbuf	env;
130	const char	*up;
131	char		*kp;
132	size_t		l;
133	int		rv, c;
134
135	if (!is_uaddr(udaddr) || is_uaddr(kaddr))
136		return (EFAULT);
137
138	td = curthread;
139
140	if (setfault(env)) {
141		td->td_pcb->pcb_onfault = NULL;
142		return (EFAULT);
143	}
144
145	kp = kaddr;
146	up = udaddr;
147
148	rv = ENAMETOOLONG;
149
150	for (l = 0; len-- > 0; l++) {
151
152		c = *up++;
153
154		if (!(*kp++ = c)) {
155			l++;
156			rv = 0;
157			break;
158		}
159	}
160
161	if (done != NULL) {
162		*done = l;
163	}
164
165	td->td_pcb->pcb_onfault = NULL;
166	return (rv);
167}
168
169int
170subyte(void *addr, int byte)
171{
172	struct		thread *td;
173	faultbuf	env;
174
175	if (!is_uaddr(addr))
176		return (EFAULT);
177
178	td = curthread;
179
180	if (setfault(env)) {
181		td->td_pcb->pcb_onfault = NULL;
182		return (EFAULT);
183	}
184
185	*(char *)addr = (char)byte;
186
187	td->td_pcb->pcb_onfault = NULL;
188	return (0);
189}
190
191int
192suword(void *addr, long word)
193{
194	struct		thread *td;
195	faultbuf	env;
196
197	if (!is_uaddr(addr))
198		return (EFAULT);
199
200	td = curthread;
201
202	if (setfault(env)) {
203		td->td_pcb->pcb_onfault = NULL;
204		return (EFAULT);
205	}
206
207	*(long *)addr = word;
208
209	td->td_pcb->pcb_onfault = NULL;
210	return (0);
211}
212
213int
214suword32(void *addr, int32_t word)
215{
216
217	return (suword(addr, (long)word));
218}
219
220
221int
222fubyte(const void *addr)
223{
224	struct		thread *td;
225	faultbuf	env;
226	int		val;
227
228	if (!is_uaddr(addr))
229		return (EFAULT);
230
231	td = curthread;
232
233	if (setfault(env)) {
234		td->td_pcb->pcb_onfault = NULL;
235		return (EFAULT);
236	}
237
238	val = *(const u_char *)addr;
239
240	td->td_pcb->pcb_onfault = NULL;
241	return (val);
242}
243
244long
245fuword(const void *addr)
246{
247	struct		thread *td;
248	faultbuf	env;
249	long		val;
250
251	if (!is_uaddr(addr))
252		return (EFAULT);
253
254	td = curthread;
255
256	if (setfault(env)) {
257		td->td_pcb->pcb_onfault = NULL;
258		return (EFAULT);
259	}
260
261	val = *(const long *)addr;
262
263	td->td_pcb->pcb_onfault = NULL;
264	return (val);
265}
266
267int32_t
268fuword32(const void *addr)
269{
270
271	return ((int32_t)fuword(addr));
272}
273
274uint32_t
275casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval)
276{
277
278	return (casuword((volatile u_long *)base, oldval, newval));
279}
280
281u_long
282casuword(volatile u_long *addr, u_long old, u_long new)
283{
284	struct thread *td;
285	faultbuf env;
286	u_long val;
287
288	if (!((vm_offset_t)addr <= VM_MAXUSER_ADDRESS))
289		return (EFAULT);
290
291	td = curthread;
292
293	if (setfault(env)) {
294		td->td_pcb->pcb_onfault = NULL;
295		return (EFAULT);
296	}
297
298	__asm __volatile (
299		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
300		"cmplw %3, %0\n\t"		/* compare */
301		"bne 2f\n\t"			/* exit if not equal */
302		"stwcx. %4, 0, %2\n\t"      	/* attempt to store */
303		"bne- 1b\n\t"			/* spin if failed */
304		"b 3f\n\t"			/* we've succeeded */
305		"2:\n\t"
306		"stwcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
307		"3:\n\t"
308		: "=&r" (val), "=m" (*addr)
309		: "r" (addr), "r" (old), "r" (new), "m" (*addr)
310		: "cc", "memory");
311
312	td->td_pcb->pcb_onfault = NULL;
313
314	return (val);
315}
316