[BACK]Return to kern_lkm.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_lkm.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: kern_lkm.c,v 1.43 2006/11/15 17:25:40 jmc Exp $       */
                      2: /*     $NetBSD: kern_lkm.c,v 1.31 1996/03/31 21:40:27 christos Exp $   */
                      3:
                      4: /*
                      5:  * Copyright (c) 1994 Christopher G. Demetriou
                      6:  * Copyright (c) 1992 Terrence R. Lambert.
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Terrence R. Lambert.
                     20:  * 4. The name Terrence R. Lambert may not be used to endorse or promote
                     21:  *    products derived from this software without specific prior written
                     22:  *    permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
                     25:  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: /*
                     38:  * XXX it's not really safe to unload *any* of the types which are
                     39:  * currently loadable; e.g. you could unload a syscall which was being
                     40:  * blocked in, etc.  In the long term, a solution should be come up
                     41:  * with, but "not right now." -- cgd
                     42:  */
                     43:
                     44: #include <sys/param.h>
                     45: #include <sys/systm.h>
                     46: #include <sys/ioctl.h>
                     47: #include <sys/tty.h>
                     48: #include <sys/file.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/uio.h>
                     51: #include <sys/kernel.h>
                     52: #include <sys/vnode.h>
                     53: #include <sys/malloc.h>
                     54: #include <sys/mount.h>
                     55: #include <sys/exec.h>
                     56: #include <sys/syscallargs.h>
                     57: #include <sys/conf.h>
                     58:
                     59: #include <sys/lkm.h>
                     60: #include <sys/syscall.h>
                     61:
                     62: #include <uvm/uvm_extern.h>
                     63:
                     64: #ifdef DDB
                     65: #include <machine/db_machdep.h>
                     66: #include <ddb/db_sym.h>
                     67: #endif
                     68:
                     69: /* flags */
                     70: #define        LKM_ALLOC               0x01
                     71: #define        LKM_WANT                0x02
                     72: #define        LKM_INIT                0x04
                     73:
                     74: #define        LKMS_IDLE               0x00
                     75: #define        LKMS_RESERVED           0x01
                     76: #define        LKMS_LOADING            0x02
                     77: #define        LKMS_LOADING_SYMS       0x03
                     78: #define        LKMS_LOADED             0x04
                     79: #define        LKMS_UNLOADING          0x08
                     80:
                     81: static int lkm_v = 0;
                     82: static int lkm_state = LKMS_IDLE;
                     83:
                     84: static TAILQ_HEAD(lkmods, lkm_table) lkmods;   /* table of loaded modules */
                     85: static struct lkm_table        *curp;          /* global for in-progress ops */
                     86:
                     87: static struct lkm_table *lkmalloc(void);
                     88: static void lkmfree(struct lkm_table *);
                     89: static struct lkm_table *lkmlookup(int, char *, int *);
                     90: static void lkmunreserve(void);
                     91: static int _lkm_syscall(struct lkm_table *, int);
                     92: static int _lkm_vfs(struct lkm_table *, int);
                     93: static int _lkm_dev(struct lkm_table *, int);
                     94: static int _lkm_exec(struct lkm_table *, int);
                     95:
                     96: void lkminit(void);
                     97: int lkmexists(struct lkm_table *);
                     98:
                     99: void init_exec(void);
                    100:
                    101: void
                    102: lkminit(void)
                    103: {
                    104:
                    105:        TAILQ_INIT(&lkmods);
                    106:        lkm_v |= LKM_INIT;
                    107: }
                    108:
                    109: /*ARGSUSED*/
                    110: int
                    111: lkmopen(dev_t dev, int flag, int devtype, struct proc *p)
                    112: {
                    113:        int error;
                    114:
                    115:        if (minor(dev) != 0)
                    116:                return (ENXIO);
                    117:
                    118:        if (!(lkm_v & LKM_INIT))
                    119:                lkminit();
                    120:
                    121:        /*
                    122:         * Use of the loadable kernel module device must be exclusive; we
                    123:         * may try to remove this restriction later, but it's really no
                    124:         * hardship.
                    125:         */
                    126:        while (lkm_v & LKM_ALLOC) {
                    127:                if (flag & FNONBLOCK)           /* don't hang */
                    128:                        return (EBUSY);
                    129:                lkm_v |= LKM_WANT;
                    130:                /*
                    131:                 * Sleep pending unlock; we use tsleep() to allow
                    132:                 * an alarm out of the open.
                    133:                 */
                    134:                error = tsleep(&lkm_v, TTIPRI|PCATCH, "lkmopn", 0);
                    135:                if (error)
                    136:                        return (error); /* leave LKM_WANT set -- no problem */
                    137:        }
                    138:        lkm_v |= LKM_ALLOC;
                    139:
                    140:        return (0);             /* pseudo-device open */
                    141: }
                    142:
                    143: /*
                    144:  * Alocates new LKM table entry, fills module id, inserts in the list.
                    145:  * Returns NULL on failure.
                    146:  *
                    147:  */
                    148: static struct lkm_table *
                    149: lkmalloc(void)
                    150: {
                    151:        struct lkm_table *p, *ret = NULL;
                    152:        int id = 0;
                    153:
                    154:        MALLOC(ret, struct lkm_table *, sizeof(*ret), M_DEVBUF, M_WAITOK);
                    155:        ret->refcnt = ret->depcnt = 0;
                    156:        ret->sym_id = -1;
                    157:        /*
                    158:         * walk the list finding the first free id. as long as the list is
                    159:         * kept sorted this is not too inefficient, which is why we insert in
                    160:         * order below.
                    161:         */
                    162:        TAILQ_FOREACH(p, &lkmods, list) {
                    163:                if (id == p->id)
                    164:                        id++;
                    165:                else
                    166:                        break;
                    167:        }
                    168:        ret->id = id;
                    169:        if (p == NULL) /* either first or last entry */
                    170:                TAILQ_INSERT_TAIL(&lkmods, ret, list);
                    171:        else
                    172:                TAILQ_INSERT_BEFORE(p, ret, list);
                    173:
                    174:        return ret;
                    175: }
                    176:
                    177: /*
                    178:  * Frees the slot, decreases the number of modules.
                    179:  */
                    180: static void
                    181: lkmfree(struct lkm_table *p)
                    182: {
                    183:
                    184:        TAILQ_REMOVE(&lkmods, p, list);
                    185:        free(p, M_DEVBUF);
                    186:        curp = NULL;
                    187: }
                    188:
                    189: struct lkm_table *
                    190: lkm_list(struct lkm_table *p)
                    191: {
                    192:
                    193:        if (p == NULL)
                    194:                p = TAILQ_FIRST(&lkmods);
                    195:        else
                    196:                p = TAILQ_NEXT(p, list);
                    197:
                    198:        return (p);
                    199: }
                    200:
                    201: static struct lkm_table *
                    202: lkmlookup(int i, char *name, int *error)
                    203: {
                    204:        struct lkm_table *p = NULL;
                    205:        char istr[MAXLKMNAME];
                    206:
                    207:        /*
                    208:         * p being NULL here implies the list is empty, so any lookup is
                    209:         * invalid (name based or otherwise). Since the list of modules is
                    210:         * kept sorted by id, lowest to highest, the id of the last entry
                    211:         * will be the highest in use.
                    212:         */
                    213:        p = TAILQ_LAST(&lkmods, lkmods);
                    214:        if (p == NULL || i > p->id) {
                    215:                *error = EINVAL;
                    216:                return NULL;
                    217:        }
                    218:
                    219:        if (i < 0) {            /* unload by name */
                    220:                /*
                    221:                 * Copy name and lookup id from all loaded
                    222:                 * modules.  May fail.
                    223:                 */
                    224:                *error = copyinstr(name, istr, MAXLKMNAME-1, NULL);
                    225:                if (*error)
                    226:                        return NULL;
                    227:                istr[MAXLKMNAME-1] = '\0';
                    228:
                    229:                TAILQ_FOREACH(p, &lkmods, list) {
                    230:                        if (!strcmp(istr, p->private.lkm_any->lkm_name))
                    231:                                break;
                    232:                }
                    233:        } else
                    234:                TAILQ_FOREACH(p, &lkmods, list)
                    235:                        if (i == p->id)
                    236:                                break;
                    237:
                    238:        if (p == NULL)
                    239:                *error = ENOENT;
                    240:
                    241:        return p;
                    242: }
                    243:
                    244: /*
                    245:  * Unreserve the memory associated with the current loaded module; done on
                    246:  * a coerced close of the lkm device (close on premature exit of modload)
                    247:  * or explicitly by modload as a result of a link failure.
                    248:  */
                    249: static void
                    250: lkmunreserve(void)
                    251: {
                    252:
                    253:        if (lkm_state == LKMS_IDLE)
                    254:                return;
                    255:
                    256: #ifdef DDB
                    257:        if (curp && curp->sym_id != -1)
                    258:                db_del_symbol_table(curp->private.lkm_any->lkm_name);
                    259: #endif
                    260:
                    261:        if (curp && curp->syms) {
                    262:                uvm_km_free(kernel_map, (vaddr_t)curp->syms, curp->sym_size);
                    263:                curp->syms = NULL;
                    264:        }
                    265:
                    266:        /*
                    267:         * Actually unreserve the memory
                    268:         */
                    269:        if (curp && curp->area) {
                    270:                uvm_km_free(kernel_map, curp->area, curp->size);
                    271:                curp->area = 0;
                    272:        }
                    273:        lkm_state = LKMS_IDLE;
                    274: }
                    275:
                    276: int
                    277: lkmclose(dev_t dev, int flag, int mode, struct proc *p)
                    278: {
                    279:
                    280:        if (minor(dev) != 0)
                    281:                return (ENXIO);
                    282:
                    283:        if (!(lkm_v & LKM_ALLOC))
                    284:                return (EBADF);
                    285:
                    286:        /* do this before waking the herd... */
                    287:        if (curp != NULL && !curp->refcnt) {
                    288:                /*
                    289:                 * If we close before setting used, we have aborted
                    290:                 * by way of error or by way of close-on-exit from
                    291:                 * a premature exit of "modload".
                    292:                 */
                    293:                lkmunreserve();
                    294:                lkmfree(curp);
                    295:        }
                    296:        lkm_v &= ~LKM_ALLOC;
                    297:        wakeup(&lkm_v); /* thundering herd "problem" here */
                    298:
                    299:        return (0);
                    300: }
                    301:
                    302: /*ARGSUSED*/
                    303: int
                    304: lkmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
                    305: {
                    306:        int error = 0;
                    307:
                    308:        if (securelevel > 0) {
                    309:                switch (cmd) {
                    310:                case LMSTAT:
                    311:                        break;
                    312:                default:
                    313:                        return (EPERM);
                    314:                }
                    315:        }
                    316:
                    317:        if (!(flags & FWRITE)) {
                    318:                switch (cmd) {
                    319:                case LMSTAT:
                    320:                        break;
                    321:                default:
                    322:                        return (EACCES);
                    323:                }
                    324:        }
                    325:
                    326:        switch (cmd) {
                    327:        case LMRESERV:
                    328:        case LMRESERV_O: {
                    329:                struct lmc_resrv *resrvp = (struct lmc_resrv *)data;
                    330:
                    331:                if ((curp = lkmalloc()) == NULL) {
                    332:                        error = ENOMEM;
                    333:                        break;
                    334:                }
                    335:                curp->ver = (cmd == LMRESERV) ? LKM_VERSION : LKM_OLDVERSION;
                    336:                resrvp->slot = curp->id;        /* return slot */
                    337:
                    338:                /*
                    339:                 * Get memory for module
                    340:                 */
                    341:                curp->size = resrvp->size;
                    342:                curp->area = uvm_km_zalloc(kernel_map, curp->size);
                    343:                curp->offset = 0;
                    344:                resrvp->addr = curp->area;
                    345:
                    346:                if (cmd == LMRESERV && resrvp->sym_size) {
                    347:                        curp->sym_size = resrvp->sym_size;
                    348:                        curp->sym_symsize = resrvp->sym_symsize;
                    349:                        curp->syms = (caddr_t)uvm_km_zalloc(kernel_map,
                    350:                                                            curp->sym_size);
                    351:                        curp->sym_offset = 0;
                    352:                        resrvp->sym_addr = curp->syms;
                    353:                } else {
                    354:                        curp->sym_size = 0;
                    355:                        curp->syms = 0;
                    356:                        curp->sym_offset = 0;
                    357:                        if (cmd == LMRESERV)
                    358:                                resrvp->sym_addr = 0;
                    359:                }
                    360: #ifdef LKM_DEBUG
                    361:                printf("LKM: LMRESERV (actual   = 0x%08lx)\n", curp->area);
                    362:                printf("LKM: LMRESERV (syms     = 0x%08x)\n", curp->syms);
                    363:                printf("LKM: LMRESERV (adjusted = 0x%08lx)\n",
                    364:                        trunc_page(curp->area));
                    365: #endif /* LKM_DEBUG */
                    366:
                    367:                lkm_state = LKMS_RESERVED;
                    368:                break;
                    369:        }
                    370:
                    371:        case LMLOADBUF: {
                    372:                struct lmc_loadbuf *loadbufp = (struct lmc_loadbuf *)data;
                    373:
                    374:                if ((lkm_state != LKMS_RESERVED && lkm_state != LKMS_LOADING)
                    375:                    || loadbufp->cnt < 0
                    376:                    || loadbufp->cnt > MODIOBUF
                    377:                    || loadbufp->cnt > (curp->size - curp->offset)) {
                    378:                        error = ENOMEM;
                    379:                        break;
                    380:                }
                    381:
                    382:                /* copy in buffer full of data */
                    383:                error = copyin(loadbufp->data,
                    384:                        (caddr_t)curp->area + curp->offset, loadbufp->cnt);
                    385:                if (error)
                    386:                        break;
                    387:
                    388:                if ((curp->offset + loadbufp->cnt) < curp->size)
                    389:                        lkm_state = LKMS_LOADING;
                    390:                else
                    391:                        lkm_state = LKMS_LOADING_SYMS;
                    392:
                    393:                curp->offset += loadbufp->cnt;
                    394:                break;
                    395:        }
                    396:
                    397:        case LMLOADSYMS: {
                    398:                struct lmc_loadbuf *loadbufp = (struct lmc_loadbuf *)data;
                    399:
                    400:                if ((lkm_state != LKMS_LOADING &&
                    401:                    lkm_state != LKMS_LOADING_SYMS)
                    402:                    || loadbufp->cnt < 0
                    403:                    || loadbufp->cnt > MODIOBUF
                    404:                    || loadbufp->cnt > (curp->sym_size - curp->sym_offset)) {
                    405:                        error = ENOMEM;
                    406:                        break;
                    407:                }
                    408:
                    409:                /* copy in buffer full of data*/
                    410:                error = copyin(loadbufp->data, curp->syms +
                    411:                    curp->sym_offset, loadbufp->cnt);
                    412:                if (error)
                    413:                        break;
                    414:
                    415:                if ((curp->sym_offset + loadbufp->cnt) < curp->sym_size)
                    416:                        lkm_state = LKMS_LOADING_SYMS;
                    417:                else
                    418:                        lkm_state = LKMS_LOADED;
                    419:
                    420:                curp->sym_offset += loadbufp->cnt;
                    421:                break;
                    422:        }
                    423:
                    424:        case LMUNRESRV:
                    425:                lkmunreserve();
                    426:                if (curp)
                    427:                        lkmfree(curp);
                    428:                break;
                    429:
                    430:        case LMREADY:
                    431:                switch (lkm_state) {
                    432:                case LKMS_LOADED:
                    433:                        break;
                    434:                case LKMS_LOADING:
                    435:                case LKMS_LOADING_SYMS:
                    436:                        if ((curp->size - curp->offset) > 0)
                    437:                            /* The remainder must be bss, so we clear it */
                    438:                            bzero((caddr_t)curp->area + curp->offset,
                    439:                                  curp->size - curp->offset);
                    440:                        break;
                    441:                default:
                    442:                        return (ENXIO);
                    443:                }
                    444:
                    445:                curp->entry = (int (*)(struct lkm_table *, int, int))
                    446:                    (*((long *) (data)));
                    447:
                    448: #ifdef LKM_DEBUG
                    449:                printf("LKM: call entrypoint %x\n", curp->entry);
                    450: #endif /* LKM_DEBUG */
                    451:
                    452:                /* call entry(load)... (assigns "private" portion) */
                    453:                error = (*(curp->entry))(curp, LKM_E_LOAD, curp->ver);
                    454:                if (error) {
                    455:                        /*
                    456:                         * Module may refuse loading or may have a
                    457:                         * version mismatch...
                    458:                         */
                    459:                        lkm_state = LKMS_UNLOADING;     /* for lkmunreserve */
                    460:                        lkmunreserve();                 /* free memory */
                    461:                        lkmfree(curp);                  /* free slot */
                    462:                        break;
                    463:                }
                    464:
                    465: #ifdef LKM_DEBUG
                    466:                printf("LKM: LMREADY, id=%d, dev=%d\n", curp->id,
                    467:                    curp->private.lkm_any->lkm_offset);
                    468: #endif /* LKM_DEBUG */
                    469:
                    470: #ifdef DDB
                    471:                if (curp->syms && curp->sym_offset >= curp->sym_size) {
                    472:                        curp->sym_id = db_add_symbol_table(curp->syms,
                    473:                            curp->syms + curp->sym_symsize,
                    474:                            curp->private.lkm_any->lkm_name,
                    475:                            curp->syms);
                    476:                        printf("DDB symbols added: %ld bytes\n",
                    477:                            curp->sym_symsize);
                    478:                }
                    479: #endif /* DDB */
                    480:
                    481:                curp->refcnt++;
                    482:                lkm_state = LKMS_IDLE;
                    483:                break;
                    484:
                    485:        case LMUNLOAD: {
                    486:                struct lmc_unload *unloadp = (struct lmc_unload *)data;
                    487:
                    488:                curp = lkmlookup(unloadp->id, unloadp->name, &error);
                    489:                if (curp == NULL)
                    490:                        break;
                    491:
                    492:                /* call entry(unload) */
                    493:                if ((*(curp->entry))(curp, LKM_E_UNLOAD, curp->ver)) {
                    494:                        error = EBUSY;
                    495:                        break;
                    496:                }
                    497:
                    498:                lkm_state = LKMS_UNLOADING;     /* non-idle for lkmunreserve */
                    499:                lkmunreserve();                 /* free memory */
                    500:                lkmfree(curp);                  /* free slot */
                    501:                break;
                    502:        }
                    503:
                    504:        case LMSTAT: {
                    505:                struct lmc_stat *statp = (struct lmc_stat *)data;
                    506:
                    507:                if ((curp = lkmlookup(statp->id, statp->name, &error)) == NULL)
                    508:                        break;
                    509:
                    510:                if ((error = (*curp->entry)(curp, LKM_E_STAT, curp->ver)))
                    511:                        break;
                    512:
                    513:                /*
                    514:                 * Copy out stat information for this module...
                    515:                 */
                    516:                statp->id       = curp->id;
                    517:                statp->offset   = curp->private.lkm_any->lkm_offset;
                    518:                statp->type     = curp->private.lkm_any->lkm_type;
                    519:                statp->area     = curp->area;
                    520:                statp->size     = curp->size / PAGE_SIZE;
                    521:                statp->private  = (unsigned long)curp->private.lkm_any;
                    522:                statp->ver      = curp->private.lkm_any->lkm_ver;
                    523:                copyoutstr(curp->private.lkm_any->lkm_name,
                    524:                          statp->name, MAXLKMNAME, NULL);
                    525:
                    526:                break;
                    527:        }
                    528:
                    529:        default:
                    530:                error = ENODEV;
                    531:                break;
                    532:        }
                    533:
                    534:        return (error);
                    535: }
                    536:
                    537: /*
                    538:  * Acts like "nosys" but can be identified in sysent for dynamic call
                    539:  * number assignment for a limited number of calls.
                    540:  *
                    541:  * Place holder for system call slots reserved for loadable modules.
                    542:  */
                    543: int
                    544: sys_lkmnosys(struct proc *p, void *v, register_t *retval)
                    545: {
                    546:
                    547:        return (sys_nosys(p, v, retval));
                    548: }
                    549:
                    550: /*
                    551:  * Acts like "enodev", but can be identified in cdevsw and bdevsw for
                    552:  * dynamic driver major number assignment for a limited number of
                    553:  * drivers.
                    554:  *
                    555:  * Place holder for device switch slots reserved for loadable modules.
                    556:  */
                    557: int
                    558: lkmenodev(void)
                    559: {
                    560:
                    561:        return (enodev());
                    562: }
                    563:
                    564: /*
                    565:  * A placeholder function for load/unload/stat calls; simply returns zero.
                    566:  * Used where people don't want to specify a special function.
                    567:  */
                    568: int
                    569: lkm_nofunc(struct lkm_table *lkmtp, int cmd)
                    570: {
                    571:
                    572:        return (0);
                    573: }
                    574:
                    575: int
                    576: lkmexists(struct lkm_table *lkmtp)
                    577: {
                    578:        struct lkm_table *p;
                    579:
                    580:        TAILQ_FOREACH(p, &lkmods, list) {
                    581:                if (!strcmp(lkmtp->private.lkm_any->lkm_name,
                    582:                     p->private.lkm_any->lkm_name) && p->refcnt)
                    583:                        return (1);
                    584:        }
                    585:        return (0);
                    586: }
                    587:
                    588: /*
                    589:  * For the loadable system call described by the structure pointed to
                    590:  * by lkmtp, load/unload/stat it depending on the cmd requested.
                    591:  */
                    592: static int
                    593: _lkm_syscall(struct lkm_table *lkmtp, int cmd)
                    594: {
                    595:        struct lkm_syscall *args = lkmtp->private.lkm_syscall;
                    596:        int i;
                    597:        int error = 0;
                    598:
                    599:        switch (cmd) {
                    600:        case LKM_E_LOAD:
                    601:                /* don't load twice! */
                    602:                if (lkmexists(lkmtp))
                    603:                        return (EEXIST);
                    604:
                    605:                if ((i = args->lkm_offset) == -1) {     /* auto */
                    606:                        /*
                    607:                         * Search the table looking for a slot...
                    608:                         */
                    609:                        for (i = 0; i < SYS_MAXSYSCALL; i++)
                    610:                                if (sysent[i].sy_call == sys_lkmnosys)
                    611:                                        break;          /* found it! */
                    612:                        /* out of allocable slots? */
                    613:                        if (i == SYS_MAXSYSCALL) {
                    614:                                error = ENFILE;
                    615:                                break;
                    616:                        }
                    617:                } else {                                /* assign */
                    618:                        if (i < 0 || i >= SYS_MAXSYSCALL) {
                    619:                                error = EINVAL;
                    620:                                break;
                    621:                        }
                    622:                }
                    623:
                    624:                /* save old */
                    625:                bcopy(&sysent[i], &args->lkm_oldent, sizeof(struct sysent));
                    626:
                    627:                /* replace with new */
                    628:                bcopy(args->lkm_sysent, &sysent[i], sizeof(struct sysent));
                    629:
                    630:                /* done! */
                    631:                args->lkm_offset = i;   /* slot in sysent[] */
                    632:
                    633:                break;
                    634:
                    635:        case LKM_E_UNLOAD:
                    636:                /* current slot... */
                    637:                i = args->lkm_offset;
                    638:
                    639:                /* replace current slot contents with old contents */
                    640:                bcopy(&args->lkm_oldent, &sysent[i], sizeof(struct sysent));
                    641:
                    642:                break;
                    643:
                    644:        case LKM_E_STAT:        /* no special handling... */
                    645:                break;
                    646:        }
                    647:
                    648:        return (error);
                    649: }
                    650:
                    651: /*
                    652:  * For the loadable virtual file system described by the structure pointed
                    653:  * to by lkmtp, load/unload/stat it depending on the cmd requested.
                    654:  */
                    655: static int
                    656: _lkm_vfs(struct lkm_table *lkmtp, int cmd)
                    657: {
                    658:        int error = 0;
                    659:        struct lkm_vfs *args = lkmtp->private.lkm_vfs;
                    660:
                    661:        switch (cmd) {
                    662:        case LKM_E_LOAD:
                    663:                /* don't load twice! */
                    664:                if (lkmexists(lkmtp))
                    665:                        return (EEXIST);
                    666:                error = vfs_register(args->lkm_vfsconf);
                    667:                break;
                    668:
                    669:        case LKM_E_UNLOAD:
                    670:                error = vfs_unregister(args->lkm_vfsconf);
                    671:                break;
                    672:
                    673:        case LKM_E_STAT:        /* no special handling... */
                    674:                break;
                    675:        }
                    676:
                    677:        return (error);
                    678: }
                    679:
                    680: /*
                    681:  * For the loadable device driver described by the structure pointed to
                    682:  * by lkmtp, load/unload/stat it depending on the cmd requested.
                    683:  */
                    684: static int
                    685: _lkm_dev(struct lkm_table *lkmtp, int cmd)
                    686: {
                    687:        struct lkm_dev *args = lkmtp->private.lkm_dev;
                    688:        int i;
                    689:        int error = 0;
                    690:
                    691:        switch (cmd) {
                    692:        case LKM_E_LOAD:
                    693:                /* don't load twice! */
                    694:                if (lkmexists(lkmtp))
                    695:                        return (EEXIST);
                    696:
                    697:                switch (args->lkm_devtype) {
                    698:                case LM_DT_BLOCK:
                    699:                        if ((i = args->lkm_offset) == -1) {     /* auto */
                    700:                                /*
                    701:                                 * Search the table looking for a slot...
                    702:                                 */
                    703:                                for (i = 0; i < nblkdev; i++)
                    704:                                        if (bdevsw[i].d_open ==
                    705:                                            (dev_type_open((*))) lkmenodev)
                    706:                                                break;          /* found it! */
                    707:                                /* out of allocable slots? */
                    708:                                if (i == nblkdev) {
                    709:                                        error = ENFILE;
                    710:                                        break;
                    711:                                }
                    712:                        } else {                                /* assign */
                    713:                                if (i < 0 || i >= nblkdev) {
                    714:                                        error = EINVAL;
                    715:                                        break;
                    716:                                }
                    717:                        }
                    718:
                    719:                        /* save old */
                    720:                        bcopy(&bdevsw[i], &args->lkm_olddev.bdev,
                    721:                            sizeof(struct bdevsw));
                    722:
                    723:                        /* replace with new */
                    724:                        bcopy(args->lkm_dev.bdev, &bdevsw[i],
                    725:                            sizeof(struct bdevsw));
                    726:
                    727:                        /* done! */
                    728:                        args->lkm_offset = i;   /* slot in bdevsw[] */
                    729:                        break;
                    730:
                    731:                case LM_DT_CHAR:
                    732:                        if ((i = args->lkm_offset) == -1) {     /* auto */
                    733:                                /*
                    734:                                 * Search the table looking for a slot...
                    735:                                 */
                    736:                                for (i = 0; i < nchrdev; i++)
                    737:                                        if (cdevsw[i].d_open ==
                    738:                                            (dev_type_open((*))) lkmenodev)
                    739:                                                break;          /* found it! */
                    740:                                /* out of allocable slots? */
                    741:                                if (i == nchrdev) {
                    742:                                        error = ENFILE;
                    743:                                        break;
                    744:                                }
                    745:                        } else {                                /* assign */
                    746:                                if (i < 0 || i >= nchrdev) {
                    747:                                        error = EINVAL;
                    748:                                        break;
                    749:                                }
                    750:                        }
                    751:
                    752:                        /* save old */
                    753:                        bcopy(&cdevsw[i], &args->lkm_olddev.cdev,
                    754:                            sizeof(struct cdevsw));
                    755:
                    756:                        /* replace with new */
                    757:                        bcopy(args->lkm_dev.cdev, &cdevsw[i],
                    758:                            sizeof(struct cdevsw));
                    759:
                    760:                        /* done! */
                    761:                        args->lkm_offset = i;   /* slot in cdevsw[] */
                    762:
                    763:                        break;
                    764:
                    765:                default:
                    766:                        error = ENODEV;
                    767:                        break;
                    768:                }
                    769:                break;
                    770:
                    771:        case LKM_E_UNLOAD:
                    772:                /* current slot... */
                    773:                i = args->lkm_offset;
                    774:
                    775:                switch (args->lkm_devtype) {
                    776:                case LM_DT_BLOCK:
                    777:                        /* replace current slot contents with old contents */
                    778:                        bcopy(&args->lkm_olddev.bdev, &bdevsw[i],
                    779:                            sizeof(struct bdevsw));
                    780:                        break;
                    781:
                    782:                case LM_DT_CHAR:
                    783:                        /* replace current slot contents with old contents */
                    784:                        bcopy(&args->lkm_olddev.cdev, &cdevsw[i],
                    785:                            sizeof(struct cdevsw));
                    786:                        break;
                    787:
                    788:                default:
                    789:                        error = ENODEV;
                    790:                        break;
                    791:                }
                    792:                break;
                    793:
                    794:        case LKM_E_STAT:        /* no special handling... */
                    795:                break;
                    796:        }
                    797:
                    798:        return (error);
                    799: }
                    800:
                    801: /*
                    802:  * For the loadable execution class described by the structure pointed to
                    803:  * by lkmtp, load/unload/stat it depending on the cmd requested.
                    804:  */
                    805: static int
                    806: _lkm_exec(struct lkm_table *lkmtp, int cmd)
                    807: {
                    808:        struct lkm_exec *args = lkmtp->private.lkm_exec;
                    809:        int i;
                    810:        int error = 0;
                    811:
                    812:        switch (cmd) {
                    813:        case LKM_E_LOAD:
                    814:                /* don't load twice! */
                    815:                if (lkmexists(lkmtp))
                    816:                        return (EEXIST);
                    817:
                    818:                if ((i = args->lkm_offset) == -1) {     /* auto */
                    819:                        /*
                    820:                         * Search the table looking for a slot...
                    821:                         */
                    822:                        for (i = 0; i < nexecs; i++)
                    823:                                if (execsw[i].es_check == NULL)
                    824:                                        break;          /* found it! */
                    825:                        /* out of allocable slots? */
                    826:                        if (i == nexecs) {
                    827:                                error = ENFILE;
                    828:                                break;
                    829:                        }
                    830:                } else {                                /* assign */
                    831:                        if (i < 0 || i >= nexecs) {
                    832:                                error = EINVAL;
                    833:                                break;
                    834:                        }
                    835:                }
                    836:
                    837:                /* save old */
                    838:                bcopy(&execsw[i], &args->lkm_oldexec, sizeof(struct execsw));
                    839:
                    840:                /* replace with new */
                    841:                bcopy(args->lkm_exec, &execsw[i], sizeof(struct execsw));
                    842:
                    843:                /* need to recompute max header size */
                    844:                init_exec();
                    845:
                    846:                /* done! */
                    847:                args->lkm_offset = i;   /* slot in execsw[] */
                    848:
                    849:                break;
                    850:
                    851:        case LKM_E_UNLOAD:
                    852:                /* current slot... */
                    853:                i = args->lkm_offset;
                    854:
                    855:                /* replace current slot contents with old contents */
                    856:                bcopy(&args->lkm_oldexec, &execsw[i], sizeof(struct execsw));
                    857:
                    858:                /* need to recompute max header size */
                    859:                init_exec();
                    860:
                    861:                break;
                    862:
                    863:        case LKM_E_STAT:        /* no special handling... */
                    864:                break;
                    865:        }
                    866:
                    867:        return (error);
                    868: }
                    869:
                    870: /*
                    871:  * This code handles the per-module type "wiring-in" of loadable modules
                    872:  * into existing kernel tables.  For "LM_MISC" modules, wiring and unwiring
                    873:  * is assumed to be done in their entry routines internal to the module
                    874:  * itself.
                    875:  */
                    876: int
                    877: lkmdispatch(struct lkm_table *lkmtp, int cmd)
                    878: {
                    879:        int error =  0;
                    880:
                    881: #ifdef LKM_DEBUG
                    882:        printf("lkmdispatch: %x %d\n", lkmtp, cmd);
                    883: #endif /* LKM_DEBUG */
                    884:
                    885:        switch (lkmtp->private.lkm_any->lkm_type) {
                    886:        case LM_SYSCALL:
                    887:                error = _lkm_syscall(lkmtp, cmd);
                    888:                break;
                    889:
                    890:        case LM_VFS:
                    891:                error = _lkm_vfs(lkmtp, cmd);
                    892:                break;
                    893:
                    894:        case LM_DEV:
                    895:                error = _lkm_dev(lkmtp, cmd);
                    896:                break;
                    897:
                    898:        case LM_EXEC:
                    899:                error = _lkm_exec(lkmtp, cmd);
                    900:                break;
                    901:
                    902:        case LM_MISC:   /* ignore content -- no "misc-specific" procedure */
                    903:                break;
                    904:
                    905:        default:
                    906:                error = ENXIO;  /* unknown type */
                    907:                break;
                    908:        }
                    909:
                    910:        return (error);
                    911: }

CVSweb