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