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$");
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
7496251Sbennoint	setfault(faultbuf);	/* defined in locore.S */
7596251Sbenno
76258024Snwhitehorn#ifdef AIM
7792916Sbenno/*
7892916Sbenno * Makes sure that the right segment of userspace is mapped in.
7992916Sbenno */
80209975Snwhitehorn
81209975Snwhitehorn#ifdef __powerpc64__
8292916Sbennostatic __inline void
83274648Skibset_user_sr(pmap_t pm, volatile const void *addr)
8492916Sbenno{
85212715Snwhitehorn	struct slb *slb;
86214574Snwhitehorn	register_t slbv;
8792916Sbenno
88212715Snwhitehorn	/* Try lockless look-up first */
89212715Snwhitehorn	slb = user_va_to_slb_entry(pm, (vm_offset_t)addr);
90212715Snwhitehorn
91212715Snwhitehorn	if (slb == NULL) {
92212715Snwhitehorn		/* If it isn't there, we need to pre-fault the VSID */
93212715Snwhitehorn		PMAP_LOCK(pm);
94214574Snwhitehorn		slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT;
95212715Snwhitehorn		PMAP_UNLOCK(pm);
96212715Snwhitehorn	} else {
97214574Snwhitehorn		slbv = slb->slbv;
98212715Snwhitehorn	}
99212715Snwhitehorn
100214610Snwhitehorn	/* Mark segment no-execute */
101214610Snwhitehorn	slbv |= SLBV_N;
102214610Snwhitehorn
103214574Snwhitehorn	/* If we have already set this VSID, we can just return */
104214574Snwhitehorn	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv)
105214574Snwhitehorn		return;
106209975Snwhitehorn
107214739Snwhitehorn	__asm __volatile("isync");
108212715Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_segm =
109212715Snwhitehorn	    (uintptr_t)addr >> ADDR_SR_SHFT;
110214574Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
111214739Snwhitehorn	__asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
112214739Snwhitehorn	    "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
113209975Snwhitehorn}
114209975Snwhitehorn#else
115209975Snwhitehornstatic __inline void
116274648Skibset_user_sr(pmap_t pm, volatile const void *addr)
117209975Snwhitehorn{
118209975Snwhitehorn	register_t vsid;
119209975Snwhitehorn
120209975Snwhitehorn	vsid = va_to_vsid(pm, (vm_offset_t)addr);
121209975Snwhitehorn
122214749Snwhitehorn	/* Mark segment no-execute */
123214749Snwhitehorn	vsid |= SR_N;
124214749Snwhitehorn
125214574Snwhitehorn	/* If we have already set this VSID, we can just return */
126214574Snwhitehorn	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
127214574Snwhitehorn		return;
128214574Snwhitehorn
129214607Snwhitehorn	__asm __volatile("isync");
130214739Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_segm =
131214739Snwhitehorn	    (uintptr_t)addr >> ADDR_SR_SHFT;
132214574Snwhitehorn	curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
133214607Snwhitehorn	__asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
13492916Sbenno}
135209975Snwhitehorn#endif
13692916Sbenno
137258024Snwhitehornstatic __inline int
138274648Skibmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
139258024Snwhitehorn    size_t *klen)
140258024Snwhitehorn{
141258024Snwhitehorn	size_t l;
142258024Snwhitehorn
143258024Snwhitehorn	*kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
144258024Snwhitehorn
145258024Snwhitehorn	l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
146258024Snwhitehorn	if (l > ulen)
147258024Snwhitehorn		l = ulen;
148258024Snwhitehorn	if (klen)
149258024Snwhitehorn		*klen = l;
150258024Snwhitehorn	else if (l != ulen)
151258024Snwhitehorn		return (EFAULT);
152258024Snwhitehorn
153258024Snwhitehorn	set_user_sr(pm, uaddr);
154258024Snwhitehorn
155258024Snwhitehorn	return (0);
156258024Snwhitehorn}
157258024Snwhitehorn#else /* Book-E uses a combined kernel/user mapping */
158258024Snwhitehornstatic __inline int
159274648Skibmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
160258024Snwhitehorn    size_t *klen)
161258024Snwhitehorn{
162258024Snwhitehorn
163258024Snwhitehorn	if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE)
164258024Snwhitehorn		return (EFAULT);
165258024Snwhitehorn
166258024Snwhitehorn	*kaddr = (void *)(uintptr_t)uaddr;
167258024Snwhitehorn	if (klen)
168258024Snwhitehorn		*klen = ulen;
169258024Snwhitehorn
170258024Snwhitehorn	return (0);
171258024Snwhitehorn}
172258024Snwhitehorn#endif
173258024Snwhitehorn
17492916Sbennoint
17592916Sbennocopyout(const void *kaddr, void *udaddr, size_t len)
17692916Sbenno{
17792916Sbenno	struct		thread *td;
17892916Sbenno	pmap_t		pm;
17995714Sbenno	faultbuf	env;
18092916Sbenno	const char	*kp;
18192916Sbenno	char		*up, *p;
18292916Sbenno	size_t		l;
18392916Sbenno
184223485Snwhitehorn	td = curthread;
18592916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
18692916Sbenno
18795714Sbenno	if (setfault(env)) {
18895714Sbenno		td->td_pcb->pcb_onfault = NULL;
18995714Sbenno		return (EFAULT);
19095714Sbenno	}
19195714Sbenno
19292916Sbenno	kp = kaddr;
19392916Sbenno	up = udaddr;
19492916Sbenno
19592916Sbenno	while (len > 0) {
196258024Snwhitehorn		if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
197258024Snwhitehorn			td->td_pcb->pcb_onfault = NULL;
198266001Sian			return (EFAULT);
199258024Snwhitehorn		}
20092916Sbenno
20192916Sbenno		bcopy(kp, p, l);
20292916Sbenno
20392916Sbenno		up += l;
20492916Sbenno		kp += l;
20592916Sbenno		len -= l;
20692916Sbenno	}
20792916Sbenno
20895714Sbenno	td->td_pcb->pcb_onfault = NULL;
20992916Sbenno	return (0);
21092916Sbenno}
21192916Sbenno
21292916Sbennoint
21392916Sbennocopyin(const void *udaddr, void *kaddr, size_t len)
21492916Sbenno{
21592916Sbenno	struct		thread *td;
21692916Sbenno	pmap_t		pm;
21795714Sbenno	faultbuf	env;
21892916Sbenno	const char	*up;
21992916Sbenno	char		*kp, *p;
22092916Sbenno	size_t		l;
22192916Sbenno
222223485Snwhitehorn	td = curthread;
22392916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
22492916Sbenno
22595714Sbenno	if (setfault(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;
236266001Sian			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
284274648Skibsubyte(volatile void *addr, int byte)
28592916Sbenno{
28695714Sbenno	struct		thread *td;
28795714Sbenno	pmap_t		pm;
28895714Sbenno	faultbuf	env;
28995714Sbenno	char		*p;
29092916Sbenno
291223485Snwhitehorn	td = curthread;
29292916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
29392916Sbenno
29495714Sbenno	if (setfault(env)) {
29595714Sbenno		td->td_pcb->pcb_onfault = NULL;
296108942Sgrehan		return (-1);
29795714Sbenno	}
29895714Sbenno
299258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
300258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
301258024Snwhitehorn		return (-1);
302258024Snwhitehorn	}
30392916Sbenno
30492916Sbenno	*p = (char)byte;
30592916Sbenno
30695714Sbenno	td->td_pcb->pcb_onfault = NULL;
30792916Sbenno	return (0);
30892916Sbenno}
30992916Sbenno
310209975Snwhitehorn#ifdef __powerpc64__
31192916Sbennoint
312274648Skibsuword32(volatile void *addr, int word)
313209975Snwhitehorn{
314209975Snwhitehorn	struct		thread *td;
315209975Snwhitehorn	pmap_t		pm;
316209975Snwhitehorn	faultbuf	env;
317209975Snwhitehorn	int		*p;
318209975Snwhitehorn
319223485Snwhitehorn	td = curthread;
320209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
321209975Snwhitehorn
322209975Snwhitehorn	if (setfault(env)) {
323209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
324209975Snwhitehorn		return (-1);
325209975Snwhitehorn	}
326209975Snwhitehorn
327258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
328258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
329258024Snwhitehorn		return (-1);
330258024Snwhitehorn	}
331209975Snwhitehorn
332209975Snwhitehorn	*p = word;
333209975Snwhitehorn
334209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
335209975Snwhitehorn	return (0);
336209975Snwhitehorn}
337209975Snwhitehorn#endif
338209975Snwhitehorn
339209975Snwhitehornint
340274648Skibsuword(volatile void *addr, long word)
34192916Sbenno{
34295714Sbenno	struct		thread *td;
34395714Sbenno	pmap_t		pm;
34495714Sbenno	faultbuf	env;
34595714Sbenno	long		*p;
34692916Sbenno
347223485Snwhitehorn	td = curthread;
34892916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
34992916Sbenno
35095714Sbenno	if (setfault(env)) {
35195714Sbenno		td->td_pcb->pcb_onfault = NULL;
352108942Sgrehan		return (-1);
35395714Sbenno	}
35495714Sbenno
355258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
356258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
357258024Snwhitehorn		return (-1);
358258024Snwhitehorn	}
35992916Sbenno
36092916Sbenno	*p = word;
36192916Sbenno
36295714Sbenno	td->td_pcb->pcb_onfault = NULL;
36392916Sbenno	return (0);
36492916Sbenno}
36592916Sbenno
366209975Snwhitehorn#ifdef __powerpc64__
36792916Sbennoint
368274648Skibsuword64(volatile void *addr, int64_t word)
369209975Snwhitehorn{
370209975Snwhitehorn	return (suword(addr, (long)word));
371209975Snwhitehorn}
372209975Snwhitehorn#else
373209975Snwhitehornint
374274648Skibsuword32(volatile void *addr, int32_t word)
37597307Sdfr{
37697342Sbenno	return (suword(addr, (long)word));
37797307Sdfr}
378209975Snwhitehorn#endif
37997307Sdfr
38097307Sdfrint
381274648Skibfubyte(volatile const void *addr)
38292916Sbenno{
38395714Sbenno	struct		thread *td;
38495714Sbenno	pmap_t		pm;
38595714Sbenno	faultbuf	env;
386108942Sgrehan	u_char		*p;
38795714Sbenno	int		val;
38892916Sbenno
389223485Snwhitehorn	td = curthread;
39092916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
39192916Sbenno
39295714Sbenno	if (setfault(env)) {
39395714Sbenno		td->td_pcb->pcb_onfault = NULL;
394108942Sgrehan		return (-1);
39595714Sbenno	}
39695714Sbenno
397258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
398258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
399258024Snwhitehorn		return (-1);
400258024Snwhitehorn	}
40192916Sbenno
402108942Sgrehan	val = *p;
40395714Sbenno
40495714Sbenno	td->td_pcb->pcb_onfault = NULL;
40595714Sbenno	return (val);
40692916Sbenno}
40792916Sbenno
408274648Skibint
409274648Skibfuword16(volatile const void *addr)
410209975Snwhitehorn{
411209975Snwhitehorn	struct		thread *td;
412209975Snwhitehorn	pmap_t		pm;
413209975Snwhitehorn	faultbuf	env;
414274648Skib	uint16_t	*p, val;
415209975Snwhitehorn
416223485Snwhitehorn	td = curthread;
417209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
418209975Snwhitehorn
419209975Snwhitehorn	if (setfault(env)) {
420209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
421209975Snwhitehorn		return (-1);
422209975Snwhitehorn	}
423209975Snwhitehorn
424258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
425258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
426258024Snwhitehorn		return (-1);
427258024Snwhitehorn	}
428209975Snwhitehorn
429209975Snwhitehorn	val = *p;
430209975Snwhitehorn
431209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
432209975Snwhitehorn	return (val);
433209975Snwhitehorn}
434209975Snwhitehorn
435274648Skibint
436274648Skibfueword32(volatile const void *addr, int32_t *val)
43792916Sbenno{
43895714Sbenno	struct		thread *td;
43995714Sbenno	pmap_t		pm;
44095714Sbenno	faultbuf	env;
441274648Skib	int32_t		*p;
44292916Sbenno
443223485Snwhitehorn	td = curthread;
44492916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
44592916Sbenno
44695714Sbenno	if (setfault(env)) {
44795714Sbenno		td->td_pcb->pcb_onfault = NULL;
448108942Sgrehan		return (-1);
44995714Sbenno	}
45095714Sbenno
451258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
452258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
453258024Snwhitehorn		return (-1);
454258024Snwhitehorn	}
45592916Sbenno
456274648Skib	*val = *p;
45795714Sbenno
45895714Sbenno	td->td_pcb->pcb_onfault = NULL;
459274648Skib	return (0);
46092916Sbenno}
46197307Sdfr
462274648Skib#ifdef __powerpc64__
463274648Skibint
464274648Skibfueword64(volatile const void *addr, int64_t *val)
46597307Sdfr{
466274648Skib	struct		thread *td;
467274648Skib	pmap_t		pm;
468274648Skib	faultbuf	env;
469274648Skib	int64_t		*p;
470274648Skib
471274648Skib	td = curthread;
472274648Skib	pm = &td->td_proc->p_vmspace->vm_pmap;
473274648Skib
474274648Skib	if (setfault(env)) {
475274648Skib		td->td_pcb->pcb_onfault = NULL;
476274648Skib		return (-1);
477274648Skib	}
478274648Skib
479274648Skib	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
480274648Skib		td->td_pcb->pcb_onfault = NULL;
481274648Skib		return (-1);
482274648Skib	}
483274648Skib
484274648Skib	*val = *p;
485274648Skib
486274648Skib	td->td_pcb->pcb_onfault = NULL;
487274648Skib	return (0);
48897307Sdfr}
489209975Snwhitehorn#endif
490126474Sgrehan
491274648Skibint
492274648Skibfueword(volatile const void *addr, long *val)
493161675Sdavidxu{
494274648Skib	struct		thread *td;
495274648Skib	pmap_t		pm;
496274648Skib	faultbuf	env;
497274648Skib	long		*p;
498274648Skib
499274648Skib	td = curthread;
500274648Skib	pm = &td->td_proc->p_vmspace->vm_pmap;
501274648Skib
502274648Skib	if (setfault(env)) {
503274648Skib		td->td_pcb->pcb_onfault = NULL;
504274648Skib		return (-1);
505274648Skib	}
506274648Skib
507274648Skib	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
508274648Skib		td->td_pcb->pcb_onfault = NULL;
509274648Skib		return (-1);
510274648Skib	}
511274648Skib
512274648Skib	*val = *p;
513274648Skib
514274648Skib	td->td_pcb->pcb_onfault = NULL;
515274648Skib	return (0);
516274648Skib}
517274648Skib
518274648Skibint
519274648Skibcasueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
520274648Skib    uint32_t new)
521274648Skib{
522209975Snwhitehorn	struct thread *td;
523209975Snwhitehorn	pmap_t pm;
524209975Snwhitehorn	faultbuf env;
525209975Snwhitehorn	uint32_t *p, val;
526209975Snwhitehorn
527223485Snwhitehorn	td = curthread;
528209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
529209975Snwhitehorn
530209975Snwhitehorn	if (setfault(env)) {
531209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
532209975Snwhitehorn		return (-1);
533209975Snwhitehorn	}
534209975Snwhitehorn
535258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
536258024Snwhitehorn	    NULL)) {
537258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
538258024Snwhitehorn		return (-1);
539258024Snwhitehorn	}
540258024Snwhitehorn
541209975Snwhitehorn	__asm __volatile (
542209975Snwhitehorn		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
543209975Snwhitehorn		"cmplw %3, %0\n\t"		/* compare */
544209975Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
545209975Snwhitehorn		"stwcx. %4, 0, %2\n\t"      	/* attempt to store */
546209975Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
547209975Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
548209975Snwhitehorn		"2:\n\t"
549209975Snwhitehorn		"stwcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
550209975Snwhitehorn		"3:\n\t"
551209975Snwhitehorn		: "=&r" (val), "=m" (*p)
552209975Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
553209975Snwhitehorn		: "cc", "memory");
554209975Snwhitehorn
555209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
556209975Snwhitehorn
557274648Skib	*oldvalp = val;
558274648Skib	return (0);
559161675Sdavidxu}
560161675Sdavidxu
561209975Snwhitehorn#ifndef __powerpc64__
562274648Skibint
563274648Skibcasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
564126474Sgrehan{
565274648Skib
566274648Skib	return (casueword32((volatile uint32_t *)addr, old,
567274648Skib	    (uint32_t *)oldvalp, new));
568209975Snwhitehorn}
569209975Snwhitehorn#else
570274648Skibint
571274648Skibcasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
572209975Snwhitehorn{
573126474Sgrehan	struct thread *td;
574126474Sgrehan	pmap_t pm;
575126474Sgrehan	faultbuf env;
576163449Sdavidxu	u_long *p, val;
577126474Sgrehan
578223485Snwhitehorn	td = curthread;
579126474Sgrehan	pm = &td->td_proc->p_vmspace->vm_pmap;
580126474Sgrehan
581126474Sgrehan	if (setfault(env)) {
582126474Sgrehan		td->td_pcb->pcb_onfault = NULL;
583126474Sgrehan		return (-1);
584126474Sgrehan	}
585126474Sgrehan
586258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
587258024Snwhitehorn	    NULL)) {
588258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
589258024Snwhitehorn		return (-1);
590258024Snwhitehorn	}
591258024Snwhitehorn
592198724Snwhitehorn	__asm __volatile (
593209975Snwhitehorn		"1:\tldarx %0, 0, %2\n\t"	/* load old value */
594209975Snwhitehorn		"cmpld %3, %0\n\t"		/* compare */
595198724Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
596209975Snwhitehorn		"stdcx. %4, 0, %2\n\t"      	/* attempt to store */
597198724Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
598198724Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
599198724Snwhitehorn		"2:\n\t"
600209975Snwhitehorn		"stdcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
601198724Snwhitehorn		"3:\n\t"
602198724Snwhitehorn		: "=&r" (val), "=m" (*p)
603198724Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
604198724Snwhitehorn		: "cc", "memory");
605126474Sgrehan
606126474Sgrehan	td->td_pcb->pcb_onfault = NULL;
607126474Sgrehan
608274648Skib	*oldvalp = val;
609274648Skib	return (0);
610126474Sgrehan}
611209975Snwhitehorn#endif
612