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