1139825Simp/*-
292916Sbenno * Copyright (C) 2002 Benno Rice
392916Sbenno * All rights reserved.
492916Sbenno *
592916Sbenno * Redistribution and use in source and binary forms, with or without
692916Sbenno * modification, are permitted provided that the following conditions
792916Sbenno * are met:
892916Sbenno * 1. Redistributions of source code must retain the above copyright
992916Sbenno *    notice, this list of conditions and the following disclaimer.
1092916Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1192916Sbenno *    notice, this list of conditions and the following disclaimer in the
1292916Sbenno *    documentation and/or other materials provided with the distribution.
1392916Sbenno *
1492916Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
1592916Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1692916Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1792916Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1892916Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1992916Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2092916Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2192916Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2292916Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2392916Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2492916Sbenno*/
2592916Sbenno/*-
2692916Sbenno * Copyright (C) 1993 Wolfgang Solfrank.
2792916Sbenno * Copyright (C) 1993 TooLs GmbH.
2892916Sbenno * All rights reserved.
2992916Sbenno *
3092916Sbenno * Redistribution and use in source and binary forms, with or without
3192916Sbenno * modification, are permitted provided that the following conditions
3292916Sbenno * are met:
3392916Sbenno * 1. Redistributions of source code must retain the above copyright
3492916Sbenno *    notice, this list of conditions and the following disclaimer.
3592916Sbenno * 2. Redistributions in binary form must reproduce the above copyright
3692916Sbenno *    notice, this list of conditions and the following disclaimer in the
3792916Sbenno *    documentation and/or other materials provided with the distribution.
3892916Sbenno * 3. All advertising materials mentioning features or use of this software
3992916Sbenno *    must display the following acknowledgement:
4092916Sbenno *	This product includes software developed by TooLs GmbH.
4192916Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products
4292916Sbenno *    derived from this software without specific prior written permission.
4392916Sbenno *
4492916Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
4592916Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4692916Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4792916Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4892916Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4992916Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
5092916Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5192916Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
5292916Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
5392916Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5492916Sbenno */
5592916Sbenno
56113038Sobrien#include <sys/cdefs.h>
57113038Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/powerpc/powerpc/copyinout.c 293636 2016-01-10 16:42:14Z nwhitehorn $");
5892916Sbenno
5992916Sbenno#include <sys/param.h>
60209975Snwhitehorn#include <sys/lock.h>
61209975Snwhitehorn#include <sys/mutex.h>
6292916Sbenno#include <sys/systm.h>
6392916Sbenno#include <sys/proc.h>
6492916Sbenno
6592916Sbenno#include <vm/vm.h>
6692916Sbenno#include <vm/pmap.h>
6792916Sbenno#include <vm/vm_map.h>
6892916Sbenno
69125687Sgrehan#include <machine/pcb.h>
70125687Sgrehan#include <machine/sr.h>
71209975Snwhitehorn#include <machine/slb.h>
72258024Snwhitehorn#include <machine/vmparam.h>
73125687Sgrehan
74258024Snwhitehorn#ifdef AIM
7592916Sbenno/*
7692916Sbenno * Makes sure that the right segment of userspace is mapped in.
7792916Sbenno */
78209975Snwhitehorn
79209975Snwhitehorn#ifdef __powerpc64__
8092916Sbennostatic __inline void
81273911Skibset_user_sr(pmap_t pm, volatile const void *addr)
8292916Sbenno{
83212715Snwhitehorn	struct slb *slb;
84214574Snwhitehorn	register_t slbv;
8592916Sbenno
86212715Snwhitehorn	/* Try lockless look-up first */
87212715Snwhitehorn	slb = user_va_to_slb_entry(pm, (vm_offset_t)addr);
88212715Snwhitehorn
89212715Snwhitehorn	if (slb == NULL) {
90212715Snwhitehorn		/* If it isn't there, we need to pre-fault the VSID */
91212715Snwhitehorn		PMAP_LOCK(pm);
92214574Snwhitehorn		slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT;
93212715Snwhitehorn		PMAP_UNLOCK(pm);
94212715Snwhitehorn	} else {
95214574Snwhitehorn		slbv = slb->slbv;
96212715Snwhitehorn	}
97212715Snwhitehorn
98214610Snwhitehorn	/* Mark segment no-execute */
99214610Snwhitehorn	slbv |= SLBV_N;
100214610Snwhitehorn
101214574Snwhitehorn	/* If we have already set this VSID, we can just return */
102214574Snwhitehorn	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv)
103214574Snwhitehorn		return;
104209975Snwhitehorn
105214739Snwhitehorn	__asm __volatile("isync");
106212715Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_segm =
107212715Snwhitehorn	    (uintptr_t)addr >> ADDR_SR_SHFT;
108214574Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
109214739Snwhitehorn	__asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
110214739Snwhitehorn	    "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
111209975Snwhitehorn}
112209975Snwhitehorn#else
113209975Snwhitehornstatic __inline void
114273911Skibset_user_sr(pmap_t pm, volatile const void *addr)
115209975Snwhitehorn{
116209975Snwhitehorn	register_t vsid;
117209975Snwhitehorn
118209975Snwhitehorn	vsid = va_to_vsid(pm, (vm_offset_t)addr);
119209975Snwhitehorn
120214749Snwhitehorn	/* Mark segment no-execute */
121214749Snwhitehorn	vsid |= SR_N;
122214749Snwhitehorn
123214574Snwhitehorn	/* If we have already set this VSID, we can just return */
124214574Snwhitehorn	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
125214574Snwhitehorn		return;
126214574Snwhitehorn
127214607Snwhitehorn	__asm __volatile("isync");
128214739Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_segm =
129214739Snwhitehorn	    (uintptr_t)addr >> ADDR_SR_SHFT;
130214574Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
131214607Snwhitehorn	__asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
13292916Sbenno}
133209975Snwhitehorn#endif
13492916Sbenno
135258024Snwhitehornstatic __inline int
136273911Skibmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
137258024Snwhitehorn    size_t *klen)
138258024Snwhitehorn{
139258024Snwhitehorn	size_t l;
140258024Snwhitehorn
141258024Snwhitehorn	*kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
142258024Snwhitehorn
143258024Snwhitehorn	l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
144258024Snwhitehorn	if (l > ulen)
145258024Snwhitehorn		l = ulen;
146258024Snwhitehorn	if (klen)
147258024Snwhitehorn		*klen = l;
148258024Snwhitehorn	else if (l != ulen)
149258024Snwhitehorn		return (EFAULT);
150258024Snwhitehorn
151258024Snwhitehorn	set_user_sr(pm, uaddr);
152258024Snwhitehorn
153258024Snwhitehorn	return (0);
154258024Snwhitehorn}
155258024Snwhitehorn#else /* Book-E uses a combined kernel/user mapping */
156258024Snwhitehornstatic __inline int
157273911Skibmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
158258024Snwhitehorn    size_t *klen)
159258024Snwhitehorn{
160258024Snwhitehorn
161258024Snwhitehorn	if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE)
162258024Snwhitehorn		return (EFAULT);
163258024Snwhitehorn
164258024Snwhitehorn	*kaddr = (void *)(uintptr_t)uaddr;
165258024Snwhitehorn	if (klen)
166258024Snwhitehorn		*klen = ulen;
167258024Snwhitehorn
168258024Snwhitehorn	return (0);
169258024Snwhitehorn}
170258024Snwhitehorn#endif
171258024Snwhitehorn
17292916Sbennoint
17392916Sbennocopyout(const void *kaddr, void *udaddr, size_t len)
17492916Sbenno{
17592916Sbenno	struct		thread *td;
17692916Sbenno	pmap_t		pm;
177293636Snwhitehorn	jmp_buf		env;
17892916Sbenno	const char	*kp;
17992916Sbenno	char		*up, *p;
18092916Sbenno	size_t		l;
18192916Sbenno
182223485Snwhitehorn	td = curthread;
18392916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
18492916Sbenno
185293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
186293636Snwhitehorn	if (setjmp(env)) {
18795714Sbenno		td->td_pcb->pcb_onfault = NULL;
18895714Sbenno		return (EFAULT);
18995714Sbenno	}
19095714Sbenno
19192916Sbenno	kp = kaddr;
19292916Sbenno	up = udaddr;
19392916Sbenno
19492916Sbenno	while (len > 0) {
195258024Snwhitehorn		if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
196258024Snwhitehorn			td->td_pcb->pcb_onfault = NULL;
197258027Snwhitehorn			return (EFAULT);
198258024Snwhitehorn		}
19992916Sbenno
20092916Sbenno		bcopy(kp, p, l);
20192916Sbenno
20292916Sbenno		up += l;
20392916Sbenno		kp += l;
20492916Sbenno		len -= l;
20592916Sbenno	}
20692916Sbenno
20795714Sbenno	td->td_pcb->pcb_onfault = NULL;
20892916Sbenno	return (0);
20992916Sbenno}
21092916Sbenno
21192916Sbennoint
21292916Sbennocopyin(const void *udaddr, void *kaddr, size_t len)
21392916Sbenno{
21492916Sbenno	struct		thread *td;
21592916Sbenno	pmap_t		pm;
216293636Snwhitehorn	jmp_buf		env;
21792916Sbenno	const char	*up;
21892916Sbenno	char		*kp, *p;
21992916Sbenno	size_t		l;
22092916Sbenno
221223485Snwhitehorn	td = curthread;
22292916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
22392916Sbenno
224293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
225293636Snwhitehorn	if (setjmp(env)) {
22695714Sbenno		td->td_pcb->pcb_onfault = NULL;
22795714Sbenno		return (EFAULT);
22895714Sbenno	}
22995714Sbenno
23092916Sbenno	kp = kaddr;
23192916Sbenno	up = udaddr;
23292916Sbenno
23392916Sbenno	while (len > 0) {
234258024Snwhitehorn		if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
235258024Snwhitehorn			td->td_pcb->pcb_onfault = NULL;
236258027Snwhitehorn			return (EFAULT);
237258024Snwhitehorn		}
23892916Sbenno
23992916Sbenno		bcopy(p, kp, l);
24092916Sbenno
24192916Sbenno		up += l;
24292916Sbenno		kp += l;
24392916Sbenno		len -= l;
24492916Sbenno	}
24592916Sbenno
24695714Sbenno	td->td_pcb->pcb_onfault = NULL;
24792916Sbenno	return (0);
24892916Sbenno}
24992916Sbenno
25092916Sbennoint
25192916Sbennocopyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
25292916Sbenno{
25392916Sbenno	const char	*up;
25492916Sbenno	char		*kp;
25592916Sbenno	size_t		l;
25692916Sbenno	int		rv, c;
25792916Sbenno
25892916Sbenno	kp = kaddr;
25992916Sbenno	up = udaddr;
26092916Sbenno
26192916Sbenno	rv = ENAMETOOLONG;
26292916Sbenno
26392916Sbenno	for (l = 0; len-- > 0; l++) {
26492916Sbenno		if ((c = fubyte(up++)) < 0) {
26592916Sbenno			rv = EFAULT;
26692916Sbenno			break;
26792916Sbenno		}
26892916Sbenno
26992916Sbenno		if (!(*kp++ = c)) {
27092916Sbenno			l++;
27192916Sbenno			rv = 0;
27292916Sbenno			break;
27392916Sbenno		}
27492916Sbenno	}
27592916Sbenno
27692916Sbenno	if (done != NULL) {
27792916Sbenno		*done = l;
27892916Sbenno	}
27992916Sbenno
28092916Sbenno	return (rv);
28192916Sbenno}
28292916Sbenno
28392916Sbennoint
284273911Skibsubyte(volatile void *addr, int byte)
28592916Sbenno{
28695714Sbenno	struct		thread *td;
28795714Sbenno	pmap_t		pm;
288293636Snwhitehorn	jmp_buf		env;
28995714Sbenno	char		*p;
29092916Sbenno
291223485Snwhitehorn	td = curthread;
29292916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
29392916Sbenno
294293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
295293636Snwhitehorn	if (setjmp(env)) {
29695714Sbenno		td->td_pcb->pcb_onfault = NULL;
297108942Sgrehan		return (-1);
29895714Sbenno	}
29995714Sbenno
300258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
301258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
302258024Snwhitehorn		return (-1);
303258024Snwhitehorn	}
30492916Sbenno
30592916Sbenno	*p = (char)byte;
30692916Sbenno
30795714Sbenno	td->td_pcb->pcb_onfault = NULL;
30892916Sbenno	return (0);
30992916Sbenno}
31092916Sbenno
311209975Snwhitehorn#ifdef __powerpc64__
31292916Sbennoint
313273911Skibsuword32(volatile void *addr, int word)
314209975Snwhitehorn{
315209975Snwhitehorn	struct		thread *td;
316209975Snwhitehorn	pmap_t		pm;
317293636Snwhitehorn	jmp_buf		env;
318209975Snwhitehorn	int		*p;
319209975Snwhitehorn
320223485Snwhitehorn	td = curthread;
321209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
322209975Snwhitehorn
323293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
324293636Snwhitehorn	if (setjmp(env)) {
325209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
326209975Snwhitehorn		return (-1);
327209975Snwhitehorn	}
328209975Snwhitehorn
329258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
330258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
331258024Snwhitehorn		return (-1);
332258024Snwhitehorn	}
333209975Snwhitehorn
334209975Snwhitehorn	*p = word;
335209975Snwhitehorn
336209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
337209975Snwhitehorn	return (0);
338209975Snwhitehorn}
339209975Snwhitehorn#endif
340209975Snwhitehorn
341209975Snwhitehornint
342273911Skibsuword(volatile void *addr, long word)
34392916Sbenno{
34495714Sbenno	struct		thread *td;
34595714Sbenno	pmap_t		pm;
346293636Snwhitehorn	jmp_buf		env;
34795714Sbenno	long		*p;
34892916Sbenno
349223485Snwhitehorn	td = curthread;
35092916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
35192916Sbenno
352293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
353293636Snwhitehorn	if (setjmp(env)) {
35495714Sbenno		td->td_pcb->pcb_onfault = NULL;
355108942Sgrehan		return (-1);
35695714Sbenno	}
35795714Sbenno
358258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
359258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
360258024Snwhitehorn		return (-1);
361258024Snwhitehorn	}
36292916Sbenno
36392916Sbenno	*p = word;
36492916Sbenno
36595714Sbenno	td->td_pcb->pcb_onfault = NULL;
36692916Sbenno	return (0);
36792916Sbenno}
36892916Sbenno
369209975Snwhitehorn#ifdef __powerpc64__
37092916Sbennoint
371273911Skibsuword64(volatile void *addr, int64_t word)
372209975Snwhitehorn{
373209975Snwhitehorn	return (suword(addr, (long)word));
374209975Snwhitehorn}
375209975Snwhitehorn#else
376209975Snwhitehornint
377273911Skibsuword32(volatile void *addr, int32_t word)
37897307Sdfr{
37997342Sbenno	return (suword(addr, (long)word));
38097307Sdfr}
381209975Snwhitehorn#endif
38297307Sdfr
38397307Sdfrint
384273911Skibfubyte(volatile const void *addr)
38592916Sbenno{
38695714Sbenno	struct		thread *td;
38795714Sbenno	pmap_t		pm;
388293636Snwhitehorn	jmp_buf		env;
389108942Sgrehan	u_char		*p;
39095714Sbenno	int		val;
39192916Sbenno
392223485Snwhitehorn	td = curthread;
39392916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
39492916Sbenno
395293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
396293636Snwhitehorn	if (setjmp(env)) {
39795714Sbenno		td->td_pcb->pcb_onfault = NULL;
398108942Sgrehan		return (-1);
39995714Sbenno	}
40095714Sbenno
401258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
402258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
403258024Snwhitehorn		return (-1);
404258024Snwhitehorn	}
40592916Sbenno
406108942Sgrehan	val = *p;
40795714Sbenno
40895714Sbenno	td->td_pcb->pcb_onfault = NULL;
40995714Sbenno	return (val);
41092916Sbenno}
41192916Sbenno
412273783Skibint
413273911Skibfuword16(volatile const void *addr)
414209975Snwhitehorn{
415209975Snwhitehorn	struct		thread *td;
416209975Snwhitehorn	pmap_t		pm;
417293636Snwhitehorn	jmp_buf		env;
418273783Skib	uint16_t	*p, val;
419209975Snwhitehorn
420223485Snwhitehorn	td = curthread;
421209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
422209975Snwhitehorn
423293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
424293636Snwhitehorn	if (setjmp(env)) {
425209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
426209975Snwhitehorn		return (-1);
427209975Snwhitehorn	}
428209975Snwhitehorn
429258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
430258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
431258024Snwhitehorn		return (-1);
432258024Snwhitehorn	}
433209975Snwhitehorn
434209975Snwhitehorn	val = *p;
435209975Snwhitehorn
436209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
437209975Snwhitehorn	return (val);
438209975Snwhitehorn}
439209975Snwhitehorn
440273783Skibint
441273911Skibfueword32(volatile const void *addr, int32_t *val)
44292916Sbenno{
44395714Sbenno	struct		thread *td;
44495714Sbenno	pmap_t		pm;
445293636Snwhitehorn	jmp_buf		env;
446273783Skib	int32_t		*p;
44792916Sbenno
448223485Snwhitehorn	td = curthread;
44992916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
45092916Sbenno
451293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
452293636Snwhitehorn	if (setjmp(env)) {
45395714Sbenno		td->td_pcb->pcb_onfault = NULL;
454108942Sgrehan		return (-1);
45595714Sbenno	}
45695714Sbenno
457258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
458258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
459258024Snwhitehorn		return (-1);
460258024Snwhitehorn	}
46192916Sbenno
462273783Skib	*val = *p;
46395714Sbenno
46495714Sbenno	td->td_pcb->pcb_onfault = NULL;
465273783Skib	return (0);
46692916Sbenno}
46797307Sdfr
468273783Skib#ifdef __powerpc64__
469273783Skibint
470273911Skibfueword64(volatile const void *addr, int64_t *val)
47197307Sdfr{
472273783Skib	struct		thread *td;
473273783Skib	pmap_t		pm;
474293636Snwhitehorn	jmp_buf		env;
475273783Skib	int64_t		*p;
476273783Skib
477273783Skib	td = curthread;
478273783Skib	pm = &td->td_proc->p_vmspace->vm_pmap;
479273783Skib
480293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
481293636Snwhitehorn	if (setjmp(env)) {
482273783Skib		td->td_pcb->pcb_onfault = NULL;
483273783Skib		return (-1);
484273783Skib	}
485273783Skib
486273783Skib	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
487273783Skib		td->td_pcb->pcb_onfault = NULL;
488273783Skib		return (-1);
489273783Skib	}
490273783Skib
491273783Skib	*val = *p;
492273783Skib
493273783Skib	td->td_pcb->pcb_onfault = NULL;
494273783Skib	return (0);
49597307Sdfr}
496209975Snwhitehorn#endif
497126474Sgrehan
498273783Skibint
499273911Skibfueword(volatile const void *addr, long *val)
500161675Sdavidxu{
501273783Skib	struct		thread *td;
502273783Skib	pmap_t		pm;
503293636Snwhitehorn	jmp_buf		env;
504273783Skib	long		*p;
505273783Skib
506273783Skib	td = curthread;
507273783Skib	pm = &td->td_proc->p_vmspace->vm_pmap;
508273783Skib
509293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
510293636Snwhitehorn	if (setjmp(env)) {
511273783Skib		td->td_pcb->pcb_onfault = NULL;
512273783Skib		return (-1);
513273783Skib	}
514273783Skib
515273783Skib	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
516273783Skib		td->td_pcb->pcb_onfault = NULL;
517273783Skib		return (-1);
518273783Skib	}
519273783Skib
520273783Skib	*val = *p;
521273783Skib
522273783Skib	td->td_pcb->pcb_onfault = NULL;
523273783Skib	return (0);
524273783Skib}
525273783Skib
526273783Skibint
527273783Skibcasueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
528273783Skib    uint32_t new)
529273783Skib{
530209975Snwhitehorn	struct thread *td;
531209975Snwhitehorn	pmap_t pm;
532293636Snwhitehorn	jmp_buf		env;
533209975Snwhitehorn	uint32_t *p, val;
534209975Snwhitehorn
535223485Snwhitehorn	td = curthread;
536209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
537209975Snwhitehorn
538293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
539293636Snwhitehorn	if (setjmp(env)) {
540209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
541209975Snwhitehorn		return (-1);
542209975Snwhitehorn	}
543209975Snwhitehorn
544258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
545258024Snwhitehorn	    NULL)) {
546258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
547258024Snwhitehorn		return (-1);
548258024Snwhitehorn	}
549258024Snwhitehorn
550209975Snwhitehorn	__asm __volatile (
551209975Snwhitehorn		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
552209975Snwhitehorn		"cmplw %3, %0\n\t"		/* compare */
553209975Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
554209975Snwhitehorn		"stwcx. %4, 0, %2\n\t"      	/* attempt to store */
555209975Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
556209975Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
557209975Snwhitehorn		"2:\n\t"
558209975Snwhitehorn		"stwcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
559209975Snwhitehorn		"3:\n\t"
560209975Snwhitehorn		: "=&r" (val), "=m" (*p)
561209975Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
562264338Sjhibbits		: "cr0", "memory");
563209975Snwhitehorn
564209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
565209975Snwhitehorn
566273783Skib	*oldvalp = val;
567273783Skib	return (0);
568161675Sdavidxu}
569161675Sdavidxu
570209975Snwhitehorn#ifndef __powerpc64__
571273783Skibint
572273783Skibcasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
573126474Sgrehan{
574273783Skib
575273783Skib	return (casueword32((volatile uint32_t *)addr, old,
576273783Skib	    (uint32_t *)oldvalp, new));
577209975Snwhitehorn}
578209975Snwhitehorn#else
579273783Skibint
580273783Skibcasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
581209975Snwhitehorn{
582126474Sgrehan	struct thread *td;
583126474Sgrehan	pmap_t pm;
584293636Snwhitehorn	jmp_buf		env;
585163449Sdavidxu	u_long *p, val;
586126474Sgrehan
587223485Snwhitehorn	td = curthread;
588126474Sgrehan	pm = &td->td_proc->p_vmspace->vm_pmap;
589126474Sgrehan
590293636Snwhitehorn	td->td_pcb->pcb_onfault = &env;
591293636Snwhitehorn	if (setjmp(env)) {
592126474Sgrehan		td->td_pcb->pcb_onfault = NULL;
593126474Sgrehan		return (-1);
594126474Sgrehan	}
595126474Sgrehan
596258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
597258024Snwhitehorn	    NULL)) {
598258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
599258024Snwhitehorn		return (-1);
600258024Snwhitehorn	}
601258024Snwhitehorn
602198724Snwhitehorn	__asm __volatile (
603209975Snwhitehorn		"1:\tldarx %0, 0, %2\n\t"	/* load old value */
604209975Snwhitehorn		"cmpld %3, %0\n\t"		/* compare */
605198724Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
606209975Snwhitehorn		"stdcx. %4, 0, %2\n\t"      	/* attempt to store */
607198724Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
608198724Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
609198724Snwhitehorn		"2:\n\t"
610209975Snwhitehorn		"stdcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
611198724Snwhitehorn		"3:\n\t"
612198724Snwhitehorn		: "=&r" (val), "=m" (*p)
613198724Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
614264338Sjhibbits		: "cr0", "memory");
615126474Sgrehan
616126474Sgrehan	td->td_pcb->pcb_onfault = NULL;
617126474Sgrehan
618273783Skib	*oldvalp = val;
619273783Skib	return (0);
620126474Sgrehan}
621209975Snwhitehorn#endif
622