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_lkm.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_lkm.c,v 1.83.2.1 2005/04/13 16:01:38 tron Exp $   */
    2 
    3 /*
    4  * Copyright (c) 1994 Christopher G. Demetriou
    5  * Copyright (c) 1992 Terrence R. Lambert.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by Terrence R. Lambert.
   19  * 4. The name Terrence R. Lambert may not be used to endorse or promote
   20  *    products derived from this software without specific prior written
   21  *    permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
   24  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 /*
   37  * XXX it's not really safe to unload *any* of the types which are
   38  * currently loadable; e.g. you could unload a syscall which was being
   39  * blocked in, etc.  In the long term, a solution should be come up
   40  * with, but "not right now." -- cgd
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: kern_lkm.c,v 1.83.2.1 2005/04/13 16:01:38 tron Exp $");
   45 
   46 #include "opt_ddb.h"
   47 #include "opt_malloclog.h"
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/ioctl.h>
   52 #include <sys/tty.h>
   53 #include <sys/file.h>
   54 #include <sys/proc.h>
   55 #include <sys/uio.h>
   56 #include <sys/kernel.h>
   57 #include <sys/vnode.h>
   58 #include <sys/malloc.h>
   59 #include <sys/mount.h>
   60 #include <sys/exec.h>
   61 #include <sys/sa.h>
   62 #include <sys/syscallargs.h>
   63 #include <sys/conf.h>
   64 #include <sys/ksyms.h>
   65 #include <sys/device.h>
   66 
   67 #include <sys/lkm.h>
   68 #include <sys/syscall.h>
   69 #ifdef DDB
   70 #include <machine/db_machdep.h>
   71 #include <ddb/db_sym.h>
   72 #endif
   73 
   74 #include <uvm/uvm_extern.h>
   75 
   76 struct vm_map *lkm_map;
   77 
   78 #define LKM_SPACE_ALLOC(size)           uvm_km_alloc(lkm_map, (size))
   79 #define LKM_SPACE_FREE(addr, size)      uvm_km_free(lkm_map, (addr), (size))
   80 
   81 #if !defined(DEBUG) && defined(LKMDEBUG)
   82 # define DEBUG
   83 #endif
   84 
   85 #ifdef DEBUG
   86 # define LKMDB_INFO     0x01
   87 # define LKMDB_LOAD     0x02
   88 int     lkmdebug = 0;
   89 #endif
   90 
   91 #define LKM_ALLOC       0x01
   92 
   93 #define LKMS_IDLE       0x00
   94 #define LKMS_RESERVED   0x01
   95 #define LKMS_LOADING    0x02
   96 #define LKMS_UNLOADING  0x08
   97 
   98 static int      lkm_v = 0;
   99 static int      lkm_state = LKMS_IDLE;
  100 
  101 static TAILQ_HEAD(lkms_head, lkm_table) lkmods; /* table of loaded modules */
  102 static struct lkm_table *curp;                  /* global for in-progress ops */
  103 
  104 static struct lkm_table *lkmlookup(int, char *, int, int *);
  105 static struct lkm_table *lkmalloc(void);
  106 static void lkmfree(void);
  107 static void lkmunreserve(int);
  108 static int _lkm_syscall(struct lkm_table *, int);
  109 static int _lkm_vfs(struct lkm_table *, int);
  110 static int _lkm_dev(struct lkm_table *, int);
  111 #ifdef STREAMS
  112 static int _lkm_strmod(struct lkm_table *, int);
  113 #endif
  114 static int _lkm_exec(struct lkm_table *, int);
  115 static int _lkm_compat(struct lkm_table *, int);
  116 static int _lkm_drv(struct lkm_table *, int);
  117 
  118 static int _lkm_checkver(struct lkm_table *);
  119 
  120 dev_type_open(lkmopen);
  121 dev_type_close(lkmclose);
  122 dev_type_ioctl(lkmioctl);
  123 
  124 const struct cdevsw lkm_cdevsw = {
  125         lkmopen, lkmclose, noread, nowrite, lkmioctl,
  126         nostop, notty, nopoll, nommap, nokqfilter,
  127 };
  128 
  129 void
  130 lkm_init(void)
  131 {
  132         /*
  133          * If machine-dependent code hasn't initialized the lkm_map
  134          * then just use kernel_map.
  135          */
  136         if (lkm_map == NULL)
  137                 lkm_map = kernel_map;
  138 
  139         TAILQ_INIT(&lkmods);
  140 }
  141 
  142 /*ARGSUSED*/
  143 int
  144 lkmopen(dev_t dev, int flag, int devtype, struct proc *p)
  145 {
  146         int error;
  147 
  148         if (minor(dev) != 0)
  149                 return (ENXIO);         /* bad minor # */
  150 
  151         /*
  152          * Use of the loadable kernel module device must be exclusive; we
  153          * may try to remove this restriction later, but it's really no
  154          * hardship.
  155          */
  156         while (lkm_v & LKM_ALLOC) {
  157                 if (flag & FNONBLOCK)           /* don't hang */
  158                         return (EBUSY);
  159                 /*
  160                  * Sleep pending unlock; we use tsleep() to allow
  161                  * an alarm out of the open.
  162                  */
  163                 error = tsleep((caddr_t)&lkm_v, TTIPRI|PCATCH, "lkmopn", 0);
  164                 if (error)
  165                         return (error);
  166         }
  167         lkm_v |= LKM_ALLOC;
  168 
  169         return (0);             /* pseudo-device open */
  170 }
  171 
  172 /*
  173  * Look up for a LKM in the list.
  174  */
  175 static struct lkm_table *
  176 lkmlookup(int i, char *name, int need_copyin, int *error)
  177 {
  178         struct lkm_table *p;
  179         char istr[MAXLKMNAME];
  180 
  181         /*
  182          * p being NULL here implies the list is empty, so any lookup is
  183          * invalid (name based or otherwise). Since the list of modules is
  184          * kept sorted by id, lowest to highest, the id of the last entry
  185          * will be the highest in use.
  186          */
  187         p = TAILQ_LAST(&lkmods, lkms_head);
  188         if (p == NULL || i > p->id) {
  189                 *error = EINVAL;
  190                 return (NULL);
  191         }
  192 
  193         if (i < 0) {            /* unload by name */
  194                 /*
  195                  * Copy name and lookup id from all loaded
  196                  * modules.  May fail.
  197                  */
  198                 if (need_copyin) {
  199                         *error = copyinstr(name, istr, MAXLKMNAME - 1, NULL);
  200                         if (*error)
  201                                 return (NULL);
  202                 } else
  203                         strncpy(istr, name, MAXLKMNAME - 1);
  204                 istr[MAXLKMNAME - 1] = '\0';
  205 
  206                 TAILQ_FOREACH(p, &lkmods, link) {
  207                         if (strcmp(istr, p->private.lkm_any->lkm_name) == 0)
  208                                 break;
  209                 }
  210         } else
  211                 TAILQ_FOREACH(p, &lkmods, link)
  212                         if (i == p->id)
  213                                 break;
  214 
  215         if (p == NULL)
  216                 *error = ENOENT;
  217 
  218         return (p);
  219 }
  220 
  221 /*
  222  * Allocates memory for a new LKM table entry and inserts in the list.
  223  * Returns NULL on failure.
  224  */
  225 static struct lkm_table *
  226 lkmalloc(void)
  227 {
  228         struct lkm_table *p, *ret;
  229         int id = 0;
  230 
  231         ret = malloc(sizeof(struct lkm_table), M_DEVBUF, M_NOWAIT);
  232         if (ret == NULL)
  233                 return (NULL);
  234         ret->refcnt = 0;
  235         ret->forced = 0;
  236 
  237         /* find the first unused id */
  238         TAILQ_FOREACH(p, &lkmods, link) {
  239                 if (id != p->id)
  240                         break;
  241                 id++;
  242         }
  243         ret->id = id;
  244 
  245         if (p == NULL)
  246                 TAILQ_INSERT_TAIL(&lkmods, ret, link);
  247         else
  248                 TAILQ_INSERT_BEFORE(p, ret, link);
  249 
  250         return (ret);
  251 }
  252 
  253 /*
  254  * Frees the current LKM table entry.
  255  */
  256 static void
  257 lkmfree(void)
  258 {
  259         TAILQ_REMOVE(&lkmods, curp, link);
  260         free(curp, M_DEVBUF);
  261         curp = NULL;
  262 }
  263 
  264 /*
  265  * Unreserve the memory associated with the current loaded module; done on
  266  * a coerced close of the lkm device (close on premature exit of modload)
  267  * or explicitly by modload as a result of a link failure.
  268  */
  269 static void
  270 lkmunreserve(int delsymtab)
  271 {
  272 
  273         if (lkm_state == LKMS_IDLE)
  274                 return;
  275 
  276         if (curp && curp->syms) {
  277                 if (delsymtab)
  278                         ksyms_delsymtab(curp->private.lkm_any->lkm_name);
  279                 LKM_SPACE_FREE(curp->syms, curp->sym_size);
  280                 curp->syms = 0;
  281         }
  282         /*
  283          * Actually unreserve the memory
  284          */
  285         if (curp && curp->area) {
  286                 LKM_SPACE_FREE(curp->area, curp->size);
  287                 curp->area = 0;
  288         }
  289 
  290         if (curp && curp->forced)
  291                 curp->forced = 0;
  292 
  293         lkm_state = LKMS_IDLE;
  294 }
  295 
  296 int
  297 lkmclose(dev_t dev, int flag, int mode, struct proc *p)
  298 {
  299 
  300         if (!(lkm_v & LKM_ALLOC)) {
  301 #ifdef DEBUG
  302                 if (lkmdebug & LKMDB_INFO)
  303                         printf("LKM: close before open!\n");
  304 #endif  /* DEBUG */
  305                 return (EBADF);
  306         }
  307 
  308         /* do this before waking the herd... */
  309         if (curp != NULL && curp->refcnt == 0) {
  310                 /*
  311                  * If we close before setting used, we have aborted
  312                  * by way of error or by way of close-on-exit from
  313                  * a premature exit of "modload".
  314                  */
  315                 lkmunreserve(1);        /* coerce state to LKM_IDLE */
  316                 lkmfree();
  317         }
  318 
  319         lkm_v &= ~LKM_ALLOC;
  320         wakeup((caddr_t)&lkm_v);        /* thundering herd "problem" here */
  321 
  322         return (0);             /* pseudo-device closed */
  323 }
  324 
  325 /*ARGSUSED*/
  326 int
  327 lkmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  328 {
  329         int i, error = 0;
  330         struct lmc_resrv *resrvp;
  331         struct lmc_loadbuf *loadbufp;
  332         struct lmc_unload *unloadp;
  333         struct lmc_stat  *statp;
  334 
  335         switch(cmd) {
  336         case LMRESERV:          /* reserve pages for a module */
  337                 if (securelevel > 0)
  338                         return EPERM;
  339 
  340                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  341                         return EPERM;
  342 
  343                 resrvp = (struct lmc_resrv *)data;
  344 
  345                 curp = lkmalloc();
  346                 if (curp == NULL) {
  347                         error = ENOMEM;
  348                         break;
  349                 }
  350                 resrvp->slot = curp->id;        /* return slot */
  351 
  352                 /*
  353                  * Get memory for module
  354                  */
  355                 curp->size = resrvp->size;
  356                 curp->area = LKM_SPACE_ALLOC(curp->size);
  357                 curp->offset = 0;               /* load offset */
  358 
  359                 resrvp->addr = curp->area;      /* ret kernel addr */
  360 
  361                 if (resrvp->sym_size) {
  362                         curp->sym_size = resrvp->sym_size;
  363                         curp->sym_symsize = resrvp->sym_symsize;
  364                         curp->syms = (u_long) LKM_SPACE_ALLOC(curp->sym_size);
  365                         curp->sym_offset = 0;
  366                         resrvp->sym_addr = curp->syms; /* ret symbol addr */
  367                 } else {
  368                         curp->sym_size = 0;
  369                         curp->syms = 0;
  370                         curp->sym_offset = 0;
  371                         resrvp->sym_addr = 0;
  372                 }
  373 
  374 #ifdef DEBUG
  375                 if (lkmdebug & LKMDB_INFO) {
  376                         printf("LKM: LMRESERV (actual   = 0x%08lx)\n",
  377                             curp->area);
  378                         printf("LKM: LMRESERV (syms     = 0x%08lx)\n",
  379                                curp->syms);
  380                         printf("LKM: LMRESERV (adjusted = 0x%08lx)\n",
  381                             trunc_page(curp->area));
  382                 }
  383 #endif /* DEBUG */
  384                 lkm_state = LKMS_RESERVED;
  385                 break;
  386 
  387         case LMLOADBUF:         /* Copy in; stateful, follows LMRESERV */
  388                 if (securelevel > 0)
  389                         return EPERM;
  390 
  391                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  392                         return EPERM;
  393 
  394                 loadbufp = (struct lmc_loadbuf *)data;
  395                 i = loadbufp->cnt;
  396                 if ((lkm_state != LKMS_RESERVED && lkm_state != LKMS_LOADING)
  397                     || i < 0
  398                     || i > MODIOBUF
  399                     || i > curp->size - curp->offset) {
  400                         error = ENOMEM;
  401                         break;
  402                 }
  403 
  404                 /* copy in buffer full of data */
  405                 error = copyin(loadbufp->data,
  406                                (caddr_t)curp->area + curp->offset, i);
  407                 if (error)
  408                         break;
  409 
  410                 if ((curp->offset + i) < curp->size) {
  411                         lkm_state = LKMS_LOADING;
  412 #ifdef DEBUG
  413                         if (lkmdebug & LKMDB_LOAD)
  414                 printf("LKM: LMLOADBUF (loading @ %ld of %ld, i = %d)\n",
  415                             curp->offset, curp->size, i);
  416 #endif /* DEBUG */
  417                 }
  418                 curp->offset += i;
  419                 break;
  420 
  421         case LMLOADSYMS:        /* Copy in; stateful, follows LMRESERV*/
  422                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  423                         return EPERM;
  424 
  425                 loadbufp = (struct lmc_loadbuf *)data;
  426                 i = loadbufp->cnt;
  427                 if ((lkm_state != LKMS_LOADING)
  428                     || i < 0
  429                     || i > MODIOBUF
  430                     || i > curp->sym_size - curp->sym_offset) {
  431                         error = ENOMEM;
  432                         break;
  433                 }
  434 
  435                 /* copy in buffer full of data*/
  436                 if ((error = copyin(loadbufp->data,
  437                                    (caddr_t)(curp->syms) + curp->sym_offset,
  438                                    i)) != 0)
  439                         break;
  440 
  441                 if ((curp->sym_offset + i) < curp->sym_size) {
  442                         lkm_state = LKMS_LOADING;
  443 #ifdef DEBUG
  444                         if (lkmdebug & LKMDB_LOAD)
  445                 printf( "LKM: LMLOADSYMS (loading @ %ld of %ld, i = %d)\n",
  446                         curp->sym_offset, curp->sym_size, i);
  447 #endif  /* DEBUG*/
  448                 }
  449                 curp->sym_offset += i;
  450                 break;
  451 
  452         case LMUNRESRV:         /* discard reserved pages for a module */
  453                 if (securelevel > 0)
  454                         return EPERM;
  455 
  456                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  457                         return EPERM;
  458 
  459                 lkmunreserve(0);        /* coerce state to LKM_IDLE */
  460                 if (curp != NULL)
  461                         lkmfree();
  462 #ifdef DEBUG
  463                 if (lkmdebug & LKMDB_INFO)
  464                         printf("LKM: LMUNRESERV\n");
  465 #endif /* DEBUG */
  466                 break;
  467 
  468         case LMREADY:           /* module loaded: call entry */
  469                 if (securelevel > 0)
  470                         return EPERM;
  471 
  472                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  473                         return EPERM;
  474 
  475                 if (lkm_state != LKMS_LOADING) {
  476 #ifdef DEBUG
  477                         if (lkmdebug & LKMDB_INFO)
  478                                 printf("lkm_state is %02x\n", lkm_state);
  479 #endif /* DEBUG */
  480                         return ENXIO;
  481                 }
  482 
  483                 if (curp->size - curp->offset > 0) {
  484                         /* The remainder must be bss, so we clear it */
  485                         memset((caddr_t)curp->area + curp->offset, 0,
  486                                curp->size - curp->offset);
  487                 }
  488 
  489 #ifdef DDB
  490                 /*
  491                  * Temporarily load the symbol table before the entry
  492                  * routine is called, so that the symbols are available
  493                  * for DDB backtrace and breakpoints.
  494                  */
  495                 if (curp->syms && curp->sym_offset >= curp->sym_size) {
  496                         error = ksyms_addsymtab("/lkmtemp/",
  497                             (char *)curp->syms, curp->sym_symsize,
  498                             (char *)curp->syms + curp->sym_symsize,
  499                             curp->sym_size - curp->sym_symsize);
  500 
  501                         if (error)
  502                                 goto rdyfail;
  503 
  504 #ifdef DEBUG
  505                         if (lkmdebug & LKMDB_INFO)
  506                                 printf( "DDB symbols added!\n" );
  507 #endif
  508                 }
  509 #endif /* DDB */
  510 
  511                 curp->entry = (int (*)(struct lkm_table *, int, int))
  512                                 (*((long *) (data)));
  513 
  514                 /* call entry(load)... (assigns "private" portion) */
  515                 error = (*(curp->entry))(curp, LKM_E_LOAD, LKM_VERSION);
  516 
  517                 if (curp->syms && curp->sym_offset >= curp->sym_size) {
  518 #ifdef DDB
  519                         ksyms_delsymtab("/lkmtemp/");
  520 #endif
  521 
  522                         if (!error) {
  523                                 error = ksyms_addsymtab(curp->private.lkm_any->lkm_name,
  524                                     (char *)curp->syms, curp->sym_symsize,
  525                                     (char *)curp->syms + curp->sym_symsize,
  526                                     curp->sym_size - curp->sym_symsize);
  527                         }
  528                 }
  529 
  530                 if (error) {
  531 #ifdef DDB
  532     rdyfail:
  533 #endif
  534                         /*
  535                          * Module may refuse loading or may have a
  536                          * version mismatch...
  537                          */
  538                         lkm_state = LKMS_UNLOADING;     /* for lkmunreserve */
  539                         lkmunreserve(0);                /* free memory */
  540                         lkmfree();                      /* free slot */
  541 #ifdef DEBUG
  542                         if (lkmdebug & LKMDB_INFO)
  543                                 printf("lkm entry point failed with error %d\n",
  544                                    error);
  545 #endif /* DEBUG */
  546                         break;
  547                 }
  548                 curp->refcnt++;
  549 
  550 #ifdef DEBUG
  551                 if (lkmdebug & LKMDB_INFO)
  552                         printf("LKM: LMREADY\n");
  553 #endif /* DEBUG */
  554                 lkm_state = LKMS_IDLE;
  555                 break;
  556 
  557         case LMUNLOAD:          /* unload a module */
  558                 if (securelevel > 0)
  559                         return EPERM;
  560 
  561                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  562                         return EPERM;
  563 
  564                 unloadp = (struct lmc_unload *)data;
  565 
  566                 curp = lkmlookup(unloadp->id, unloadp->name, 1, &error);
  567                 if (curp == NULL)
  568                         break;
  569 
  570                 /* call entry(unload) */
  571                 if ((*(curp->entry))(curp, LKM_E_UNLOAD, LKM_VERSION)) {
  572                         error = EBUSY;
  573                         break;
  574                 }
  575 
  576                 lkm_state = LKMS_UNLOADING;     /* non-idle for lkmunreserve */
  577                 lkmunreserve(1);                /* free memory */
  578                 lkmfree();                      /* free slot */
  579                 break;
  580 
  581         case LMSTAT:            /* stat a module by id/name */
  582                 /* allow readers and writers to stat */
  583 
  584                 statp = (struct lmc_stat *)data;
  585 
  586                 if ((curp = lkmlookup(statp->id, statp->name, 0, &error)) == NULL)
  587                         break;
  588 
  589                 if ((error = (*curp->entry)(curp, LKM_E_STAT, LKM_VERSION)))
  590                         break;
  591 
  592                 /*
  593                  * Copy out stat information for this module...
  594                  */
  595                 statp->id       = curp->id;
  596                 statp->offset   = curp->private.lkm_any->lkm_offset;
  597                 statp->type     = curp->private.lkm_any->lkm_type;
  598                 statp->area     = curp->area;
  599                 statp->size     = curp->size / 1024;
  600                 statp->private  = (unsigned long)curp->private.lkm_any;
  601                 statp->ver      = LKM_VERSION;
  602                 copystr(curp->private.lkm_any->lkm_name,
  603                           statp->name,
  604                           MAXLKMNAME - 2,
  605                           (size_t *)0);
  606 
  607                 break;
  608 
  609 #ifdef LMFORCE
  610         case LMFORCE:           /* stateful, optionally follows LMRESERV */
  611                 if (securelevel > 0)
  612                         return EPERM;
  613 
  614                 if ((flag & FWRITE) == 0) /* only allow this if writing */
  615                         return EPERM;
  616 
  617                 if (lkm_state != LKMS_RESERVED) {
  618                         error = EPERM;
  619                         break;
  620                 }
  621 
  622                 curp->forced = (*(u_long *)data != 0);
  623                 break;
  624 #endif /* LMFORCE */
  625 
  626         default:                /* bad ioctl()... */
  627                 error = ENOTTY;
  628                 break;
  629         }
  630 
  631         return (error);
  632 }
  633 
  634 /*
  635  * Acts like "nosys" but can be identified in sysent for dynamic call
  636  * number assignment for a limited number of calls.
  637  *
  638  * Place holder for system call slots reserved for loadable modules.
  639  */
  640 int
  641 sys_lkmnosys(struct lwp *l, void *v, register_t *retval)
  642 {
  643 
  644         return (sys_nosys(l, v, retval));
  645 }
  646 
  647 /*
  648  * A placeholder function for load/unload/stat calls; simply returns zero.
  649  * Used where people don't want to specify a special function.
  650  */
  651 int
  652 lkm_nofunc(struct lkm_table *lkmtp, int cmd)
  653 {
  654 
  655         return (0);
  656 }
  657 
  658 int
  659 lkmexists(struct lkm_table *lkmtp)
  660 {
  661         struct lkm_table *p;
  662 
  663         /* see if name exists... */
  664         TAILQ_FOREACH(p, &lkmods, link) {
  665                 if (strcmp(lkmtp->private.lkm_any->lkm_name,
  666                     p->private.lkm_any->lkm_name) == 0 && (p->refcnt != 0))
  667                         return (1);             /* already loaded... */
  668         }
  669 
  670         return (0);             /* module not loaded... */
  671 }
  672 
  673 /*
  674  * For the loadable system call described by the structure pointed to
  675  * by lkmtp, load/unload/stat it depending on the cmd requested.
  676  */
  677 static int
  678 _lkm_syscall(struct lkm_table *lkmtp, int cmd)
  679 {
  680         struct lkm_syscall *args = lkmtp->private.lkm_syscall;
  681         int i;
  682         int error = 0;
  683 
  684         switch(cmd) {
  685         case LKM_E_LOAD:
  686                 /* don't load twice! */
  687                 if (lkmexists(lkmtp))
  688                         return (EEXIST);
  689 
  690                 if ((i = args->mod.lkm_offset) == -1) { /* auto */
  691                         /*
  692                          * Search the table looking for a slot...
  693                          */
  694                         for (i = 0; i < SYS_MAXSYSCALL; i++)
  695                                 if (sysent[i].sy_call == sys_lkmnosys)
  696                                         break;          /* found it! */
  697                         /* out of allocable slots? */
  698                         if (i == SYS_MAXSYSCALL) {
  699                                 error = ENFILE;
  700                                 break;
  701                         }
  702                 } else {                                /* assign */
  703                         if (i < 0 || i >= SYS_MAXSYSCALL) {
  704                                 error = EINVAL;
  705                                 break;
  706                         }
  707                 }
  708 
  709                 /* save old */
  710                 memcpy(&args->lkm_oldent, &sysent[i], sizeof(struct sysent));
  711 
  712                 /* replace with new */
  713                 memcpy(&sysent[i], args->lkm_sysent, sizeof(struct sysent));
  714 
  715                 /* done! */
  716                 args->mod.lkm_offset = i;       /* slot in sysent[] */
  717 
  718                 break;
  719 
  720         case LKM_E_UNLOAD:
  721                 /* current slot... */
  722                 i = args->mod.lkm_offset;
  723 
  724                 /* replace current slot contents with old contents */
  725                 memcpy(&sysent[i], &args->lkm_oldent, sizeof(struct sysent));
  726 
  727                 break;
  728 
  729         case LKM_E_STAT:        /* no special handling... */
  730                 break;
  731         }
  732 
  733         return (error);
  734 }
  735 
  736 /*
  737  * For the loadable virtual file system described by the structure pointed
  738  * to by lkmtp, load/unload/stat it depending on the cmd requested.
  739  */
  740 static int
  741 _lkm_vfs(struct lkm_table *lkmtp, int cmd)
  742 {
  743         struct lkm_vfs *args = lkmtp->private.lkm_vfs;
  744         int error = 0;
  745 
  746         switch(cmd) {
  747         case LKM_E_LOAD:
  748                 /* don't load twice! */
  749                 if (lkmexists(lkmtp))
  750                         return (EEXIST);
  751 
  752                 /* Establish the file system. */
  753                 if ((error = vfs_attach(args->lkm_vfsops)) != 0)
  754                         return (error);
  755 
  756                 /* done! */
  757                 break;
  758 
  759         case LKM_E_UNLOAD:
  760                 /* Disestablish the file system. */
  761                 if ((error = vfs_detach(args->lkm_vfsops)) != 0)
  762                         return (error);
  763                 break;
  764 
  765         case LKM_E_STAT:        /* no special handling... */
  766                 break;
  767         }
  768 
  769         return (error);
  770 }
  771 
  772 /*
  773  * For the loadable device driver described by the structure pointed to
  774  * by lkmtp, load/unload/stat it depending on the cmd requested.
  775  */
  776 static int
  777 _lkm_dev(struct lkm_table *lkmtp, int cmd)
  778 {
  779         struct lkm_dev *args = lkmtp->private.lkm_dev;
  780         int error;
  781 
  782         switch(cmd) {
  783         case LKM_E_LOAD:
  784                 /* don't load twice! */
  785                 if (lkmexists(lkmtp))
  786                         return (EEXIST);
  787 
  788                 error = devsw_attach(args->lkm_devname,
  789                                      args->lkm_bdev, &args->lkm_bdevmaj,
  790                                      args->lkm_cdev, &args->lkm_cdevmaj);
  791                 if (error != 0)
  792                         return (error);
  793 
  794                 args->mod.lkm_offset =
  795                         LKM_MAKEMAJOR(args->lkm_bdevmaj, args->lkm_cdevmaj);
  796                 break;
  797 
  798         case LKM_E_UNLOAD:
  799                 devsw_detach(args->lkm_bdev, args->lkm_cdev);
  800                 args->lkm_bdevmaj = -1;
  801                 args->lkm_cdevmaj = -1;
  802                 break;
  803 
  804         case LKM_E_STAT:        /* no special handling... */
  805                 break;
  806         }
  807 
  808         return (0);
  809 }
  810 
  811 #ifdef STREAMS
  812 /*
  813  * For the loadable streams module described by the structure pointed to
  814  * by lkmtp, load/unload/stat it depending on the cmd requested.
  815  */
  816 static int
  817 _lkm_strmod(struct lkm_table *lkmtp, int cmd)
  818 {
  819         struct lkm_strmod *args = lkmtp->private.lkm_strmod;
  820         int i;
  821         int error = 0;
  822 
  823         switch(cmd) {
  824         case LKM_E_LOAD:
  825                 /* don't load twice! */
  826                 if (lkmexists(lkmtp))
  827                         return (EEXIST);
  828                 break;
  829 
  830         case LKM_E_UNLOAD:
  831                 break;
  832 
  833         case LKM_E_STAT:        /* no special handling... */
  834                 break;
  835         }
  836 
  837         return (error);
  838 }
  839 #endif  /* STREAMS */
  840 
  841 /*
  842  * For the loadable execution class described by the structure pointed to
  843  * by lkmtp, load/unload/stat it depending on the cmd requested.
  844  */
  845 static int
  846 _lkm_exec(struct lkm_table *lkmtp, int cmd)
  847 {
  848         struct lkm_exec *args = lkmtp->private.lkm_exec;
  849         int error = 0;
  850 
  851         switch(cmd) {
  852         case LKM_E_LOAD:
  853                 /* don't load twice! */
  854                 if (lkmexists(lkmtp))
  855                         return (EEXIST);
  856 
  857                 /* this would also fill in the emulation pointer in
  858                  * args->lkm_execsw */
  859                 error = exec_add(args->lkm_execsw, args->lkm_emul);
  860                 break;
  861 
  862         case LKM_E_UNLOAD:
  863                 error = exec_remove(args->lkm_execsw);
  864                 break;
  865 
  866         case LKM_E_STAT:        /* no special handling... */
  867                 break;
  868         }
  869 
  870         return (error);
  871 }
  872 
  873 /*
  874  * For the loadable compat/emulation class described by the structure pointed to
  875  * by lkmtp, load/unload/stat it depending on the cmd requested.
  876  */
  877 static int
  878 _lkm_compat(struct lkm_table *lkmtp, int cmd)
  879 {
  880         struct lkm_compat *args = lkmtp->private.lkm_compat;
  881         int error = 0;
  882 
  883         switch(cmd) {
  884         case LKM_E_LOAD:
  885                 /* don't load twice! */
  886                 if (lkmexists(lkmtp))
  887                         return (EEXIST);
  888 
  889                 error = emul_register(args->lkm_compat, 0);
  890                 break;
  891 
  892         case LKM_E_UNLOAD:
  893                 error = emul_unregister(args->lkm_compat->e_name);
  894                 break;
  895 
  896         case LKM_E_STAT:        /* no special handling... */
  897                 break;
  898         }
  899 
  900         return (error);
  901 }
  902 
  903 static int
  904 drvlkm_load(struct cfdriver **cd, const struct cfattachlkminit *cai,
  905             struct cfdata *cf)
  906 {
  907         const struct cfattachlkminit *cfai;
  908         int i, error, j;
  909 
  910         for (i = 0; cd[i]; i++) {
  911                 error = config_cfdriver_attach(cd[i]);
  912                 if (!error)
  913                         continue;
  914                 if (error != EEXIST) {
  915                         printf("%s: unable to register driver\n",
  916                                cd[i]->cd_name);
  917                         /* XXX roll back previous attachments */
  918                         goto out;
  919                 }
  920                 printf("driver %s already present\n", cd[i]->cd_name);
  921                 /*
  922                  * get existing drivers out of the list so we won't try
  923                  * to detach them
  924                  */
  925                 for (j = i; cd[j]; j++)
  926                         cd[j] = cd[j + 1];
  927                 i--; /* continue at same index */
  928         }
  929 
  930         for (cfai = cai; cfai->cfai_name; cfai++) {
  931                 for (i = 0; cfai->cfai_list[i]; i++) {
  932                         error = config_cfattach_attach(cfai->cfai_name,
  933                                                        cfai->cfai_list[i]);
  934                         if (!error)
  935                                 continue;
  936                         if (error != EEXIST) {
  937                                 printf("%s: unable to register cfattach\n",
  938                                        cfai->cfai_list[i]->ca_name);
  939                                 /* XXX roll back previous attachments */
  940                                 goto out;
  941                         }
  942                         printf("driver attachment %s for %s already present\n",
  943                                cfai->cfai_list[i]->ca_name, cfai->cfai_name);
  944                         /*
  945                          * get existing attachments out of the list so we
  946                          * won't try to detach them
  947                          */
  948                         for (j = i; cfai->cfai_list[j]; j++)
  949                                 cfai->cfai_list[j] = cfai->cfai_list[j + 1];
  950                         i--; /* continue at same index */
  951                 }
  952         }
  953 
  954         error = config_cfdata_attach(cf, 1);
  955         /* XXX roll back cfdriver / cfattach attachments in error case */
  956 
  957 out:
  958         return (error);
  959 }
  960 
  961 static int
  962 drvlkm_unload(struct cfdriver **cd, const struct cfattachlkminit *cai,
  963               struct cfdata *cf)
  964 {
  965         const struct cfattachlkminit *cfai;
  966         int i, error;
  967 
  968         error = config_cfdata_detach(cf);
  969         if (error)
  970                 return (error);
  971 
  972         for (cfai = cai; cfai->cfai_name; cfai++) {
  973                 for (i = 0; cfai->cfai_list[i]; i++) {
  974                         error = config_cfattach_detach(cfai->cfai_name,
  975                                                        cfai->cfai_list[i]);
  976                         if (error) {
  977                                 printf("%s: unable to deregister cfattach\n",
  978                                        cfai->cfai_list[i]->ca_name);
  979                                 return (error);
  980                         }
  981                 }
  982         }
  983 
  984         for (i = 0; cd[i]; i++) {
  985                 error = config_cfdriver_detach(cd[i]);
  986                 if (error) {
  987                         printf("%s: unable to deregister cfdriver\n",
  988                                 cd[i]->cd_name);
  989                         return (error);
  990                 }
  991         }
  992 
  993         return (0);
  994 }
  995 
  996 static int
  997 _lkm_drv(struct lkm_table *lkmtp, int cmd)
  998 {
  999         struct lkm_drv *args = lkmtp->private.lkm_drv;
 1000         int error = 0;
 1001 
 1002         switch(cmd) {
 1003         case LKM_E_LOAD:
 1004                 /* don't load twice! */
 1005                 if (lkmexists(lkmtp))
 1006                         return (EEXIST);
 1007 
 1008                 error = drvlkm_load(args->lkm_cd,
 1009                                     args->lkm_cai,
 1010                                     args->lkm_cf);
 1011                 break;
 1012 
 1013         case LKM_E_UNLOAD:
 1014                 error = drvlkm_unload(args->lkm_cd,
 1015                                       args->lkm_cai,
 1016                                       args->lkm_cf);
 1017                 break;
 1018 
 1019         case LKM_E_STAT:        /* no special handling... */
 1020                 break;
 1021         }
 1022 
 1023         return (error);
 1024 }
 1025 
 1026 /*
 1027  * This code handles the per-module type "wiring-in" of loadable modules
 1028  * into existing kernel tables.  For "LM_MISC" modules, wiring and unwiring
 1029  * is assumed to be done in their entry routines internal to the module
 1030  * itself.
 1031  */
 1032 int
 1033 lkmdispatch(struct lkm_table *lkmtp, int cmd)
 1034 {
 1035         int error = 0;          /* default = success */
 1036 #ifdef DEBUG
 1037         if (lkmdebug & LKMDB_INFO)
 1038                 printf( "lkmdispatch: %p %d\n", lkmtp, cmd );
 1039 #endif
 1040 
 1041         /* If loading, check the LKM is compatible */
 1042         if (cmd == LKM_E_LOAD) {
 1043                 if (_lkm_checkver(lkmtp))
 1044                         return (EPROGMISMATCH);
 1045         }
 1046 
 1047         switch(lkmtp->private.lkm_any->lkm_type) {
 1048         case LM_SYSCALL:
 1049                 error = _lkm_syscall(lkmtp, cmd);
 1050                 break;
 1051 
 1052         case LM_VFS:
 1053                 error = _lkm_vfs(lkmtp, cmd);
 1054                 break;
 1055 
 1056         case LM_DEV:
 1057                 error = _lkm_dev(lkmtp, cmd);
 1058                 break;
 1059 
 1060 #ifdef STREAMS
 1061         case LM_STRMOD:
 1062             {
 1063                 struct lkm_strmod *args = lkmtp->private.lkm_strmod;
 1064             }
 1065                 break;
 1066 
 1067 #endif  /* STREAMS */
 1068 
 1069         case LM_EXEC:
 1070                 error = _lkm_exec(lkmtp, cmd);
 1071                 break;
 1072 
 1073         case LM_COMPAT:
 1074                 error = _lkm_compat(lkmtp, cmd);
 1075                 break;
 1076 
 1077         case LM_MISC:   /* ignore content -- no "misc-specific" procedure */
 1078                 break;
 1079 
 1080         case LM_DRV:
 1081                 error = _lkm_drv(lkmtp, cmd);
 1082                 break;
 1083 
 1084         default:
 1085                 error = ENXIO;  /* unknown type */
 1086                 break;
 1087         }
 1088 
 1089         return (error);
 1090 }
 1091 
 1092 /*
 1093  * Check LKM version against current kernel.
 1094  */
 1095 static int
 1096 _lkm_checkver(struct lkm_table *lkmtp)
 1097 {
 1098         struct lkm_any *mod = lkmtp->private.lkm_any;
 1099 
 1100         if (mod->lkm_modver != LKM_VERSION) {
 1101                 printf("LKM '%s': LKM version mismatch - LKM %d, kernel %d\n",
 1102                     mod->lkm_name, mod->lkm_modver, LKM_VERSION);
 1103                 return (1);
 1104         }
 1105 
 1106         if (lkmtp->forced) {
 1107                 printf("LKM '%s': forced load, skipping compatibility checks\n",
 1108                     mod->lkm_name);
 1109                 return (0);
 1110         }
 1111 
 1112         if (mod->lkm_sysver != __NetBSD_Version__) {
 1113                 printf("LKM '%s': kernel version mismatch - LKM %d, kernel %d\n",
 1114                     mod->lkm_name, mod->lkm_sysver, __NetBSD_Version__);
 1115                 return (2);
 1116         }
 1117 
 1118         /*
 1119          * Following might eventually be changed to take into account envdep,
 1120          * if it's non-NULL.
 1121          */
 1122         if (strcmp(mod->lkm_envver, _LKM_ENV_VERSION) != 0) {
 1123                 const char *kenv = _LKM_ENV_VERSION;
 1124                 const char *envver = mod->lkm_envver;
 1125 
 1126                 if (kenv[0] == ',')
 1127                         kenv++;
 1128                 if (envver[0] == ',')
 1129                         envver++;
 1130 
 1131                 printf("LKM '%s': environment compile options mismatch - LKM '%s', kernel '%s'\n",
 1132                     mod->lkm_name, envver, kenv);
 1133                 return (3);
 1134         }
 1135 
 1136         /*
 1137          * Basic parameters match, LKM is hopefully compatible.
 1138          * Cross fingers and approve.
 1139          */
 1140         return (0);
 1141 }

Cache object: 0f6e53898592990af9569c22ef2c1340


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