The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/aim/copyinout.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (C) 2002 Benno Rice
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24 */
   25 /*-
   26  * Copyright (C) 1993 Wolfgang Solfrank.
   27  * Copyright (C) 1993 TooLs GmbH.
   28  * All rights reserved.
   29  *
   30  * Redistribution and use in source and binary forms, with or without
   31  * modification, are permitted provided that the following conditions
   32  * are met:
   33  * 1. Redistributions of source code must retain the above copyright
   34  *    notice, this list of conditions and the following disclaimer.
   35  * 2. Redistributions in binary form must reproduce the above copyright
   36  *    notice, this list of conditions and the following disclaimer in the
   37  *    documentation and/or other materials provided with the distribution.
   38  * 3. All advertising materials mentioning features or use of this software
   39  *    must display the following acknowledgement:
   40  *      This product includes software developed by TooLs GmbH.
   41  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   42  *    derived from this software without specific prior written permission.
   43  *
   44  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   47  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   49  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   50  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   51  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   52  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   53  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   54  */
   55 
   56 #include <sys/cdefs.h>
   57 __FBSDID("$FreeBSD$");
   58 
   59 #include <sys/param.h>
   60 #include <sys/lock.h>
   61 #include <sys/mutex.h>
   62 #include <sys/systm.h>
   63 #include <sys/proc.h>
   64 
   65 #include <vm/vm.h>
   66 #include <vm/pmap.h>
   67 #include <vm/vm_map.h>
   68 
   69 #include <machine/pcb.h>
   70 #include <machine/sr.h>
   71 #include <machine/slb.h>
   72 
   73 int     setfault(faultbuf);     /* defined in locore.S */
   74 
   75 /*
   76  * Makes sure that the right segment of userspace is mapped in.
   77  */
   78 
   79 #ifdef __powerpc64__
   80 static __inline void
   81 set_user_sr(pmap_t pm, const void *addr)
   82 {
   83         struct slb *slb;
   84         register_t slbv;
   85 
   86         /* Try lockless look-up first */
   87         slb = user_va_to_slb_entry(pm, (vm_offset_t)addr);
   88 
   89         if (slb == NULL) {
   90                 /* If it isn't there, we need to pre-fault the VSID */
   91                 PMAP_LOCK(pm);
   92                 slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT;
   93                 PMAP_UNLOCK(pm);
   94         } else {
   95                 slbv = slb->slbv;
   96         }
   97 
   98         /* Mark segment no-execute */
   99         slbv |= SLBV_N;
  100 
  101         /* If we have already set this VSID, we can just return */
  102         if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv) 
  103                 return;
  104 
  105         __asm __volatile("isync");
  106         curthread->td_pcb->pcb_cpu.aim.usr_segm =
  107             (uintptr_t)addr >> ADDR_SR_SHFT;
  108         curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
  109         __asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
  110             "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
  111 }
  112 #else
  113 static __inline void
  114 set_user_sr(pmap_t pm, const void *addr)
  115 {
  116         register_t vsid;
  117 
  118         vsid = va_to_vsid(pm, (vm_offset_t)addr);
  119 
  120         /* Mark segment no-execute */
  121         vsid |= SR_N;
  122 
  123         /* If we have already set this VSID, we can just return */
  124         if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
  125                 return;
  126 
  127         __asm __volatile("isync");
  128         curthread->td_pcb->pcb_cpu.aim.usr_segm =
  129             (uintptr_t)addr >> ADDR_SR_SHFT;
  130         curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
  131         __asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
  132 }
  133 #endif
  134 
  135 int
  136 copyout(const void *kaddr, void *udaddr, size_t len)
  137 {
  138         struct          thread *td;
  139         pmap_t          pm;
  140         faultbuf        env;
  141         const char      *kp;
  142         char            *up, *p;
  143         size_t          l;
  144 
  145         td = curthread;
  146         pm = &td->td_proc->p_vmspace->vm_pmap;
  147 
  148         if (setfault(env)) {
  149                 td->td_pcb->pcb_onfault = NULL;
  150                 return (EFAULT);
  151         }
  152 
  153         kp = kaddr;
  154         up = udaddr;
  155 
  156         while (len > 0) {
  157                 p = (char *)USER_ADDR + ((uintptr_t)up & ~SEGMENT_MASK);
  158 
  159                 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
  160                 if (l > len)
  161                         l = len;
  162 
  163                 set_user_sr(pm,up);
  164 
  165                 bcopy(kp, p, l);
  166 
  167                 up += l;
  168                 kp += l;
  169                 len -= l;
  170         }
  171 
  172         td->td_pcb->pcb_onfault = NULL;
  173         return (0);
  174 }
  175 
  176 int
  177 copyin(const void *udaddr, void *kaddr, size_t len)
  178 {
  179         struct          thread *td;
  180         pmap_t          pm;
  181         faultbuf        env;
  182         const char      *up;
  183         char            *kp, *p;
  184         size_t          l;
  185 
  186         td = curthread;
  187         pm = &td->td_proc->p_vmspace->vm_pmap;
  188 
  189         if (setfault(env)) {
  190                 td->td_pcb->pcb_onfault = NULL;
  191                 return (EFAULT);
  192         }
  193 
  194         kp = kaddr;
  195         up = udaddr;
  196 
  197         while (len > 0) {
  198                 p = (char *)USER_ADDR + ((uintptr_t)up & ~SEGMENT_MASK);
  199 
  200                 l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
  201                 if (l > len)
  202                         l = len;
  203 
  204                 set_user_sr(pm,up);
  205 
  206                 bcopy(p, kp, l);
  207 
  208                 up += l;
  209                 kp += l;
  210                 len -= l;
  211         }
  212 
  213         td->td_pcb->pcb_onfault = NULL;
  214         return (0);
  215 }
  216 
  217 int
  218 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
  219 {
  220         struct          thread *td;
  221         pmap_t          pm;
  222         faultbuf        env;
  223         const char      *up;
  224         char            *kp;
  225         size_t          l;
  226         int             rv, c;
  227 
  228         td = curthread;
  229         pm = &td->td_proc->p_vmspace->vm_pmap;
  230 
  231         if (setfault(env)) {
  232                 td->td_pcb->pcb_onfault = NULL;
  233                 return (EFAULT);
  234         }
  235 
  236         kp = kaddr;
  237         up = udaddr;
  238 
  239         rv = ENAMETOOLONG;
  240 
  241         for (l = 0; len-- > 0; l++) {
  242                 if ((c = fubyte(up++)) < 0) {
  243                         rv = EFAULT;
  244                         break;
  245                 }
  246 
  247                 if (!(*kp++ = c)) {
  248                         l++;
  249                         rv = 0;
  250                         break;
  251                 }
  252         }
  253 
  254         if (done != NULL) {
  255                 *done = l;
  256         }
  257 
  258         td->td_pcb->pcb_onfault = NULL;
  259         return (rv);
  260 }
  261 
  262 int
  263 subyte(void *addr, int byte)
  264 {
  265         struct          thread *td;
  266         pmap_t          pm;
  267         faultbuf        env;
  268         char            *p;
  269 
  270         td = curthread;
  271         pm = &td->td_proc->p_vmspace->vm_pmap;
  272         p = (char *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  273 
  274         if (setfault(env)) {
  275                 td->td_pcb->pcb_onfault = NULL;
  276                 return (-1);
  277         }
  278 
  279         set_user_sr(pm,addr);
  280 
  281         *p = (char)byte;
  282 
  283         td->td_pcb->pcb_onfault = NULL;
  284         return (0);
  285 }
  286 
  287 #ifdef __powerpc64__
  288 int
  289 suword32(void *addr, int word)
  290 {
  291         struct          thread *td;
  292         pmap_t          pm;
  293         faultbuf        env;
  294         int             *p;
  295 
  296         td = curthread;
  297         pm = &td->td_proc->p_vmspace->vm_pmap;
  298         p = (int *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  299 
  300         if (setfault(env)) {
  301                 td->td_pcb->pcb_onfault = NULL;
  302                 return (-1);
  303         }
  304 
  305         set_user_sr(pm,addr);
  306 
  307         *p = word;
  308 
  309         td->td_pcb->pcb_onfault = NULL;
  310         return (0);
  311 }
  312 #endif
  313 
  314 int
  315 suword(void *addr, long word)
  316 {
  317         struct          thread *td;
  318         pmap_t          pm;
  319         faultbuf        env;
  320         long            *p;
  321 
  322         td = curthread;
  323         pm = &td->td_proc->p_vmspace->vm_pmap;
  324         p = (long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  325 
  326         if (setfault(env)) {
  327                 td->td_pcb->pcb_onfault = NULL;
  328                 return (-1);
  329         }
  330 
  331         set_user_sr(pm,addr);
  332 
  333         *p = word;
  334 
  335         td->td_pcb->pcb_onfault = NULL;
  336         return (0);
  337 }
  338 
  339 #ifdef __powerpc64__
  340 int
  341 suword64(void *addr, int64_t word)
  342 {
  343         return (suword(addr, (long)word));
  344 }
  345 #else
  346 int
  347 suword32(void *addr, int32_t word)
  348 {
  349         return (suword(addr, (long)word));
  350 }
  351 #endif
  352 
  353 int
  354 fubyte(const void *addr)
  355 {
  356         struct          thread *td;
  357         pmap_t          pm;
  358         faultbuf        env;
  359         u_char          *p;
  360         int             val;
  361 
  362         td = curthread;
  363         pm = &td->td_proc->p_vmspace->vm_pmap;
  364         p = (u_char *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  365 
  366         if (setfault(env)) {
  367                 td->td_pcb->pcb_onfault = NULL;
  368                 return (-1);
  369         }
  370 
  371         set_user_sr(pm,addr);
  372 
  373         val = *p;
  374 
  375         td->td_pcb->pcb_onfault = NULL;
  376         return (val);
  377 }
  378 
  379 #ifdef __powerpc64__
  380 int32_t
  381 fuword32(const void *addr)
  382 {
  383         struct          thread *td;
  384         pmap_t          pm;
  385         faultbuf        env;
  386         int32_t         *p, val;
  387 
  388         td = curthread;
  389         pm = &td->td_proc->p_vmspace->vm_pmap;
  390         p = (int32_t *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  391 
  392         if (setfault(env)) {
  393                 td->td_pcb->pcb_onfault = NULL;
  394                 return (-1);
  395         }
  396 
  397         set_user_sr(pm,addr);
  398 
  399         val = *p;
  400 
  401         td->td_pcb->pcb_onfault = NULL;
  402         return (val);
  403 }
  404 #endif
  405 
  406 long
  407 fuword(const void *addr)
  408 {
  409         struct          thread *td;
  410         pmap_t          pm;
  411         faultbuf        env;
  412         long            *p, val;
  413 
  414         td = curthread;
  415         pm = &td->td_proc->p_vmspace->vm_pmap;
  416         p = (long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  417 
  418         if (setfault(env)) {
  419                 td->td_pcb->pcb_onfault = NULL;
  420                 return (-1);
  421         }
  422 
  423         set_user_sr(pm,addr);
  424 
  425         val = *p;
  426 
  427         td->td_pcb->pcb_onfault = NULL;
  428         return (val);
  429 }
  430 
  431 #ifndef __powerpc64__
  432 int32_t
  433 fuword32(const void *addr)
  434 {
  435         return ((int32_t)fuword(addr));
  436 }
  437 #endif
  438 
  439 uint32_t
  440 casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new)
  441 {
  442         struct thread *td;
  443         pmap_t pm;
  444         faultbuf env;
  445         uint32_t *p, val;
  446 
  447         td = curthread;
  448         pm = &td->td_proc->p_vmspace->vm_pmap;
  449         p = (uint32_t *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  450 
  451         set_user_sr(pm,(const void *)(vm_offset_t)addr);
  452 
  453         if (setfault(env)) {
  454                 td->td_pcb->pcb_onfault = NULL;
  455                 return (-1);
  456         }
  457 
  458         __asm __volatile (
  459                 "1:\tlwarx %0, 0, %2\n\t"       /* load old value */
  460                 "cmplw %3, %0\n\t"              /* compare */
  461                 "bne 2f\n\t"                    /* exit if not equal */
  462                 "stwcx. %4, 0, %2\n\t"          /* attempt to store */
  463                 "bne- 1b\n\t"                   /* spin if failed */
  464                 "b 3f\n\t"                      /* we've succeeded */
  465                 "2:\n\t"
  466                 "stwcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
  467                 "3:\n\t"
  468                 : "=&r" (val), "=m" (*p)
  469                 : "r" (p), "r" (old), "r" (new), "m" (*p)
  470                 : "cc", "memory");
  471 
  472         td->td_pcb->pcb_onfault = NULL;
  473 
  474         return (val);
  475 }
  476 
  477 #ifndef __powerpc64__
  478 u_long
  479 casuword(volatile u_long *addr, u_long old, u_long new)
  480 {
  481         return (casuword32((volatile uint32_t *)addr, old, new));
  482 }
  483 #else
  484 u_long
  485 casuword(volatile u_long *addr, u_long old, u_long new)
  486 {
  487         struct thread *td;
  488         pmap_t pm;
  489         faultbuf env;
  490         u_long *p, val;
  491 
  492         td = curthread;
  493         pm = &td->td_proc->p_vmspace->vm_pmap;
  494         p = (u_long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK));
  495 
  496         set_user_sr(pm,(const void *)(vm_offset_t)addr);
  497 
  498         if (setfault(env)) {
  499                 td->td_pcb->pcb_onfault = NULL;
  500                 return (-1);
  501         }
  502 
  503         __asm __volatile (
  504                 "1:\tldarx %0, 0, %2\n\t"       /* load old value */
  505                 "cmpld %3, %0\n\t"              /* compare */
  506                 "bne 2f\n\t"                    /* exit if not equal */
  507                 "stdcx. %4, 0, %2\n\t"          /* attempt to store */
  508                 "bne- 1b\n\t"                   /* spin if failed */
  509                 "b 3f\n\t"                      /* we've succeeded */
  510                 "2:\n\t"
  511                 "stdcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
  512                 "3:\n\t"
  513                 : "=&r" (val), "=m" (*p)
  514                 : "r" (p), "r" (old), "r" (new), "m" (*p)
  515                 : "cc", "memory");
  516 
  517         td->td_pcb->pcb_onfault = NULL;
  518 
  519         return (val);
  520 }
  521 #endif
  522 

Cache object: b3252ce9962db07ad3f11ba2f234489f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.