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