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.10 2005/02/26 21:34:55 perry 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.10 2005/02/26 21:34:55 perry 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 #define MAX_RAS_PER_PROC        16
   57 
   58 u_int ras_per_proc = MAX_RAS_PER_PROC;
   59 
   60 #ifdef DEBUG
   61 int ras_debug = 0;
   62 #define DPRINTF(x)      if (ras_debug) printf x
   63 #else
   64 #define DPRINTF(x)      /* nothing */
   65 #endif
   66 
   67 int ras_install(struct proc *, caddr_t, size_t);
   68 int ras_purge(struct proc *, caddr_t, size_t);
   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 /*
  192  * Install the new sequence.  If it already exists, return
  193  * an error.
  194  */
  195 int
  196 ras_install(struct proc *p, caddr_t addr, size_t len)
  197 {
  198         struct ras *rp;
  199         struct ras *newrp;
  200         caddr_t endaddr = addr + len;
  201         int nras = 0;
  202 
  203         if (addr < (caddr_t)VM_MIN_ADDRESS ||
  204             endaddr > (caddr_t)VM_MAXUSER_ADDRESS)
  205                 return (EINVAL);
  206 
  207         if (len <= 0)
  208                 return (EINVAL);
  209 
  210         newrp = NULL;
  211 again:
  212         simple_lock(&p->p_lock);
  213         LIST_FOREACH(rp, &p->p_raslist, ras_list) {
  214                 if (++nras >= ras_per_proc ||
  215                     (addr < rp->ras_endaddr && endaddr > rp->ras_startaddr)) {
  216                         simple_unlock(&p->p_lock);
  217                         return (EINVAL);
  218                 }
  219         }
  220         if (newrp == NULL) {
  221                 simple_unlock(&p->p_lock);
  222                 newrp = pool_get(&ras_pool, PR_WAITOK);
  223                 goto again;
  224         }
  225         newrp->ras_startaddr = addr;
  226         newrp->ras_endaddr = endaddr;
  227         newrp->ras_hits = 0;
  228         LIST_INSERT_HEAD(&p->p_raslist, newrp, ras_list);
  229         simple_unlock(&p->p_lock);
  230 
  231         return (0);
  232 }
  233 
  234 /*
  235  * Nuke the specified sequence.  Both address and len must
  236  * match, otherwise we return an error.
  237  */
  238 int
  239 ras_purge(struct proc *p, caddr_t addr, size_t len)
  240 {
  241         struct ras *rp;
  242         caddr_t endaddr = addr + len;
  243         int error = ESRCH;
  244 
  245         simple_lock(&p->p_lock);
  246         LIST_FOREACH(rp, &p->p_raslist, ras_list) {
  247                 if (addr == rp->ras_startaddr && endaddr == rp->ras_endaddr) {
  248                         LIST_REMOVE(rp, ras_list);
  249                         pool_put(&ras_pool, rp);
  250                         error = 0;
  251                         break;
  252                 }
  253         }
  254         simple_unlock(&p->p_lock);
  255 
  256         return (error);
  257 }
  258 
  259 /*ARGSUSED*/
  260 int
  261 sys_rasctl(struct lwp *l, void *v, register_t *retval)
  262 {
  263 
  264 #if defined(__HAVE_RAS)
  265 
  266         struct sys_rasctl_args /* {
  267                 syscallarg(caddr_t) addr;
  268                 syscallarg(size_t) len;
  269                 syscallarg(int) op;
  270         } */ *uap = v;
  271         struct proc *p = l->l_proc;
  272         caddr_t addr;
  273         size_t len;
  274         int op;
  275         int error;
  276 
  277         /*
  278          * first, extract syscall args from the uap.
  279          */
  280 
  281         addr = (caddr_t)SCARG(uap, addr);
  282         len = (size_t)SCARG(uap, len);
  283         op = SCARG(uap, op);
  284 
  285         DPRINTF(("sys_rasctl: p=%p addr=%p, len=%ld, op=0x%x\n",
  286             p, addr, (long)len, op));
  287 
  288         switch (op) {
  289         case RAS_INSTALL:
  290                 error = ras_install(p, addr, len);
  291                 break;
  292         case RAS_PURGE:
  293                 error = ras_purge(p, addr, len);
  294                 break;
  295         case RAS_PURGE_ALL:
  296                 error = ras_purgeall(p);
  297                 break;
  298         default:
  299                 error = EINVAL;
  300                 break;
  301         }
  302 
  303         return (error);
  304 
  305 #else
  306 
  307         return (EOPNOTSUPP);
  308 
  309 #endif
  310 
  311 }

Cache object: 46a0e3a4435cb95b7f2b5e9af0580cf1


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