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
83209975Snwhitehornset_user_sr(pmap_t pm, 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
116209975Snwhitehornset_user_sr(pmap_t pm, 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
138258024Snwhitehornmap_user_ptr(pmap_t pm, 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
159258024Snwhitehornmap_user_ptr(pmap_t pm, 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
28492916Sbennosubyte(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
312209975Snwhitehornsuword32(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
34092916Sbennosuword(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
368209975Snwhitehornsuword64(void *addr, int64_t word)
369209975Snwhitehorn{
370209975Snwhitehorn	return (suword(addr, (long)word));
371209975Snwhitehorn}
372209975Snwhitehorn#else
373209975Snwhitehornint
37497342Sbennosuword32(void *addr, int32_t word)
37597307Sdfr{
37697342Sbenno	return (suword(addr, (long)word));
37797307Sdfr}
378209975Snwhitehorn#endif
37997307Sdfr
38097307Sdfrint
38192916Sbennofubyte(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
408209975Snwhitehorn#ifdef __powerpc64__
409209975Snwhitehornint32_t
410209975Snwhitehornfuword32(const void *addr)
411209975Snwhitehorn{
412209975Snwhitehorn	struct		thread *td;
413209975Snwhitehorn	pmap_t		pm;
414209975Snwhitehorn	faultbuf	env;
415209975Snwhitehorn	int32_t		*p, val;
416209975Snwhitehorn
417223485Snwhitehorn	td = curthread;
418209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
419209975Snwhitehorn
420209975Snwhitehorn	if (setfault(env)) {
421209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
422209975Snwhitehorn		return (-1);
423209975Snwhitehorn	}
424209975Snwhitehorn
425258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
426258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
427258024Snwhitehorn		return (-1);
428258024Snwhitehorn	}
429209975Snwhitehorn
430209975Snwhitehorn	val = *p;
431209975Snwhitehorn
432209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
433209975Snwhitehorn	return (val);
434209975Snwhitehorn}
435209975Snwhitehorn#endif
436209975Snwhitehorn
43792916Sbennolong
43892916Sbennofuword(const void *addr)
43992916Sbenno{
44095714Sbenno	struct		thread *td;
44195714Sbenno	pmap_t		pm;
44295714Sbenno	faultbuf	env;
44395714Sbenno	long		*p, val;
44492916Sbenno
445223485Snwhitehorn	td = curthread;
44692916Sbenno	pm = &td->td_proc->p_vmspace->vm_pmap;
44792916Sbenno
44895714Sbenno	if (setfault(env)) {
44995714Sbenno		td->td_pcb->pcb_onfault = NULL;
450108942Sgrehan		return (-1);
45195714Sbenno	}
45295714Sbenno
453258024Snwhitehorn	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
454258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
455258024Snwhitehorn		return (-1);
456258024Snwhitehorn	}
45792916Sbenno
45895714Sbenno	val = *p;
45995714Sbenno
46095714Sbenno	td->td_pcb->pcb_onfault = NULL;
46195714Sbenno	return (val);
46292916Sbenno}
46397307Sdfr
464209975Snwhitehorn#ifndef __powerpc64__
46597342Sbennoint32_t
46697307Sdfrfuword32(const void *addr)
46797307Sdfr{
46897342Sbenno	return ((int32_t)fuword(addr));
46997307Sdfr}
470209975Snwhitehorn#endif
471126474Sgrehan
472163449Sdavidxuuint32_t
473209975Snwhitehorncasuword32(volatile uint32_t *addr, uint32_t old, uint32_t new)
474161675Sdavidxu{
475209975Snwhitehorn	struct thread *td;
476209975Snwhitehorn	pmap_t pm;
477209975Snwhitehorn	faultbuf env;
478209975Snwhitehorn	uint32_t *p, val;
479209975Snwhitehorn
480223485Snwhitehorn	td = curthread;
481209975Snwhitehorn	pm = &td->td_proc->p_vmspace->vm_pmap;
482209975Snwhitehorn
483209975Snwhitehorn	if (setfault(env)) {
484209975Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
485209975Snwhitehorn		return (-1);
486209975Snwhitehorn	}
487209975Snwhitehorn
488258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
489258024Snwhitehorn	    NULL)) {
490258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
491258024Snwhitehorn		return (-1);
492258024Snwhitehorn	}
493258024Snwhitehorn
494209975Snwhitehorn	__asm __volatile (
495209975Snwhitehorn		"1:\tlwarx %0, 0, %2\n\t"	/* load old value */
496209975Snwhitehorn		"cmplw %3, %0\n\t"		/* compare */
497209975Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
498209975Snwhitehorn		"stwcx. %4, 0, %2\n\t"      	/* attempt to store */
499209975Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
500209975Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
501209975Snwhitehorn		"2:\n\t"
502209975Snwhitehorn		"stwcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
503209975Snwhitehorn		"3:\n\t"
504209975Snwhitehorn		: "=&r" (val), "=m" (*p)
505209975Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
506209975Snwhitehorn		: "cc", "memory");
507209975Snwhitehorn
508209975Snwhitehorn	td->td_pcb->pcb_onfault = NULL;
509209975Snwhitehorn
510209975Snwhitehorn	return (val);
511161675Sdavidxu}
512161675Sdavidxu
513209975Snwhitehorn#ifndef __powerpc64__
514163449Sdavidxuu_long
515163449Sdavidxucasuword(volatile u_long *addr, u_long old, u_long new)
516126474Sgrehan{
517209975Snwhitehorn	return (casuword32((volatile uint32_t *)addr, old, new));
518209975Snwhitehorn}
519209975Snwhitehorn#else
520209975Snwhitehornu_long
521209975Snwhitehorncasuword(volatile u_long *addr, u_long old, u_long new)
522209975Snwhitehorn{
523126474Sgrehan	struct thread *td;
524126474Sgrehan	pmap_t pm;
525126474Sgrehan	faultbuf env;
526163449Sdavidxu	u_long *p, val;
527126474Sgrehan
528223485Snwhitehorn	td = curthread;
529126474Sgrehan	pm = &td->td_proc->p_vmspace->vm_pmap;
530126474Sgrehan
531126474Sgrehan	if (setfault(env)) {
532126474Sgrehan		td->td_pcb->pcb_onfault = NULL;
533126474Sgrehan		return (-1);
534126474Sgrehan	}
535126474Sgrehan
536258024Snwhitehorn	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
537258024Snwhitehorn	    NULL)) {
538258024Snwhitehorn		td->td_pcb->pcb_onfault = NULL;
539258024Snwhitehorn		return (-1);
540258024Snwhitehorn	}
541258024Snwhitehorn
542198724Snwhitehorn	__asm __volatile (
543209975Snwhitehorn		"1:\tldarx %0, 0, %2\n\t"	/* load old value */
544209975Snwhitehorn		"cmpld %3, %0\n\t"		/* compare */
545198724Snwhitehorn		"bne 2f\n\t"			/* exit if not equal */
546209975Snwhitehorn		"stdcx. %4, 0, %2\n\t"      	/* attempt to store */
547198724Snwhitehorn		"bne- 1b\n\t"			/* spin if failed */
548198724Snwhitehorn		"b 3f\n\t"			/* we've succeeded */
549198724Snwhitehorn		"2:\n\t"
550209975Snwhitehorn		"stdcx. %0, 0, %2\n\t"       	/* clear reservation (74xx) */
551198724Snwhitehorn		"3:\n\t"
552198724Snwhitehorn		: "=&r" (val), "=m" (*p)
553198724Snwhitehorn		: "r" (p), "r" (old), "r" (new), "m" (*p)
554198724Snwhitehorn		: "cc", "memory");
555126474Sgrehan
556126474Sgrehan	td->td_pcb->pcb_onfault = NULL;
557126474Sgrehan
558126474Sgrehan	return (val);
559126474Sgrehan}
560209975Snwhitehorn#endif
561209975Snwhitehorn
562