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/kern/kern_ras.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 /*      $NetBSD: kern_ras.c,v 1.15 2006/11/01 10:17:58 yamt Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Gregory McGarry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: kern_ras.c,v 1.15 2006/11/01 10:17:58 yamt Exp $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/lock.h>
   44 #include <sys/systm.h>
   45 #include <sys/pool.h>
   46 #include <sys/proc.h>
   47 #include <sys/ras.h>
   48 #include <sys/sa.h>
   49 #include <sys/savar.h>
   50 
   51 #include <sys/mount.h>
   52 #include <sys/syscallargs.h>
   53 
   54 #include <uvm/uvm_extern.h>
   55 
   56 POOL_INIT(ras_pool, sizeof(struct ras), 0, 0, 0, "raspl",
   57     &pool_allocator_nointr);
   58 
   59 #define MAX_RAS_PER_PROC        16
   60 
   61 u_int ras_per_proc = MAX_RAS_PER_PROC;
   62 
   63 #ifdef DEBUG
   64 int ras_debug = 0;
   65 #define DPRINTF(x)      if (ras_debug) printf x
   66 #else
   67 #define DPRINTF(x)      /* nothing */
   68 #endif
   69 
   70 /*
   71  * Check the specified address to see if it is within the
   72  * sequence.  If it is found, we return the restart address,
   73  * otherwise we return -1.  If we do perform a restart, we
   74  * mark the sequence as hit.
   75  */
   76 caddr_t
   77 ras_lookup(struct proc *p, caddr_t addr)
   78 {
   79         struct ras *rp;
   80 
   81 #ifdef DIAGNOSTIC
   82         if (addr < (caddr_t)VM_MIN_ADDRESS ||
   83             addr > (caddr_t)VM_MAXUSER_ADDRESS)
   84                 return ((caddr_t)-1);
   85 #endif
   86 
   87         simple_lock(&p->p_lock);
   88         LIST_FOREACH(rp, &p->p_raslist, ras_list) {
   89                 if (addr > rp->ras_startaddr && addr < rp->ras_endaddr) {
   90                         rp->ras_hits++;
   91                         simple_unlock(&p->p_lock);
   92 #ifdef DIAGNOSTIC
   93                         DPRINTF(("RAS hit: p=%p %p\n", p, addr));
   94 #endif
   95                         return (rp->ras_startaddr);
   96                 }
   97         }
   98         simple_unlock(&p->p_lock);
   99 
  100         return ((caddr_t)-1);
  101 }
  102 
  103 /*
  104  * During a fork, we copy all of the sequences from parent p1 to
  105  * the child p2.
  106  */
  107 int
  108 ras_fork(struct proc *p1, struct proc *p2)
  109 {
  110         struct ras *rp, *nrp;
  111         int nras;
  112 
  113 again:
  114         /*
  115          * first, try to shortcut.
  116          */
  117 
  118         if (LIST_EMPTY(&p1->p_raslist))
  119                 return (0);
  120 
  121         /*
  122          * count entries.
  123          */
  124 
  125         nras = 0;
  126         simple_lock(&p1->p_lock);
  127         LIST_FOREACH(rp, &p1->p_raslist, ras_list)
  128                 nras++;
  129         simple_unlock(&p1->p_lock);
  130 
  131         /*
  132          * allocate entries.
  133          */
  134 
  135         for ( ; nras > 0; nras--) {
  136                 nrp = pool_get(&ras_pool, PR_WAITOK);
  137                 nrp->ras_hits = 0;
  138                 LIST_INSERT_HEAD(&p2->p_raslist, nrp, ras_list);
  139         }
  140 
  141         /*
  142          * copy entries.
  143          */
  144 
  145         simple_lock(&p1->p_lock);
  146         nrp = LIST_FIRST(&p2->p_raslist);
  147         LIST_FOREACH(rp, &p1->p_raslist, ras_list) {
  148                 if (nrp == NULL)
  149                         break;
  150                 nrp->ras_startaddr = rp->ras_startaddr;
  151                 nrp->ras_endaddr = rp->ras_endaddr;
  152                 nrp = LIST_NEXT(nrp, ras_list);
  153         }
  154         simple_unlock(&p1->p_lock);
  155 
  156         /*
  157          * if we lose a race, retry.
  158          */
  159 
  160         if (rp != NULL || nrp != NULL) {
  161                 ras_purgeall(p2);
  162                 goto again;
  163         }
  164 
  165         DPRINTF(("ras_fork: p1=%p, p2=%p, nras=%d\n", p1, p2, nras));
  166 
  167         return (0);
  168 }
  169 
  170 /*
  171  * Nuke all sequences for this process.
  172  */
  173 int
  174 ras_purgeall(struct proc *p)
  175 {
  176         struct ras *rp;
  177 
  178         simple_lock(&p->p_lock);
  179         while (!LIST_EMPTY(&p->p_raslist)) {
  180                 rp = LIST_FIRST(&p->p_raslist);
  181                 DPRINTF(("RAS %p-%p, hits %d\n", rp->ras_startaddr,
  182                     rp->ras_endaddr, rp->ras_hits));
  183                 LIST_REMOVE(rp, ras_list);
  184                 pool_put(&ras_pool, rp);
  185         }
  186         simple_unlock(&p->p_lock);
  187 
  188         return (0);
  189 }
  190 
  191 #if defined(__HAVE_RAS)
  192 
  193 /*
  194  * Install the new sequence.  If it already exists, return
  195  * an error.
  196  */
  197 static int
  198 ras_install(struct proc *p, caddr_t addr, size_t len)
  199 {
  200         struct ras *rp;
  201         struct ras *newrp;
  202         caddr_t endaddr = addr + len;
  203         int nras = 0;
  204 
  205         if (addr < (caddr_t)VM_MIN_ADDRESS ||
  206             endaddr > (caddr_t)VM_MAXUSER_ADDRESS)
  207                 return (EINVAL);
  208 
  209         if (len <= 0)
  210                 return (EINVAL);
  211 
  212         newrp = NULL;
  213 again:
  214         simple_lock(&p->p_lock);
  215         LIST_FOREACH(rp, &p->p_raslist, ras_list) {
  216                 if (++nras >= ras_per_proc ||
  217                     (addr < rp->ras_endaddr && endaddr > rp->ras_startaddr)) {
  218                         simple_unlock(&p->p_lock);
  219                         return (EINVAL);
  220                 }
  221         }
  222         if (newrp == NULL) {
  223                 simple_unlock(&p->p_lock);
  224                 newrp = pool_get(&ras_pool, PR_WAITOK);
  225                 goto again;
  226         }
  227         newrp->ras_startaddr = addr;
  228         newrp->ras_endaddr = endaddr;
  229         newrp->ras_hits = 0;
  230         LIST_INSERT_HEAD(&p->p_raslist, newrp, ras_list);
  231         simple_unlock(&p->p_lock);
  232 
  233         return (0);
  234 }
  235 
  236 /*
  237  * Nuke the specified sequence.  Both address and len must
  238  * match, otherwise we return an error.
  239  */
  240 static int
  241 ras_purge(struct proc *p, caddr_t addr, size_t len)
  242 {
  243         struct ras *rp;
  244         caddr_t endaddr = addr + len;
  245         int error = ESRCH;
  246 
  247         simple_lock(&p->p_lock);
  248         LIST_FOREACH(rp, &p->p_raslist, ras_list) {
  249                 if (addr == rp->ras_startaddr && endaddr == rp->ras_endaddr) {
  250                         LIST_REMOVE(rp, ras_list);
  251                         pool_put(&ras_pool, rp);
  252                         error = 0;
  253                         break;
  254                 }
  255         }
  256         simple_unlock(&p->p_lock);
  257 
  258         return (error);
  259 }
  260 
  261 #endif /* defined(__HAVE_RAS) */
  262 
  263 /*ARGSUSED*/
  264 int
  265 sys_rasctl(struct lwp *l, void *v, register_t *retval)
  266 {
  267 
  268 #if defined(__HAVE_RAS)
  269 
  270         struct sys_rasctl_args /* {
  271                 syscallarg(caddr_t) addr;
  272                 syscallarg(size_t) len;
  273                 syscallarg(int) op;
  274         } */ *uap = v;
  275         struct proc *p = l->l_proc;
  276         caddr_t addr;
  277         size_t len;
  278         int op;
  279         int error;
  280 
  281         /*
  282          * first, extract syscall args from the uap.
  283          */
  284 
  285         addr = (caddr_t)SCARG(uap, addr);
  286         len = (size_t)SCARG(uap, len);
  287         op = SCARG(uap, op);
  288 
  289         DPRINTF(("sys_rasctl: p=%p addr=%p, len=%ld, op=0x%x\n",
  290             p, addr, (long)len, op));
  291 
  292         switch (op) {
  293         case RAS_INSTALL:
  294                 error = ras_install(p, addr, len);
  295                 break;
  296         case RAS_PURGE:
  297                 error = ras_purge(p, addr, len);
  298                 break;
  299         case RAS_PURGE_ALL:
  300                 error = ras_purgeall(p);
  301                 break;
  302         default:
  303                 error = EINVAL;
  304                 break;
  305         }
  306 
  307         return (error);
  308 
  309 #else
  310 
  311         return (EOPNOTSUPP);
  312 
  313 #endif
  314 
  315 }

Cache object: 64f4ef5e0d34ce38b900b7a0e52f47a3


[ 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.