copyinout.c revision 125687
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: head/sys/powerpc/aim/copyinout.c 125687 2004-02-11 07:27:34Z grehan $");
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/sr.h>
69
70int	setfault(faultbuf);	/* defined in locore.S */
71
72/*
73 * Makes sure that the right segment of userspace is mapped in.
74 */
75static __inline void
76set_user_sr(register_t vsid)
77{
78
79	isync();
80	__asm __volatile ("mtsr %0,%1" :: "n"(USER_SR), "r"(vsid));
81	isync();
82}
83
84int
85copyout(const void *kaddr, void *udaddr, size_t len)
86{
87	struct		thread *td;
88	pmap_t		pm;
89	faultbuf	env;
90	const char	*kp;
91	char		*up, *p;
92	size_t		l;
93
94	td = PCPU_GET(curthread);
95	pm = &td->td_proc->p_vmspace->vm_pmap;
96
97	if (setfault(env)) {
98		td->td_pcb->pcb_onfault = NULL;
99		return (EFAULT);
100	}
101
102	kp = kaddr;
103	up = udaddr;
104
105	while (len > 0) {
106		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
107
108		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
109		if (l > len)
110			l = len;
111
112		set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
113
114		bcopy(kp, p, l);
115
116		up += l;
117		kp += l;
118		len -= l;
119	}
120
121	td->td_pcb->pcb_onfault = NULL;
122	return (0);
123}
124
125int
126copyin(const void *udaddr, void *kaddr, size_t len)
127{
128	struct		thread *td;
129	pmap_t		pm;
130	faultbuf	env;
131	const char	*up;
132	char		*kp, *p;
133	size_t		l;
134
135	td = PCPU_GET(curthread);
136	pm = &td->td_proc->p_vmspace->vm_pmap;
137
138	if (setfault(env)) {
139		td->td_pcb->pcb_onfault = NULL;
140		return (EFAULT);
141	}
142
143	kp = kaddr;
144	up = udaddr;
145
146	while (len > 0) {
147		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
148
149		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
150		if (l > len)
151			l = len;
152
153		set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
154
155		bcopy(p, kp, l);
156
157		up += l;
158		kp += l;
159		len -= l;
160	}
161
162	td->td_pcb->pcb_onfault = NULL;
163	return (0);
164}
165
166int
167copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
168{
169	struct		thread *td;
170	pmap_t		pm;
171	faultbuf	env;
172	const char	*up;
173	char		*kp;
174	size_t		l;
175	int		rv, c;
176
177	td = PCPU_GET(curthread);
178	pm = &td->td_proc->p_vmspace->vm_pmap;
179
180	if (setfault(env)) {
181		td->td_pcb->pcb_onfault = NULL;
182		return (EFAULT);
183	}
184
185	kp = kaddr;
186	up = udaddr;
187
188	rv = ENAMETOOLONG;
189
190	for (l = 0; len-- > 0; l++) {
191		if ((c = fubyte(up++)) < 0) {
192			rv = EFAULT;
193			break;
194		}
195
196		if (!(*kp++ = c)) {
197			l++;
198			rv = 0;
199			break;
200		}
201	}
202
203	if (done != NULL) {
204		*done = l;
205	}
206
207	td->td_pcb->pcb_onfault = NULL;
208	return (rv);
209}
210
211int
212subyte(void *addr, int byte)
213{
214	struct		thread *td;
215	pmap_t		pm;
216	faultbuf	env;
217	char		*p;
218
219	td = PCPU_GET(curthread);
220	pm = &td->td_proc->p_vmspace->vm_pmap;
221	p = (char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
222
223	if (setfault(env)) {
224		td->td_pcb->pcb_onfault = NULL;
225		return (-1);
226	}
227
228	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
229
230	*p = (char)byte;
231
232	td->td_pcb->pcb_onfault = NULL;
233	return (0);
234}
235
236int
237suword(void *addr, long word)
238{
239	struct		thread *td;
240	pmap_t		pm;
241	faultbuf	env;
242	long		*p;
243
244	td = PCPU_GET(curthread);
245	pm = &td->td_proc->p_vmspace->vm_pmap;
246	p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
247
248	if (setfault(env)) {
249		td->td_pcb->pcb_onfault = NULL;
250		return (-1);
251	}
252
253	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
254
255	*p = word;
256
257	td->td_pcb->pcb_onfault = NULL;
258	return (0);
259}
260
261int
262suword32(void *addr, int32_t word)
263{
264	return (suword(addr, (long)word));
265}
266
267
268int
269fubyte(const void *addr)
270{
271	struct		thread *td;
272	pmap_t		pm;
273	faultbuf	env;
274	u_char		*p;
275	int		val;
276
277	td = PCPU_GET(curthread);
278	pm = &td->td_proc->p_vmspace->vm_pmap;
279	p = (u_char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
280
281	if (setfault(env)) {
282		td->td_pcb->pcb_onfault = NULL;
283		return (-1);
284	}
285
286	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
287
288	val = *p;
289
290	td->td_pcb->pcb_onfault = NULL;
291	return (val);
292}
293
294long
295fuword(const void *addr)
296{
297	struct		thread *td;
298	pmap_t		pm;
299	faultbuf	env;
300	long		*p, val;
301
302	td = PCPU_GET(curthread);
303	pm = &td->td_proc->p_vmspace->vm_pmap;
304	p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
305
306	if (setfault(env)) {
307		td->td_pcb->pcb_onfault = NULL;
308		return (-1);
309	}
310
311	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
312
313	val = *p;
314
315	td->td_pcb->pcb_onfault = NULL;
316	return (val);
317}
318
319int32_t
320fuword32(const void *addr)
321{
322	return ((int32_t)fuword(addr));
323}
324