1241675Suqs/*- 2241675Suqs * Copyright (C) 2002 Benno Rice 3241675Suqs * All rights reserved. 4241675Suqs * 5241675Suqs * Redistribution and use in source and binary forms, with or without 6241675Suqs * modification, are permitted provided that the following conditions 7241675Suqs * are met: 8241675Suqs * 1. Redistributions of source code must retain the above copyright 9241675Suqs * notice, this list of conditions and the following disclaimer. 10241675Suqs * 2. Redistributions in binary form must reproduce the above copyright 11241675Suqs * notice, this list of conditions and the following disclaimer in the 12241675Suqs * documentation and/or other materials provided with the distribution. 13241675Suqs * 14241675Suqs * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15241675Suqs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16241675Suqs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17241675Suqs * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18241675Suqs * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19241675Suqs * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20241675Suqs * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21241675Suqs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22241675Suqs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23241675Suqs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24241675Suqs*/ 25241675Suqs/*- 26241675Suqs * Copyright (C) 1993 Wolfgang Solfrank. 27241675Suqs * Copyright (C) 1993 TooLs GmbH. 28241675Suqs * All rights reserved. 29241675Suqs * 30241675Suqs * Redistribution and use in source and binary forms, with or without 31241675Suqs * modification, are permitted provided that the following conditions 32241675Suqs * are met: 33241675Suqs * 1. Redistributions of source code must retain the above copyright 34241675Suqs * notice, this list of conditions and the following disclaimer. 35241675Suqs * 2. Redistributions in binary form must reproduce the above copyright 36241675Suqs * notice, this list of conditions and the following disclaimer in the 37241675Suqs * documentation and/or other materials provided with the distribution. 38241675Suqs * 3. All advertising materials mentioning features or use of this software 39241675Suqs * must display the following acknowledgement: 40241675Suqs * This product includes software developed by TooLs GmbH. 41241675Suqs * 4. The name of TooLs GmbH may not be used to endorse or promote products 42241675Suqs * derived from this software without specific prior written permission. 43241675Suqs * 44241675Suqs * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 45241675Suqs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46241675Suqs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47241675Suqs * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48241675Suqs * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 49241675Suqs * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 50241675Suqs * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 51241675Suqs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 52241675Suqs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 53241675Suqs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54241675Suqs */ 55241675Suqs 56241675Suqs#include <sys/cdefs.h> 57241675Suqs__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/powerpc/copyinout.c 274648 2014-11-18 12:53:32Z kib $"); 58241675Suqs 59241675Suqs#include <sys/param.h> 60241675Suqs#include <sys/lock.h> 61241675Suqs#include <sys/mutex.h> 62241675Suqs#include <sys/systm.h> 63241675Suqs#include <sys/proc.h> 64241675Suqs 65241675Suqs#include <vm/vm.h> 66241675Suqs#include <vm/pmap.h> 67241675Suqs#include <vm/vm_map.h> 68241675Suqs 69241675Suqs#include <machine/pcb.h> 70241675Suqs#include <machine/sr.h> 71241675Suqs#include <machine/slb.h> 72241675Suqs#include <machine/vmparam.h> 73241675Suqs 74241675Suqsint setfault(faultbuf); /* defined in locore.S */ 75241675Suqs 76241675Suqs#ifdef AIM 77241675Suqs/* 78241675Suqs * Makes sure that the right segment of userspace is mapped in. 79241675Suqs */ 80241675Suqs 81241675Suqs#ifdef __powerpc64__ 82241675Suqsstatic __inline void 83241675Suqsset_user_sr(pmap_t pm, volatile const void *addr) 84241675Suqs{ 85241675Suqs struct slb *slb; 86241675Suqs register_t slbv; 87241675Suqs 88241675Suqs /* Try lockless look-up first */ 89241675Suqs slb = user_va_to_slb_entry(pm, (vm_offset_t)addr); 90241675Suqs 91241675Suqs if (slb == NULL) { 92241675Suqs /* If it isn't there, we need to pre-fault the VSID */ 93241675Suqs PMAP_LOCK(pm); 94241675Suqs slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT; 95241675Suqs PMAP_UNLOCK(pm); 96241675Suqs } else { 97241675Suqs slbv = slb->slbv; 98241675Suqs } 99241675Suqs 100241675Suqs /* Mark segment no-execute */ 101241675Suqs slbv |= SLBV_N; 102241675Suqs 103241675Suqs /* If we have already set this VSID, we can just return */ 104241675Suqs if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv) 105241675Suqs return; 106241675Suqs 107241675Suqs __asm __volatile("isync"); 108241675Suqs curthread->td_pcb->pcb_cpu.aim.usr_segm = 109241675Suqs (uintptr_t)addr >> ADDR_SR_SHFT; 110241675Suqs curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv; 111241675Suqs __asm __volatile ("slbie %0; slbmte %1, %2; isync" :: 112241675Suqs "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE)); 113241675Suqs} 114241675Suqs#else 115241675Suqsstatic __inline void 116241675Suqsset_user_sr(pmap_t pm, volatile const void *addr) 117241675Suqs{ 118241675Suqs register_t vsid; 119241675Suqs 120241675Suqs vsid = va_to_vsid(pm, (vm_offset_t)addr); 121241675Suqs 122241675Suqs /* Mark segment no-execute */ 123241675Suqs vsid |= SR_N; 124241675Suqs 125241675Suqs /* If we have already set this VSID, we can just return */ 126241675Suqs if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid) 127241675Suqs return; 128241675Suqs 129241675Suqs __asm __volatile("isync"); 130241675Suqs curthread->td_pcb->pcb_cpu.aim.usr_segm = 131241675Suqs (uintptr_t)addr >> ADDR_SR_SHFT; 132241675Suqs curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid; 133241675Suqs __asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid)); 134241675Suqs} 135241675Suqs#endif 136241675Suqs 137241675Suqsstatic __inline int 138241675Suqsmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen, 139241675Suqs size_t *klen) 140241675Suqs{ 141241675Suqs size_t l; 142241675Suqs 143241675Suqs *kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK); 144241675Suqs 145241675Suqs l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr); 146241675Suqs if (l > ulen) 147241675Suqs l = ulen; 148241675Suqs if (klen) 149241675Suqs *klen = l; 150241675Suqs else if (l != ulen) 151241675Suqs return (EFAULT); 152241675Suqs 153241675Suqs set_user_sr(pm, uaddr); 154241675Suqs 155241675Suqs return (0); 156241675Suqs} 157241675Suqs#else /* Book-E uses a combined kernel/user mapping */ 158241675Suqsstatic __inline int 159241675Suqsmap_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen, 160241675Suqs size_t *klen) 161241675Suqs{ 162241675Suqs 163241675Suqs if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE) 164241675Suqs return (EFAULT); 165241675Suqs 166241675Suqs *kaddr = (void *)(uintptr_t)uaddr; 167241675Suqs if (klen) 168241675Suqs *klen = ulen; 169241675Suqs 170241675Suqs return (0); 171241675Suqs} 172241675Suqs#endif 173241675Suqs 174241675Suqsint 175241675Suqscopyout(const void *kaddr, void *udaddr, size_t len) 176241675Suqs{ 177241675Suqs struct thread *td; 178241675Suqs pmap_t pm; 179241675Suqs faultbuf env; 180241675Suqs const char *kp; 181241675Suqs char *up, *p; 182241675Suqs size_t l; 183241675Suqs 184241675Suqs td = curthread; 185241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 186241675Suqs 187241675Suqs if (setfault(env)) { 188241675Suqs td->td_pcb->pcb_onfault = NULL; 189241675Suqs return (EFAULT); 190241675Suqs } 191241675Suqs 192241675Suqs kp = kaddr; 193241675Suqs up = udaddr; 194241675Suqs 195241675Suqs while (len > 0) { 196241675Suqs if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) { 197241675Suqs td->td_pcb->pcb_onfault = NULL; 198241675Suqs return (EFAULT); 199241675Suqs } 200241675Suqs 201241675Suqs bcopy(kp, p, l); 202241675Suqs 203241675Suqs up += l; 204241675Suqs kp += l; 205241675Suqs len -= l; 206241675Suqs } 207241675Suqs 208241675Suqs td->td_pcb->pcb_onfault = NULL; 209241675Suqs return (0); 210241675Suqs} 211241675Suqs 212241675Suqsint 213241675Suqscopyin(const void *udaddr, void *kaddr, size_t len) 214241675Suqs{ 215241675Suqs struct thread *td; 216241675Suqs pmap_t pm; 217241675Suqs faultbuf env; 218241675Suqs const char *up; 219241675Suqs char *kp, *p; 220241675Suqs size_t l; 221241675Suqs 222241675Suqs td = curthread; 223241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 224241675Suqs 225241675Suqs if (setfault(env)) { 226241675Suqs td->td_pcb->pcb_onfault = NULL; 227241675Suqs return (EFAULT); 228241675Suqs } 229241675Suqs 230241675Suqs kp = kaddr; 231241675Suqs up = udaddr; 232241675Suqs 233241675Suqs while (len > 0) { 234241675Suqs if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) { 235241675Suqs td->td_pcb->pcb_onfault = NULL; 236241675Suqs return (EFAULT); 237241675Suqs } 238241675Suqs 239241675Suqs bcopy(p, kp, l); 240241675Suqs 241241675Suqs up += l; 242241675Suqs kp += l; 243241675Suqs len -= l; 244241675Suqs } 245241675Suqs 246241675Suqs td->td_pcb->pcb_onfault = NULL; 247241675Suqs return (0); 248241675Suqs} 249241675Suqs 250241675Suqsint 251241675Suqscopyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) 252241675Suqs{ 253241675Suqs const char *up; 254241675Suqs char *kp; 255241675Suqs size_t l; 256241675Suqs int rv, c; 257241675Suqs 258241675Suqs kp = kaddr; 259241675Suqs up = udaddr; 260241675Suqs 261241675Suqs rv = ENAMETOOLONG; 262241675Suqs 263241675Suqs for (l = 0; len-- > 0; l++) { 264241675Suqs if ((c = fubyte(up++)) < 0) { 265241675Suqs rv = EFAULT; 266241675Suqs break; 267241675Suqs } 268241675Suqs 269241675Suqs if (!(*kp++ = c)) { 270241675Suqs l++; 271241675Suqs rv = 0; 272241675Suqs break; 273241675Suqs } 274241675Suqs } 275241675Suqs 276241675Suqs if (done != NULL) { 277241675Suqs *done = l; 278241675Suqs } 279241675Suqs 280241675Suqs return (rv); 281241675Suqs} 282241675Suqs 283241675Suqsint 284241675Suqssubyte(volatile void *addr, int byte) 285241675Suqs{ 286241675Suqs struct thread *td; 287241675Suqs pmap_t pm; 288241675Suqs faultbuf env; 289241675Suqs char *p; 290241675Suqs 291241675Suqs td = curthread; 292241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 293241675Suqs 294241675Suqs if (setfault(env)) { 295241675Suqs td->td_pcb->pcb_onfault = NULL; 296241675Suqs return (-1); 297241675Suqs } 298241675Suqs 299241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 300241675Suqs td->td_pcb->pcb_onfault = NULL; 301241675Suqs return (-1); 302241675Suqs } 303241675Suqs 304241675Suqs *p = (char)byte; 305241675Suqs 306241675Suqs td->td_pcb->pcb_onfault = NULL; 307241675Suqs return (0); 308241675Suqs} 309241675Suqs 310241675Suqs#ifdef __powerpc64__ 311241675Suqsint 312241675Suqssuword32(volatile void *addr, int word) 313241675Suqs{ 314241675Suqs struct thread *td; 315241675Suqs pmap_t pm; 316241675Suqs faultbuf env; 317241675Suqs int *p; 318241675Suqs 319241675Suqs td = curthread; 320241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 321241675Suqs 322241675Suqs if (setfault(env)) { 323241675Suqs td->td_pcb->pcb_onfault = NULL; 324241675Suqs return (-1); 325241675Suqs } 326241675Suqs 327241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 328241675Suqs td->td_pcb->pcb_onfault = NULL; 329241675Suqs return (-1); 330241675Suqs } 331241675Suqs 332241675Suqs *p = word; 333241675Suqs 334241675Suqs td->td_pcb->pcb_onfault = NULL; 335241675Suqs return (0); 336241675Suqs} 337241675Suqs#endif 338241675Suqs 339241675Suqsint 340241675Suqssuword(volatile void *addr, long word) 341241675Suqs{ 342241675Suqs struct thread *td; 343241675Suqs pmap_t pm; 344241675Suqs faultbuf env; 345241675Suqs long *p; 346241675Suqs 347241675Suqs td = curthread; 348241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 349241675Suqs 350241675Suqs if (setfault(env)) { 351241675Suqs td->td_pcb->pcb_onfault = NULL; 352241675Suqs return (-1); 353241675Suqs } 354241675Suqs 355241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 356241675Suqs td->td_pcb->pcb_onfault = NULL; 357241675Suqs return (-1); 358241675Suqs } 359241675Suqs 360241675Suqs *p = word; 361241675Suqs 362241675Suqs td->td_pcb->pcb_onfault = NULL; 363241675Suqs return (0); 364241675Suqs} 365241675Suqs 366241675Suqs#ifdef __powerpc64__ 367241675Suqsint 368241675Suqssuword64(volatile void *addr, int64_t word) 369241675Suqs{ 370241675Suqs return (suword(addr, (long)word)); 371241675Suqs} 372241675Suqs#else 373241675Suqsint 374241675Suqssuword32(volatile void *addr, int32_t word) 375241675Suqs{ 376241675Suqs return (suword(addr, (long)word)); 377241675Suqs} 378241675Suqs#endif 379241675Suqs 380241675Suqsint 381241675Suqsfubyte(volatile const void *addr) 382241675Suqs{ 383241675Suqs struct thread *td; 384241675Suqs pmap_t pm; 385241675Suqs faultbuf env; 386241675Suqs u_char *p; 387241675Suqs int val; 388241675Suqs 389241675Suqs td = curthread; 390241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 391241675Suqs 392241675Suqs if (setfault(env)) { 393241675Suqs td->td_pcb->pcb_onfault = NULL; 394241675Suqs return (-1); 395241675Suqs } 396241675Suqs 397241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 398241675Suqs td->td_pcb->pcb_onfault = NULL; 399241675Suqs return (-1); 400241675Suqs } 401241675Suqs 402241675Suqs val = *p; 403241675Suqs 404241675Suqs td->td_pcb->pcb_onfault = NULL; 405241675Suqs return (val); 406241675Suqs} 407241675Suqs 408241675Suqsint 409241675Suqsfuword16(volatile const void *addr) 410241675Suqs{ 411241675Suqs struct thread *td; 412241675Suqs pmap_t pm; 413241675Suqs faultbuf env; 414241675Suqs uint16_t *p, val; 415241675Suqs 416241675Suqs td = curthread; 417241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 418241675Suqs 419241675Suqs if (setfault(env)) { 420241675Suqs td->td_pcb->pcb_onfault = NULL; 421241675Suqs return (-1); 422241675Suqs } 423241675Suqs 424241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 425241675Suqs td->td_pcb->pcb_onfault = NULL; 426241675Suqs return (-1); 427241675Suqs } 428241675Suqs 429241675Suqs val = *p; 430241675Suqs 431241675Suqs td->td_pcb->pcb_onfault = NULL; 432241675Suqs return (val); 433241675Suqs} 434241675Suqs 435241675Suqsint 436241675Suqsfueword32(volatile const void *addr, int32_t *val) 437241675Suqs{ 438241675Suqs struct thread *td; 439241675Suqs pmap_t pm; 440241675Suqs faultbuf env; 441241675Suqs int32_t *p; 442241675Suqs 443241675Suqs td = curthread; 444241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 445241675Suqs 446241675Suqs if (setfault(env)) { 447241675Suqs td->td_pcb->pcb_onfault = NULL; 448241675Suqs return (-1); 449241675Suqs } 450241675Suqs 451241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 452241675Suqs td->td_pcb->pcb_onfault = NULL; 453241675Suqs return (-1); 454241675Suqs } 455241675Suqs 456241675Suqs *val = *p; 457241675Suqs 458241675Suqs td->td_pcb->pcb_onfault = NULL; 459241675Suqs return (0); 460241675Suqs} 461241675Suqs 462241675Suqs#ifdef __powerpc64__ 463241675Suqsint 464241675Suqsfueword64(volatile const void *addr, int64_t *val) 465241675Suqs{ 466241675Suqs struct thread *td; 467241675Suqs pmap_t pm; 468241675Suqs faultbuf env; 469241675Suqs int64_t *p; 470241675Suqs 471241675Suqs td = curthread; 472241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 473241675Suqs 474241675Suqs if (setfault(env)) { 475241675Suqs td->td_pcb->pcb_onfault = NULL; 476241675Suqs return (-1); 477241675Suqs } 478241675Suqs 479241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 480241675Suqs td->td_pcb->pcb_onfault = NULL; 481241675Suqs return (-1); 482241675Suqs } 483241675Suqs 484241675Suqs *val = *p; 485241675Suqs 486241675Suqs td->td_pcb->pcb_onfault = NULL; 487241675Suqs return (0); 488241675Suqs} 489241675Suqs#endif 490241675Suqs 491241675Suqsint 492241675Suqsfueword(volatile const void *addr, long *val) 493241675Suqs{ 494241675Suqs struct thread *td; 495241675Suqs pmap_t pm; 496241675Suqs faultbuf env; 497241675Suqs long *p; 498241675Suqs 499241675Suqs td = curthread; 500241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 501241675Suqs 502241675Suqs if (setfault(env)) { 503241675Suqs td->td_pcb->pcb_onfault = NULL; 504241675Suqs return (-1); 505241675Suqs } 506241675Suqs 507241675Suqs if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 508241675Suqs td->td_pcb->pcb_onfault = NULL; 509241675Suqs return (-1); 510241675Suqs } 511241675Suqs 512241675Suqs *val = *p; 513241675Suqs 514241675Suqs td->td_pcb->pcb_onfault = NULL; 515241675Suqs return (0); 516241675Suqs} 517241675Suqs 518241675Suqsint 519241675Suqscasueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp, 520241675Suqs uint32_t new) 521241675Suqs{ 522241675Suqs struct thread *td; 523241675Suqs pmap_t pm; 524241675Suqs faultbuf env; 525241675Suqs uint32_t *p, val; 526241675Suqs 527241675Suqs td = curthread; 528241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 529241675Suqs 530241675Suqs if (setfault(env)) { 531241675Suqs td->td_pcb->pcb_onfault = NULL; 532241675Suqs return (-1); 533241675Suqs } 534241675Suqs 535241675Suqs if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p), 536241675Suqs NULL)) { 537241675Suqs td->td_pcb->pcb_onfault = NULL; 538241675Suqs return (-1); 539241675Suqs } 540241675Suqs 541241675Suqs __asm __volatile ( 542241675Suqs "1:\tlwarx %0, 0, %2\n\t" /* load old value */ 543241675Suqs "cmplw %3, %0\n\t" /* compare */ 544241675Suqs "bne 2f\n\t" /* exit if not equal */ 545241675Suqs "stwcx. %4, 0, %2\n\t" /* attempt to store */ 546241675Suqs "bne- 1b\n\t" /* spin if failed */ 547241675Suqs "b 3f\n\t" /* we've succeeded */ 548241675Suqs "2:\n\t" 549241675Suqs "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 550241675Suqs "3:\n\t" 551241675Suqs : "=&r" (val), "=m" (*p) 552241675Suqs : "r" (p), "r" (old), "r" (new), "m" (*p) 553241675Suqs : "cc", "memory"); 554241675Suqs 555241675Suqs td->td_pcb->pcb_onfault = NULL; 556241675Suqs 557241675Suqs *oldvalp = val; 558241675Suqs return (0); 559241675Suqs} 560241675Suqs 561241675Suqs#ifndef __powerpc64__ 562241675Suqsint 563241675Suqscasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) 564241675Suqs{ 565241675Suqs 566241675Suqs return (casueword32((volatile uint32_t *)addr, old, 567241675Suqs (uint32_t *)oldvalp, new)); 568241675Suqs} 569241675Suqs#else 570241675Suqsint 571241675Suqscasueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) 572241675Suqs{ 573241675Suqs struct thread *td; 574241675Suqs pmap_t pm; 575241675Suqs faultbuf env; 576241675Suqs u_long *p, val; 577241675Suqs 578241675Suqs td = curthread; 579241675Suqs pm = &td->td_proc->p_vmspace->vm_pmap; 580241675Suqs 581241675Suqs if (setfault(env)) { 582241675Suqs td->td_pcb->pcb_onfault = NULL; 583241675Suqs return (-1); 584241675Suqs } 585241675Suqs 586241675Suqs if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p), 587241675Suqs NULL)) { 588241675Suqs td->td_pcb->pcb_onfault = NULL; 589241675Suqs return (-1); 590241675Suqs } 591241675Suqs 592241675Suqs __asm __volatile ( 593241675Suqs "1:\tldarx %0, 0, %2\n\t" /* load old value */ 594241675Suqs "cmpld %3, %0\n\t" /* compare */ 595241675Suqs "bne 2f\n\t" /* exit if not equal */ 596241675Suqs "stdcx. %4, 0, %2\n\t" /* attempt to store */ 597241675Suqs "bne- 1b\n\t" /* spin if failed */ 598241675Suqs "b 3f\n\t" /* we've succeeded */ 599241675Suqs "2:\n\t" 600241675Suqs "stdcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 601241675Suqs "3:\n\t" 602241675Suqs : "=&r" (val), "=m" (*p) 603241675Suqs : "r" (p), "r" (old), "r" (new), "m" (*p) 604241675Suqs : "cc", "memory"); 605241675Suqs 606241675Suqs td->td_pcb->pcb_onfault = NULL; 607241675Suqs 608241675Suqs *oldvalp = val; 609241675Suqs return (0); 610241675Suqs} 611241675Suqs#endif 612241675Suqs