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