xref: /illumos-gate/usr/src/uts/common/os/modconf.c (revision fc910014e8a32a65612105835a10995f2c13d942)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 2018, Joyent, Inc.
28  * Copyright 2021 Oxide Computer Company
29  */
30 
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/param.h>
34 #include <sys/user.h>
35 #include <sys/vm.h>
36 #include <sys/conf.h>
37 #include <sys/class.h>
38 #include <sys/vfs.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
41 #include <sys/systm.h>
42 #include <sys/modctl.h>
43 #include <sys/exec.h>
44 #include <sys/exechdr.h>
45 #include <sys/devops.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include <sys/cmn_err.h>
49 #include <sys/hwconf.h>
50 #include <sys/ddi_impldefs.h>
51 #include <sys/autoconf.h>
52 #include <sys/disp.h>
53 #include <sys/kmem.h>
54 #include <sys/instance.h>
55 #include <sys/modhash.h>
56 #include <sys/dacf.h>
57 #include <sys/debug.h>
58 #include <ipp/ipp.h>
59 #include <sys/strsubr.h>
60 #include <sys/kcpc.h>
61 #include <sys/brand.h>
62 #include <sys/cpc_pcbe.h>
63 #include <sys/kstat.h>
64 #include <sys/socketvar.h>
65 #include <sys/kiconv.h>
66 
67 extern int moddebug;
68 
69 extern struct cb_ops no_cb_ops;
70 extern struct dev_ops nodev_ops;
71 extern struct dev_ops mod_nodev_ops;
72 
73 extern struct modctl *mod_getctl(struct modlinkage *);
74 extern int errsys(), nodev(), nulldev();
75 
76 extern int findmodbyname(char *);
77 extern int mod_getsysnum(const char *);
78 
79 extern struct execsw execsw[];
80 
81 /*
82  * Define dev_ops for unused devopsp entry.
83  */
84 struct dev_ops mod_nodev_ops = {
85 	DEVO_REV,		/* devo_rev	*/
86 	0,			/* refcnt	*/
87 	ddi_no_info,		/* info */
88 	nulldev,		/* identify	*/
89 	nulldev,		/* probe	*/
90 	ddifail,		/* attach	*/
91 	nodev,			/* detach	*/
92 	nulldev,		/* reset	*/
93 	&no_cb_ops,		/* character/block driver operations */
94 	(struct bus_ops *)0	/* bus operations for nexus drivers */
95 };
96 
97 /*
98  * Define mod_ops for each supported module type
99  */
100 
101 /*
102  * Null operations; used for uninitialized and "misc" modules.
103  */
104 static int mod_null(struct modldrv *, struct modlinkage *);
105 static int mod_infonull(void *, struct modlinkage *, int *);
106 
107 struct mod_ops mod_miscops = {
108 	mod_null, mod_null, mod_infonull
109 };
110 
111 /* CPU Modules */
112 struct mod_ops mod_cpuops = {
113 	mod_null, mod_null, mod_infonull
114 };
115 
116 /*
117  * Cryptographic Modules
118  */
119 struct mod_ops mod_cryptoops = {
120 	mod_null, mod_null, mod_infonull
121 };
122 
123 /*
124  * IP Policy Modules
125  */
126 static int mod_installipp(struct modlipp *, struct modlinkage *);
127 static int mod_removeipp(struct modlipp *, struct modlinkage *);
128 static int mod_infoipp(struct modlipp *, struct modlinkage *, int *);
129 
130 struct mod_ops mod_ippops = {
131 	mod_installipp, mod_removeipp, mod_infoipp
132 };
133 
134 /*
135  * Device drivers
136  */
137 static int mod_infodrv(struct modldrv *, struct modlinkage *, int *);
138 static int mod_installdrv(struct modldrv *, struct modlinkage *);
139 static int mod_removedrv(struct modldrv *, struct modlinkage *);
140 
141 struct mod_ops mod_driverops = {
142 	mod_installdrv, mod_removedrv, mod_infodrv
143 };
144 
145 /*
146  * System calls (new interface)
147  */
148 static int mod_infosys(struct modlsys *, struct modlinkage *, int *);
149 static int mod_installsys(struct modlsys *, struct modlinkage *);
150 static int mod_removesys(struct modlsys *, struct modlinkage *);
151 
152 struct mod_ops mod_syscallops = {
153 	mod_installsys, mod_removesys, mod_infosys
154 };
155 
156 #ifdef _SYSCALL32_IMPL
157 /*
158  * 32-bit system calls in 64-bit kernel
159  */
160 static int mod_infosys32(struct modlsys *, struct modlinkage *, int *);
161 static int mod_installsys32(struct modlsys *, struct modlinkage *);
162 static int mod_removesys32(struct modlsys *, struct modlinkage *);
163 
164 struct mod_ops mod_syscallops32 = {
165 	mod_installsys32, mod_removesys32, mod_infosys32
166 };
167 #endif	/* _SYSCALL32_IMPL */
168 
169 /*
170  * Filesystems
171  */
172 static int mod_infofs(struct modlfs *, struct modlinkage *, int *);
173 static int mod_installfs(struct modlfs *, struct modlinkage *);
174 static int mod_removefs(struct modlfs *, struct modlinkage *);
175 
176 struct mod_ops mod_fsops = {
177 	mod_installfs, mod_removefs, mod_infofs
178 };
179 
180 /*
181  * Streams modules.
182  */
183 static int mod_infostrmod(struct modlstrmod *, struct modlinkage *, int *);
184 static int mod_installstrmod(struct modlstrmod *, struct modlinkage *);
185 static int mod_removestrmod(struct modlstrmod *, struct modlinkage *);
186 
187 struct mod_ops mod_strmodops = {
188 	mod_installstrmod, mod_removestrmod, mod_infostrmod
189 };
190 
191 /*
192  * Socket modules.
193  */
194 static int mod_infosockmod(struct modlsockmod *, struct modlinkage *, int *);
195 static int mod_installsockmod(struct modlsockmod *, struct modlinkage *);
196 static int mod_removesockmod(struct modlsockmod *, struct modlinkage *);
197 
198 struct mod_ops mod_sockmodops = {
199 	mod_installsockmod, mod_removesockmod, mod_infosockmod
200 };
201 
202 /*
203  * Scheduling classes.
204  */
205 static int mod_infosched(struct modlsched *, struct modlinkage *, int *);
206 static int mod_installsched(struct modlsched *, struct modlinkage *);
207 static int mod_removesched(struct modlsched *, struct modlinkage *);
208 
209 struct mod_ops mod_schedops = {
210 	mod_installsched, mod_removesched, mod_infosched
211 };
212 
213 /*
214  * Exec file type (like ELF, ...).
215  */
216 static int mod_infoexec(struct modlexec *, struct modlinkage *, int *);
217 static int mod_installexec(struct modlexec *, struct modlinkage *);
218 static int mod_removeexec(struct modlexec *, struct modlinkage *);
219 
220 struct mod_ops mod_execops = {
221 	mod_installexec, mod_removeexec, mod_infoexec
222 };
223 
224 /*
225  * Dacf (Dynamic Autoconfiguration) modules.
226  */
227 static int mod_infodacf(struct modldacf *, struct modlinkage *, int *);
228 static int mod_installdacf(struct modldacf *, struct modlinkage *);
229 static int mod_removedacf(struct modldacf *, struct modlinkage *);
230 
231 struct mod_ops mod_dacfops = {
232 	mod_installdacf, mod_removedacf, mod_infodacf
233 };
234 
235 /*
236  * PCBE (Performance Counter BackEnd) modules.
237  */
238 static int mod_installpcbe(struct modlpcbe *, struct modlinkage *);
239 static int mod_removepcbe(struct modlpcbe *, struct modlinkage *);
240 
241 struct mod_ops mod_pcbeops = {
242 	mod_installpcbe, mod_removepcbe, mod_infonull
243 };
244 
245 /*
246  * Brand modules.
247  */
248 static int mod_installbrand(struct modlbrand *, struct modlinkage *);
249 static int mod_removebrand(struct modlbrand *, struct modlinkage *);
250 
251 struct mod_ops mod_brandops = {
252 	mod_installbrand, mod_removebrand, mod_infonull
253 };
254 
255 /*
256  * kiconv modules.
257  */
258 static int mod_installkiconv(struct modlkiconv *, struct modlinkage *);
259 static int mod_removekiconv(struct modlkiconv *, struct modlinkage *);
260 
261 struct mod_ops mod_kiconvops = {
262 	mod_installkiconv, mod_removekiconv, mod_infonull
263 };
264 
265 static struct sysent *mod_getsysent(struct modlinkage *, struct sysent *);
266 
267 static char uninstall_err[] = "Cannot uninstall %s; not installed";
268 
269 /*
270  * Debugging support
271  */
272 #define	DRV_DBG		MODDEBUG_LOADMSG2
273 
274 /*PRINTFLIKE2*/
275 static void mod_dprintf(int flag, const char *format, ...) __KPRINTFLIKE(2);
276 
277 static void
278 mod_dprintf(int flag, const char *format, ...)
279 {
280 	va_list alist;
281 
282 	if ((moddebug & flag) != 0) {
283 		va_start(alist, format);
284 		(void) vprintf(format, alist);
285 		va_end(alist);
286 	}
287 }
288 
289 /*
290  * Install a module.
291  * (This routine is in the Solaris SPARC DDI/DKI)
292  */
293 int
294 mod_install(struct modlinkage *modlp)
295 {
296 	int retval = -1;	/* No linkage structures */
297 	struct modlmisc **linkpp;
298 	struct modlmisc **linkpp1;
299 
300 	if (modlp->ml_rev != MODREV_1) {
301 		printf("mod_install:  modlinkage structure is not MODREV_1\n");
302 		return (EINVAL);
303 	}
304 	linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
305 
306 	while (*linkpp != NULL) {
307 		if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) {
308 			linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0];
309 
310 			while (linkpp1 != linkpp) {
311 				MODL_REMOVE(*linkpp1, modlp); /* clean up */
312 				linkpp1++;
313 			}
314 			break;
315 		}
316 		linkpp++;
317 	}
318 	return (retval);
319 }
320 
321 static char *reins_err =
322 	"Could not reinstall %s\nReboot to correct the problem";
323 
324 /*
325  * Remove a module.  This is called by the module wrapper routine.
326  * (This routine is in the Solaris SPARC DDI/DKI)
327  */
328 int
329 mod_remove(struct modlinkage *modlp)
330 {
331 	int retval = 0;
332 	struct modlmisc **linkpp, *last_linkp;
333 
334 	linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
335 
336 	while (*linkpp != NULL) {
337 		if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) {
338 			last_linkp = *linkpp;
339 			linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
340 			while (*linkpp != last_linkp) {
341 				if (MODL_INSTALL(*linkpp, modlp) != 0) {
342 					cmn_err(CE_WARN, reins_err,
343 					    (*linkpp)->misc_linkinfo);
344 					break;
345 				}
346 				linkpp++;
347 			}
348 			break;
349 		}
350 		linkpp++;
351 	}
352 	return (retval);
353 }
354 
355 /*
356  * Get module status.
357  * (This routine is in the Solaris SPARC DDI/DKI)
358  */
359 int
360 mod_info(struct modlinkage *modlp, struct modinfo *modinfop)
361 {
362 	int i;
363 	int retval = 0;
364 	struct modspecific_info *msip;
365 	struct modlmisc **linkpp;
366 
367 	modinfop->mi_rev = modlp->ml_rev;
368 
369 	linkpp = (struct modlmisc **)modlp->ml_linkage;
370 	msip = &modinfop->mi_msinfo[0];
371 
372 	for (i = 0; i < MODMAXLINK; i++) {
373 		if (*linkpp == NULL) {
374 			msip->msi_linkinfo[0] = '\0';
375 		} else {
376 			(void) strncpy(msip->msi_linkinfo,
377 			    (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN);
378 			retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0);
379 			if (retval != 0)
380 				break;
381 			linkpp++;
382 		}
383 		msip++;
384 	}
385 
386 	if (modinfop->mi_info == MI_INFO_LINKAGE) {
387 		/*
388 		 * Slight kludge used to extract the address of the
389 		 * modlinkage structure from the module (just after
390 		 * loading a module for the very first time)
391 		 */
392 		modinfop->mi_base = (void *)modlp;
393 	}
394 
395 	if (retval == 0)
396 		return (1);
397 	return (0);
398 }
399 
400 /*
401  * Get module name.
402  */
403 const char *
404 mod_modname(struct modlinkage *modlp)
405 {
406 	struct modctl	*mcp;
407 
408 	if ((mcp = mod_getctl(modlp)) == NULL)
409 		return (NULL);
410 
411 	return (mcp->mod_modname);
412 }
413 
414 /*
415  * Null operation; return 0.
416  */
417 /*ARGSUSED*/
418 static int
419 mod_null(struct modldrv *modl, struct modlinkage *modlp)
420 {
421 	return (0);
422 }
423 
424 /*
425  * Status for User modules.
426  */
427 /*ARGSUSED*/
428 static int
429 mod_infonull(void *modl, struct modlinkage *modlp, int *p0)
430 {
431 	*p0 = -1;		/* for modinfo display */
432 	return (0);
433 }
434 
435 /*
436  * Driver status info
437  */
438 /*ARGSUSED*/
439 static int
440 mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0)
441 {
442 	struct modctl *mcp;
443 	char *mod_name;
444 
445 	if ((mcp = mod_getctl(modlp)) == NULL) {
446 		*p0 = -1;
447 		return (0);	/* driver is not yet installed */
448 	}
449 
450 	mod_name = mcp->mod_modname;
451 
452 	*p0 = ddi_name_to_major(mod_name);
453 	return (0);
454 }
455 
456 /*
457  * Manage dacf (device autoconfiguration) modules
458  */
459 
460 /*ARGSUSED*/
461 static int
462 mod_infodacf(struct modldacf *modl, struct modlinkage *modlp, int *p0)
463 {
464 	if (mod_getctl(modlp) == NULL) {
465 		*p0 = -1;
466 		return (0);	/* module is not yet installed */
467 	}
468 
469 	*p0 = 0;
470 	return (0);
471 }
472 
473 static int
474 mod_installdacf(struct modldacf *modl, struct modlinkage *modlp)
475 {
476 	struct modctl	*mcp;
477 
478 	if ((mcp = mod_getctl(modlp)) == NULL)
479 		return (EINVAL);
480 	return (dacf_module_register(mcp->mod_modname, modl->dacf_dacfsw));
481 }
482 
483 /*ARGSUSED*/
484 static int
485 mod_removedacf(struct modldacf *modl, struct modlinkage *modlp)
486 {
487 	struct modctl	*mcp;
488 
489 	if ((mcp = mod_getctl(modlp)) == NULL)
490 		return (EINVAL);
491 	return (dacf_module_unregister(mcp->mod_modname));
492 }
493 
494 /*
495  * Manage PCBE (Performance Counter BackEnd) modules.
496  */
497 /*ARGSUSED*/
498 static int
499 mod_installpcbe(struct modlpcbe *modl, struct modlinkage *modlp)
500 {
501 	if (modl->pcbe_ops->pcbe_ver != PCBE_VER_1) {
502 		cmn_err(CE_WARN, "pcbe '%s' version mismatch",
503 		    modl->pcbe_linkinfo);
504 		return (EINVAL);
505 	}
506 
507 	kcpc_register_pcbe(modl->pcbe_ops);
508 	return (0);
509 }
510 
511 /*
512  * PCBEs may not be unloaded. It would make CPC locking too complex, and since
513  * PCBEs are loaded once and used for life, there is no harm done in leaving
514  * them in the system.
515  */
516 /*ARGSUSED*/
517 static int
518 mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp)
519 {
520 	return (EBUSY);
521 }
522 
523 /*
524  * Manage BrandZ modules.
525  */
526 /*ARGSUSED*/
527 static int
528 mod_installbrand(struct modlbrand *modl, struct modlinkage *modlp)
529 {
530 	return (brand_register(modl->brand_branddef));
531 }
532 
533 /*ARGSUSED*/
534 static int
535 mod_removebrand(struct modlbrand *modl, struct modlinkage *modlp)
536 {
537 	return (brand_unregister(modl->brand_branddef));
538 }
539 
540 /*
541  * Install a new driver
542  */
543 static int
544 mod_installdrv(struct modldrv *modl, struct modlinkage *modlp)
545 {
546 	struct modctl *mcp;
547 	struct dev_ops *ops;
548 	char *modname;
549 	major_t major;
550 	struct dev_ops *dp;
551 	struct devnames *dnp;
552 	struct streamtab *str;
553 	cdevsw_impl_t *cdp;
554 	uint_t sqtype;
555 	uint_t qflag;
556 	uint_t flag;
557 	int err = 0;
558 
559 	/* sanity check module */
560 	if ((mcp = mod_getctl(modlp)) == NULL) {
561 		cmn_err(CE_WARN, "mod_install: bad module linkage data");
562 		err = ENXIO;
563 		goto done;
564 	}
565 	modname = mcp->mod_modname;
566 
567 	/* Sanity check modname */
568 	if ((major = ddi_name_to_major(modname)) == DDI_MAJOR_T_NONE) {
569 		cmn_err(CE_WARN,
570 		    "mod_installdrv: no major number for %s", modname);
571 		err = ENXIO;
572 		goto done;
573 	}
574 
575 	/* Verify MP safety flag */
576 	ops = modl->drv_dev_ops;
577 	if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL &&
578 	    !(ops->devo_cb_ops->cb_flag & D_MP)) {
579 		cmn_err(CE_WARN,
580 		    "mod_installdrv: MT-unsafe driver '%s' rejected", modname);
581 		err = ENXIO;
582 		goto done;
583 	}
584 
585 
586 	/* Is bus_map_fault signature correct (version 8 and higher)? */
587 	if (ops->devo_bus_ops != NULL &&
588 	    ops->devo_bus_ops->bus_map_fault != NULL &&
589 	    ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault &&
590 	    ops->devo_bus_ops->busops_rev < BUSO_REV_8) {
591 
592 		cmn_err(CE_WARN,
593 		    "mod_installdrv: busops' revision of '%s' is too low"
594 		    " (must be at least 8)", modname);
595 		err = ENXIO;
596 		goto done;
597 	}
598 
599 
600 	/* Make sure the driver is uninstalled */
601 	dnp = &devnamesp[major];
602 	LOCK_DEV_OPS(&dnp->dn_lock);
603 	dp = devopsp[major];
604 
605 	if (dnp->dn_flags & (DN_DRIVER_REMOVED|DN_DRIVER_INACTIVE)) {
606 #ifdef DEBUG
607 		cmn_err(CE_CONT,
608 		    "mod_installdrv: driver %s not installed", modname);
609 #endif
610 		err = ENXIO;
611 		goto unlock;
612 	}
613 
614 	if (dp != &nodev_ops && dp != &mod_nodev_ops) {
615 		cmn_err(CE_WARN,
616 		    "mod_installdrv: driver already installed %s", modname);
617 		err = EALREADY;
618 		goto unlock;
619 	}
620 
621 	devopsp[major] = ops; /* setup devopsp */
622 
623 	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
624 		flag = CBFLAG(major);
625 		if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0)
626 			goto unlock;
627 		cdp = &devimpl[major];
628 		ASSERT(cdp->d_str == NULL);
629 		cdp->d_str = str;
630 		cdp->d_qflag = qflag | QISDRV;
631 		cdp->d_sqtype = sqtype;
632 	}
633 
634 	if (ops->devo_bus_ops == NULL)
635 		dnp->dn_flags |= DN_LEAF_DRIVER;
636 
637 unlock:
638 	UNLOCK_DEV_OPS(&dnp->dn_lock);
639 done:
640 	return (err);
641 }
642 
643 static int
644 mod_removedrv(struct modldrv *modl, struct modlinkage *modlp)
645 {
646 	struct modctl *mcp;
647 	struct dev_ops *ops;
648 	struct devnames *dnp;
649 	struct dev_ops *dp;
650 	major_t major;
651 	char *modname;
652 	extern kthread_id_t mod_aul_thread;
653 	struct streamtab *str;
654 	cdevsw_impl_t *cdp;
655 	int err = 0;
656 
657 	/* Don't auto unload modules on if moddebug flag is set */
658 	if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) {
659 		err = EBUSY;
660 		goto done;
661 	}
662 
663 	/* Verify modname has a driver major */
664 	mcp = mod_getctl(modlp);
665 	ASSERT(mcp != NULL);
666 	modname = mcp->mod_modname;
667 
668 	if ((major = ddi_name_to_major(modname)) == -1) {
669 		cmn_err(CE_WARN, uninstall_err, modname);
670 		err = EINVAL;
671 		goto done;
672 	}
673 
674 	ops = modl->drv_dev_ops;
675 	dnp = &(devnamesp[major]);
676 	LOCK_DEV_OPS(&(dnp->dn_lock));
677 
678 	dp = devopsp[major];
679 
680 	if (dp != ops)  {
681 		cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s",
682 		    modname);
683 		err = EBUSY;
684 		goto unlock;
685 	}
686 
687 	/*
688 	 * A driver is not unloadable if its dev_ops are held
689 	 */
690 	if (!DRV_UNLOADABLE(dp)) {
691 		mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>,"
692 		    " refcnt %d\n", modname, dp->devo_refcnt);
693 		err = EBUSY;
694 		goto unlock;
695 	}
696 
697 	/*
698 	 * OK to unload.
699 	 */
700 	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
701 		cdp = &devimpl[major];
702 		ASSERT(cdp->d_str == str);
703 		cdp->d_str = NULL;
704 
705 		/* check for reference to per-dev syncq */
706 		if (cdp->d_dmp != NULL) {
707 			rele_dm(cdp->d_dmp);
708 			cdp->d_dmp = NULL;
709 		}
710 	}
711 
712 	devopsp[major] = &mod_nodev_ops;
713 	dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH);
714 
715 unlock:
716 	UNLOCK_DEV_OPS(&(dnp->dn_lock));
717 done:
718 	return (err);
719 }
720 
721 /*
722  * System call subroutines
723  */
724 
725 /*
726  * Compute system call number for given sysent and sysent table
727  */
728 static int
729 mod_infosysnum(struct modlinkage *modlp, struct sysent table[])
730 {
731 	struct sysent *sysp;
732 
733 	if ((sysp = mod_getsysent(modlp, table)) == NULL)
734 		return (-1);
735 	return ((int)(sysp - table));
736 }
737 
738 /*
739  * Put a loadable system call entry into a sysent table.
740  */
741 static int
742 mod_installsys_sysent(
743 	struct modlsys		*modl,
744 	struct modlinkage	*modlp,
745 	struct sysent		table[])
746 {
747 	struct sysent *sysp;
748 	struct sysent *mp;
749 
750 #ifdef DEBUG
751 	/*
752 	 * Before we even play with the sysent table, sanity check the
753 	 * incoming flags to make sure the entry is valid
754 	 */
755 	switch (modl->sys_sysent->sy_flags & SE_RVAL_MASK) {
756 	case SE_32RVAL1:
757 		/* only r_val1 returned */
758 	case SE_32RVAL1 | SE_32RVAL2:
759 		/* r_val1 and r_val2 returned */
760 	case SE_64RVAL:
761 		/* 64-bit rval returned */
762 		break;
763 	default:
764 		cmn_err(CE_WARN, "loadable syscall: %p: bad rval flags %x",
765 		    (void *)modl, modl->sys_sysent->sy_flags);
766 		return (ENOSYS);
767 	}
768 #endif
769 	if ((sysp = mod_getsysent(modlp, table)) == NULL)
770 		return (ENOSPC);
771 
772 	/*
773 	 * We should only block here until the reader in syscall gives
774 	 * up the lock.  Multiple writers are prevented in the mod layer.
775 	 */
776 	rw_enter(sysp->sy_lock, RW_WRITER);
777 	mp = modl->sys_sysent;
778 	sysp->sy_narg = mp->sy_narg;
779 	sysp->sy_call = mp->sy_call;
780 
781 	/*
782 	 * clear the old call method flag, and get the new one from the module.
783 	 */
784 	sysp->sy_flags &= ~SE_ARGC;
785 	sysp->sy_flags |= SE_LOADED |
786 	    (mp->sy_flags & (SE_ARGC | SE_NOUNLOAD | SE_RVAL_MASK));
787 
788 	/*
789 	 * If the syscall doesn't need or want unloading, it can avoid
790 	 * the locking overhead on each entry.  Convert the sysent to a
791 	 * normal non-loadable entry in that case.
792 	 */
793 	if (mp->sy_flags & SE_NOUNLOAD) {
794 		if (mp->sy_flags & SE_ARGC) {
795 			sysp->sy_callc = (int64_t (*)())(uintptr_t)mp->sy_call;
796 		} else {
797 			sysp->sy_callc = syscall_ap;
798 		}
799 		sysp->sy_flags &= ~SE_LOADABLE;
800 	}
801 	rw_exit(sysp->sy_lock);
802 	return (0);
803 }
804 
805 /*
806  * Remove a loadable system call entry from a sysent table.
807  */
808 static int
809 mod_removesys_sysent(
810 	struct modlsys		*modl,
811 	struct modlinkage	*modlp,
812 	struct sysent		table[])
813 {
814 	struct sysent	*sysp;
815 
816 	if ((sysp = mod_getsysent(modlp, table)) == NULL ||
817 	    (sysp->sy_flags & (SE_LOADABLE | SE_NOUNLOAD)) == 0 ||
818 	    sysp->sy_call != modl->sys_sysent->sy_call) {
819 
820 		struct modctl *mcp = mod_getctl(modlp);
821 		char *modname = mcp->mod_modname;
822 
823 		cmn_err(CE_WARN, uninstall_err, modname);
824 		return (EINVAL);
825 	}
826 
827 	/* If we can't get the write lock, we can't unlink from the system */
828 
829 	if (!(moddebug & MODDEBUG_NOAUL_SYS) &&
830 	    rw_tryenter(sysp->sy_lock, RW_WRITER)) {
831 		/*
832 		 * Check the flags to be sure the syscall is still
833 		 * (un)loadable.
834 		 * If SE_NOUNLOAD is set, SE_LOADABLE will not be.
835 		 */
836 		if ((sysp->sy_flags & (SE_LOADED | SE_LOADABLE)) ==
837 		    (SE_LOADED | SE_LOADABLE)) {
838 			sysp->sy_flags &= ~SE_LOADED;
839 			sysp->sy_callc = loadable_syscall;
840 			sysp->sy_call = nosys32;
841 			rw_exit(sysp->sy_lock);
842 			return (0);
843 		}
844 		rw_exit(sysp->sy_lock);
845 	}
846 	return (EBUSY);
847 }
848 
849 /*
850  * System call status info
851  */
852 /*ARGSUSED*/
853 static int
854 mod_infosys(struct modlsys *modl, struct modlinkage *modlp, int *p0)
855 {
856 	*p0 = mod_infosysnum(modlp, sysent);
857 	return (0);
858 }
859 
860 /*
861  * Link a system call into the system by setting the proper sysent entry.
862  * Called from the module's _init routine.
863  */
864 static int
865 mod_installsys(struct modlsys *modl, struct modlinkage *modlp)
866 {
867 	return (mod_installsys_sysent(modl, modlp, sysent));
868 }
869 
870 /*
871  * Unlink a system call from the system.
872  * Called from a modules _fini routine.
873  */
874 static int
875 mod_removesys(struct modlsys *modl, struct modlinkage *modlp)
876 {
877 	return (mod_removesys_sysent(modl, modlp, sysent));
878 }
879 
880 #ifdef _SYSCALL32_IMPL
881 
882 /*
883  * 32-bit system call status info
884  */
885 /*ARGSUSED*/
886 static int
887 mod_infosys32(struct modlsys *modl, struct modlinkage *modlp, int *p0)
888 {
889 	*p0 = mod_infosysnum(modlp, sysent32);
890 	return (0);
891 }
892 
893 /*
894  * Link the 32-bit syscall into the system by setting the proper sysent entry.
895  * Also called from the module's _init routine.
896  */
897 static int
898 mod_installsys32(struct modlsys *modl, struct modlinkage *modlp)
899 {
900 	return (mod_installsys_sysent(modl, modlp, sysent32));
901 }
902 
903 /*
904  * Unlink the 32-bit flavor of a system call from the system.
905  * Also called from a module's _fini routine.
906  */
907 static int
908 mod_removesys32(struct modlsys *modl, struct modlinkage *modlp)
909 {
910 	return (mod_removesys_sysent(modl, modlp, sysent32));
911 }
912 
913 #endif	/* _SYSCALL32_IMPL */
914 
915 /*
916  * Filesystem status info
917  */
918 /*ARGSUSED*/
919 static int
920 mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0)
921 {
922 	struct vfssw *vswp;
923 
924 	RLOCK_VFSSW();
925 	if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL)
926 		*p0 = -1;
927 	else {
928 		*p0 = vswp - vfssw;
929 		vfs_unrefvfssw(vswp);
930 	}
931 	RUNLOCK_VFSSW();
932 	return (0);
933 }
934 
935 /*
936  * Install a filesystem.
937  */
938 /*ARGSUSED1*/
939 static int
940 mod_installfs(struct modlfs *modl, struct modlinkage *modlp)
941 {
942 	struct vfssw *vswp;
943 	struct modctl *mcp;
944 	char *fsname;
945 	char ksname[KSTAT_STRLEN + 1];
946 	int fstype;	/* index into vfssw[] and vsanchor_fstype[] */
947 	int allocated;
948 	int err;
949 	int vsw_stats_enabled;
950 	/* Not for public consumption so these aren't in a header file */
951 	extern int	vopstats_enabled;
952 	extern vopstats_t **vopstats_fstype;
953 	extern kstat_t *new_vskstat(char *, vopstats_t *);
954 	extern void initialize_vopstats(vopstats_t *);
955 
956 	if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) {
957 		/* Version matched */
958 		fsname = modl->fs_vfsdef->name;
959 	} else {
960 		if ((modl->fs_vfsdef->def_version > 0) &&
961 		    (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) {
962 			/* Older VFSDEF_VERSION */
963 			fsname = modl->fs_vfsdef->name;
964 		} else if ((mcp = mod_getctl(modlp)) != NULL) {
965 			/* Pre-VFSDEF_VERSION */
966 			fsname = mcp->mod_modname;
967 		} else {
968 			/* If all else fails... */
969 			fsname = "<unknown file system type>";
970 		}
971 
972 		cmn_err(CE_WARN, "file system '%s' version mismatch", fsname);
973 		return (ENXIO);
974 	}
975 
976 	allocated = 0;
977 
978 	WLOCK_VFSSW();
979 	if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) {
980 		if ((vswp = allocate_vfssw(fsname)) == NULL) {
981 			WUNLOCK_VFSSW();
982 			/*
983 			 * See 1095689.  If this message appears, then
984 			 * we either need to make the vfssw table bigger
985 			 * statically, or make it grow dynamically.
986 			 */
987 			cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname);
988 			return (ENXIO);
989 		}
990 		allocated = 1;
991 	}
992 	ASSERT(vswp != NULL);
993 
994 	fstype = vswp - vfssw;	/* Pointer arithmetic to get the fstype */
995 
996 	/* Turn on everything by default *except* VSW_STATS */
997 	vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS);
998 
999 	if (modl->fs_vfsdef->flags & VSW_HASPROTO) {
1000 		vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto,
1001 		    &vswp->vsw_optproto);
1002 	} else {
1003 		vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto);
1004 	}
1005 
1006 	if (modl->fs_vfsdef->flags & VSW_CANRWRO) {
1007 		/*
1008 		 * This obviously implies VSW_CANREMOUNT.
1009 		 */
1010 		vswp->vsw_flag |= VSW_CANREMOUNT;
1011 	}
1012 
1013 	/*
1014 	 * If stats are enabled system wide and for this fstype, then
1015 	 * set the VSW_STATS flag in the proper vfssw[] table entry.
1016 	 */
1017 	if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) {
1018 		vswp->vsw_flag |= VSW_STATS;
1019 	}
1020 
1021 	if (modl->fs_vfsdef->init == NULL)
1022 		err = EFAULT;
1023 	else
1024 		err = (*(modl->fs_vfsdef->init))(fstype, fsname);
1025 
1026 	if (err != 0) {
1027 		if (allocated) {
1028 			kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1);
1029 			vswp->vsw_name = "";
1030 		}
1031 		vswp->vsw_flag = 0;
1032 		vswp->vsw_init = NULL;
1033 	}
1034 
1035 	/* We don't want to hold the vfssw[] write lock over a kmem_alloc() */
1036 	vsw_stats_enabled = vswp->vsw_flag & VSW_STATS;
1037 
1038 	vfs_unrefvfssw(vswp);
1039 	WUNLOCK_VFSSW();
1040 
1041 	/* If everything is on, set up the per-fstype vopstats */
1042 	if (vsw_stats_enabled && vopstats_enabled &&
1043 	    vopstats_fstype && vopstats_fstype[fstype] == NULL) {
1044 		(void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname));
1045 		(void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname));
1046 		vopstats_fstype[fstype] =
1047 		    kmem_alloc(sizeof (vopstats_t), KM_SLEEP);
1048 		initialize_vopstats(vopstats_fstype[fstype]);
1049 		(void) new_vskstat(ksname, vopstats_fstype[fstype]);
1050 	}
1051 	return (err);
1052 }
1053 
1054 /*
1055  * Remove a filesystem
1056  */
1057 static int
1058 mod_removefs(struct modlfs *modl, struct modlinkage *modlp)
1059 {
1060 	struct vfssw *vswp;
1061 	struct modctl *mcp;
1062 	char *modname;
1063 
1064 	if (moddebug & MODDEBUG_NOAUL_FS)
1065 		return (EBUSY);
1066 
1067 	WLOCK_VFSSW();
1068 	if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) {
1069 		mcp = mod_getctl(modlp);
1070 		ASSERT(mcp != NULL);
1071 		modname = mcp->mod_modname;
1072 		WUNLOCK_VFSSW();
1073 		cmn_err(CE_WARN, uninstall_err, modname);
1074 		return (EINVAL);
1075 	}
1076 	if (vswp->vsw_count != 1) {
1077 		vfs_unrefvfssw(vswp);
1078 		WUNLOCK_VFSSW();
1079 		return (EBUSY);
1080 	}
1081 
1082 	/*
1083 	 * A mounted filesystem could still have vsw_count = 0
1084 	 * so we must check whether anyone is actually using our ops
1085 	 */
1086 	if (vfs_opsinuse(&vswp->vsw_vfsops)) {
1087 		vfs_unrefvfssw(vswp);
1088 		WUNLOCK_VFSSW();
1089 		return (EBUSY);
1090 	}
1091 
1092 	vfs_freeopttbl(&vswp->vsw_optproto);
1093 	vswp->vsw_optproto.mo_count = 0;
1094 
1095 	vswp->vsw_flag = 0;
1096 	vswp->vsw_init = NULL;
1097 	vfs_unrefvfssw(vswp);
1098 	WUNLOCK_VFSSW();
1099 	return (0);
1100 }
1101 
1102 /*
1103  * Get status of a streams module.
1104  */
1105 /*ARGSUSED*/
1106 static int
1107 mod_infostrmod(struct modlstrmod *modl, struct modlinkage *modlp, int *p0)
1108 {
1109 	*p0 = -1;	/* no useful info */
1110 	return (0);
1111 }
1112 
1113 
1114 /*
1115  * Install a streams module.
1116  */
1117 /*ARGSUSED*/
1118 static int
1119 mod_installstrmod(struct modlstrmod *modl, struct modlinkage *modlp)
1120 {
1121 	struct fmodsw *fp = modl->strmod_fmodsw;
1122 
1123 	if (!(fp->f_flag & D_MP)) {
1124 		cmn_err(CE_WARN, "mod_install: MT-unsafe strmod '%s' rejected",
1125 		    fp->f_name);
1126 		return (ENXIO);
1127 	}
1128 
1129 	return (fmodsw_register(fp->f_name, fp->f_str, fp->f_flag));
1130 }
1131 
1132 /*
1133  * Remove a streams module.
1134  */
1135 /*ARGSUSED*/
1136 static int
1137 mod_removestrmod(struct modlstrmod *modl, struct modlinkage *modlp)
1138 {
1139 	if (moddebug & MODDEBUG_NOAUL_STR)
1140 		return (EBUSY);
1141 
1142 	return (fmodsw_unregister(modl->strmod_fmodsw->f_name));
1143 }
1144 
1145 /*
1146  * Get status of a socket module.
1147  */
1148 /*ARGSUSED*/
1149 static int
1150 mod_infosockmod(struct modlsockmod *modl, struct modlinkage *modlp, int *p0)
1151 {
1152 	*p0 = -1;	/* no useful info */
1153 	return (0);
1154 }
1155 
1156 /*
1157  * Install a socket module.
1158  */
1159 /*ARGSUSED*/
1160 static int
1161 mod_installsockmod(struct modlsockmod *modl, struct modlinkage *modlp)
1162 {
1163 	struct modctl *mcp;
1164 	char *mod_name;
1165 
1166 	mcp = mod_getctl(modlp);
1167 	ASSERT(mcp != NULL);
1168 	mod_name = mcp->mod_modname;
1169 	if (strcmp(mod_name, modl->sockmod_reg_info->smod_name) != 0) {
1170 #ifdef DEBUG
1171 		cmn_err(CE_CONT, "mod_installsockmod: different names"
1172 		    " %s != %s \n", mod_name,
1173 		    modl->sockmod_reg_info->smod_name);
1174 #endif
1175 		return (EINVAL);
1176 	}
1177 
1178 	/*
1179 	 * Register module.
1180 	 */
1181 	return (smod_register(modl->sockmod_reg_info));
1182 }
1183 
1184 /*
1185  * Remove a socket module.
1186  */
1187 /*ARGSUSED*/
1188 static int
1189 mod_removesockmod(struct modlsockmod *modl, struct modlinkage *modlp)
1190 {
1191 	/*
1192 	 * unregister from the global socket creation table
1193 	 * check the refcnt in the lookup table
1194 	 */
1195 	return (smod_unregister(modl->sockmod_reg_info->smod_name));
1196 }
1197 
1198 /*
1199  * Get status of a scheduling class module.
1200  */
1201 /*ARGSUSED1*/
1202 static int
1203 mod_infosched(struct modlsched *modl, struct modlinkage *modlp, int *p0)
1204 {
1205 	int	status;
1206 	auto id_t	cid;
1207 
1208 	status = getcidbyname(modl->sched_class->cl_name, &cid);
1209 
1210 	if (status != 0)
1211 		*p0 = -1;
1212 	else
1213 		*p0 = cid;
1214 
1215 	return (0);
1216 }
1217 
1218 /*
1219  * Install a scheduling class module.
1220  */
1221 /*ARGSUSED1*/
1222 static int
1223 mod_installsched(struct modlsched *modl, struct modlinkage *modlp)
1224 {
1225 	sclass_t *clp;
1226 	int status;
1227 	id_t cid;
1228 
1229 	/*
1230 	 * See if module is already installed.
1231 	 */
1232 	mutex_enter(&class_lock);
1233 	status = alloc_cid(modl->sched_class->cl_name, &cid);
1234 	mutex_exit(&class_lock);
1235 	ASSERT(status == 0);
1236 	clp = &sclass[cid];
1237 	rw_enter(clp->cl_lock, RW_WRITER);
1238 	if (SCHED_INSTALLED(clp)) {
1239 		printf("scheduling class %s is already installed\n",
1240 		    modl->sched_class->cl_name);
1241 		rw_exit(clp->cl_lock);
1242 		return (EBUSY);		/* it's already there */
1243 	}
1244 
1245 	clp->cl_init = modl->sched_class->cl_init;
1246 	clp->cl_funcs = modl->sched_class->cl_funcs;
1247 	modl->sched_class = clp;
1248 	disp_add(clp);
1249 	loaded_classes++;		/* for priocntl system call */
1250 	rw_exit(clp->cl_lock);
1251 	return (0);
1252 }
1253 
1254 /*
1255  * Remove a scheduling class module.
1256  *
1257  * we only null out the init func and the class functions because
1258  * once a class has been loaded it has that slot in the class
1259  * array until the next reboot. We don't decrement loaded_classes
1260  * because this keeps count of the number of classes that have
1261  * been loaded for this session. It will have to be this way until
1262  * we implement the class array as a linked list and do true
1263  * dynamic allocation.
1264  */
1265 static int
1266 mod_removesched(struct modlsched *modl, struct modlinkage *modlp)
1267 {
1268 	int status;
1269 	sclass_t *clp;
1270 	struct modctl *mcp;
1271 	char *modname;
1272 	id_t cid;
1273 
1274 	status = getcidbyname(modl->sched_class->cl_name, &cid);
1275 	if (status != 0) {
1276 		mcp = mod_getctl(modlp);
1277 		ASSERT(mcp != NULL);
1278 		modname = mcp->mod_modname;
1279 		cmn_err(CE_WARN, uninstall_err, modname);
1280 		return (EINVAL);
1281 	}
1282 	clp = &sclass[cid];
1283 	if (moddebug & MODDEBUG_NOAUL_SCHED ||
1284 	    !rw_tryenter(clp->cl_lock, RW_WRITER))
1285 		return (EBUSY);
1286 
1287 	clp->cl_init = NULL;
1288 	clp->cl_funcs = NULL;
1289 	rw_exit(clp->cl_lock);
1290 	return (0);
1291 }
1292 
1293 /*
1294  * Get status of an exec module.
1295  */
1296 /*ARGSUSED1*/
1297 static int
1298 mod_infoexec(struct modlexec *modl, struct modlinkage *modlp, int *p0)
1299 {
1300 	struct execsw *eswp;
1301 
1302 	if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL)
1303 		*p0 = -1;
1304 	else
1305 		*p0 = eswp - execsw;
1306 
1307 	return (0);
1308 }
1309 
1310 /*
1311  * Install an exec module.
1312  */
1313 static int
1314 mod_installexec(struct modlexec *modl, struct modlinkage *modlp)
1315 {
1316 	struct execsw *eswp;
1317 	struct modctl *mcp;
1318 	char *modname;
1319 	char *magic;
1320 	size_t magic_size;
1321 
1322 	/*
1323 	 * See if execsw entry is already allocated.  Can't use findexectype()
1324 	 * because we may get a recursive call to here.
1325 	 */
1326 
1327 	if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) {
1328 		mcp = mod_getctl(modlp);
1329 		ASSERT(mcp != NULL);
1330 		modname = mcp->mod_modname;
1331 		magic = modl->exec_execsw->exec_magic;
1332 		magic_size = modl->exec_execsw->exec_maglen;
1333 		if ((eswp = allocate_execsw(modname, magic, magic_size)) ==
1334 		    NULL) {
1335 			printf("no unused entries in 'execsw'\n");
1336 			return (ENOSPC);
1337 		}
1338 	}
1339 	if (eswp->exec_func != NULL) {
1340 		printf("exec type %x is already installed\n",
1341 		    *eswp->exec_magic);
1342 		return (EBUSY);		 /* it's already there! */
1343 	}
1344 
1345 	rw_enter(eswp->exec_lock, RW_WRITER);
1346 	eswp->exec_func = modl->exec_execsw->exec_func;
1347 	eswp->exec_core = modl->exec_execsw->exec_core;
1348 	rw_exit(eswp->exec_lock);
1349 
1350 	return (0);
1351 }
1352 
1353 /*
1354  * Remove an exec module.
1355  */
1356 static int
1357 mod_removeexec(struct modlexec *modl, struct modlinkage *modlp)
1358 {
1359 	struct execsw *eswp;
1360 	struct modctl *mcp;
1361 	char *modname;
1362 
1363 	eswp = findexecsw(modl->exec_execsw->exec_magic);
1364 	if (eswp == NULL) {
1365 		mcp = mod_getctl(modlp);
1366 		ASSERT(mcp != NULL);
1367 		modname = mcp->mod_modname;
1368 		cmn_err(CE_WARN, uninstall_err, modname);
1369 		return (EINVAL);
1370 	}
1371 	if (moddebug & MODDEBUG_NOAUL_EXEC ||
1372 	    !rw_tryenter(eswp->exec_lock, RW_WRITER))
1373 		return (EBUSY);
1374 	eswp->exec_func = NULL;
1375 	eswp->exec_core = NULL;
1376 	rw_exit(eswp->exec_lock);
1377 	return (0);
1378 }
1379 
1380 /*
1381  * Find a free sysent entry or check if the specified one is free.
1382  */
1383 static struct sysent *
1384 mod_getsysent(struct modlinkage *modlp, struct sysent *se)
1385 {
1386 	int sysnum;
1387 	struct modctl *mcp;
1388 	char *mod_name;
1389 
1390 	if ((mcp = mod_getctl(modlp)) == NULL) {
1391 		/*
1392 		 * This happens when we're looking up the module
1393 		 * pointer as part of a stub installation.  So
1394 		 * there's no need to whine at this point.
1395 		 */
1396 		return (NULL);
1397 	}
1398 
1399 	mod_name = mcp->mod_modname;
1400 
1401 	if ((sysnum = mod_getsysnum(mod_name)) == -1) {
1402 		cmn_err(CE_WARN, "system call missing from bind file");
1403 		return (NULL);
1404 	}
1405 
1406 	if (sysnum > 0 && sysnum < NSYSCALL &&
1407 	    (se[sysnum].sy_flags & (SE_LOADABLE | SE_NOUNLOAD)))
1408 		return (se + sysnum);
1409 
1410 	cmn_err(CE_WARN, "system call entry %d is already in use", sysnum);
1411 	return (NULL);
1412 }
1413 
1414 /*
1415  * IP Policy Modules.
1416  */
1417 /*ARGSUSED*/
1418 static int
1419 mod_infoipp(struct modlipp *modl, struct modlinkage *modlp, int *p0)
1420 {
1421 	struct modctl *mcp = mod_getctl(modlp);
1422 	ipp_mod_id_t mid;
1423 
1424 	if (mcp == NULL) {
1425 		*p0 = -1;
1426 		return (0);	/* module is not yet installed */
1427 	}
1428 
1429 	mid = ipp_mod_lookup(mcp->mod_modname);
1430 
1431 	*p0 = mid;
1432 	return (0);
1433 }
1434 
1435 static int
1436 mod_installipp(struct modlipp *modl, struct modlinkage *modlp)
1437 {
1438 	struct modctl *mcp = mod_getctl(modlp);
1439 
1440 	ASSERT(mcp != NULL);
1441 	return (ipp_mod_register(mcp->mod_modname, modl->ipp_ops));
1442 }
1443 
1444 /*ARGSUSED*/
1445 static int
1446 mod_removeipp(struct modlipp *modl, struct modlinkage *modlp)
1447 {
1448 	struct modctl *mcp = mod_getctl(modlp);
1449 	extern kthread_id_t mod_aul_thread;
1450 	ipp_mod_id_t mid;
1451 
1452 	ASSERT(mcp != NULL);
1453 
1454 	if ((moddebug & MODDEBUG_NOAUL_IPP) && (mod_aul_thread == curthread))
1455 		return (EBUSY);
1456 
1457 	mid = ipp_mod_lookup(mcp->mod_modname);
1458 	ASSERT(mid != IPP_MOD_INVAL);
1459 
1460 	return (ipp_mod_unregister(mid));
1461 }
1462 
1463 /*
1464  * Manage kiconv modules.
1465  */
1466 /*ARGSUSED*/
1467 static int
1468 mod_installkiconv(struct modlkiconv *modl, struct modlinkage *modlp)
1469 {
1470 	return (kiconv_register_module(modl->kiconv_moddef));
1471 }
1472 
1473 /*ARGSUSED*/
1474 static int
1475 mod_removekiconv(struct modlkiconv *modl, struct modlinkage *modlp)
1476 {
1477 	return (kiconv_unregister_module(modl->kiconv_moddef));
1478 }
1479