FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_lkm.c
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
|