10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51488Srsb * Common Development and Distribution License (the "License"). 61488Srsb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*10097SEric.Taylor@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/systm.h> 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/user.h> 300Sstevel@tonic-gate #include <sys/vm.h> 310Sstevel@tonic-gate #include <sys/conf.h> 320Sstevel@tonic-gate #include <sys/class.h> 330Sstevel@tonic-gate #include <sys/vfs.h> 341488Srsb #include <sys/vnode.h> 350Sstevel@tonic-gate #include <sys/mount.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/modctl.h> 380Sstevel@tonic-gate #include <sys/exec.h> 390Sstevel@tonic-gate #include <sys/exechdr.h> 400Sstevel@tonic-gate #include <sys/devops.h> 410Sstevel@tonic-gate #include <sys/ddi.h> 420Sstevel@tonic-gate #include <sys/sunddi.h> 430Sstevel@tonic-gate #include <sys/cmn_err.h> 440Sstevel@tonic-gate #include <sys/hwconf.h> 450Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 460Sstevel@tonic-gate #include <sys/autoconf.h> 470Sstevel@tonic-gate #include <sys/disp.h> 480Sstevel@tonic-gate #include <sys/kmem.h> 490Sstevel@tonic-gate #include <sys/instance.h> 500Sstevel@tonic-gate #include <sys/modhash.h> 510Sstevel@tonic-gate #include <sys/dacf.h> 520Sstevel@tonic-gate #include <sys/debug.h> 530Sstevel@tonic-gate #include <ipp/ipp.h> 540Sstevel@tonic-gate #include <sys/strsubr.h> 550Sstevel@tonic-gate #include <sys/kcpc.h> 562712Snn35248 #include <sys/brand.h> 570Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 581488Srsb #include <sys/kstat.h> 598348SEric.Yu@Sun.COM #include <sys/socketvar.h> 605206Sis #include <sys/kiconv.h> 610Sstevel@tonic-gate 620Sstevel@tonic-gate extern int moddebug; 630Sstevel@tonic-gate 640Sstevel@tonic-gate extern struct cb_ops no_cb_ops; 650Sstevel@tonic-gate extern struct dev_ops nodev_ops; 660Sstevel@tonic-gate extern struct dev_ops mod_nodev_ops; 670Sstevel@tonic-gate 680Sstevel@tonic-gate extern struct modctl *mod_getctl(struct modlinkage *); 690Sstevel@tonic-gate extern int errsys(), nodev(), nulldev(); 700Sstevel@tonic-gate 710Sstevel@tonic-gate extern int findmodbyname(char *); 720Sstevel@tonic-gate extern int mod_getsysnum(char *); 730Sstevel@tonic-gate 740Sstevel@tonic-gate extern struct execsw execsw[]; 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* 770Sstevel@tonic-gate * Define dev_ops for unused devopsp entry. 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate struct dev_ops mod_nodev_ops = { 800Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 810Sstevel@tonic-gate 0, /* refcnt */ 820Sstevel@tonic-gate ddi_no_info, /* info */ 830Sstevel@tonic-gate nulldev, /* identify */ 840Sstevel@tonic-gate nulldev, /* probe */ 850Sstevel@tonic-gate ddifail, /* attach */ 860Sstevel@tonic-gate nodev, /* detach */ 870Sstevel@tonic-gate nulldev, /* reset */ 880Sstevel@tonic-gate &no_cb_ops, /* character/block driver operations */ 890Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations for nexus drivers */ 900Sstevel@tonic-gate }; 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Define mod_ops for each supported module type 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * Null operations; used for uninitialized and "misc" modules. 980Sstevel@tonic-gate */ 990Sstevel@tonic-gate static int mod_null(struct modldrv *, struct modlinkage *); 1000Sstevel@tonic-gate static int mod_infonull(void *, struct modlinkage *, int *); 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate struct mod_ops mod_miscops = { 1030Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1061414Scindi /* CPU Modules */ 1071414Scindi struct mod_ops mod_cpuops = { 1081414Scindi mod_null, mod_null, mod_infonull 1091414Scindi }; 1101414Scindi 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * Cryptographic Modules 1130Sstevel@tonic-gate */ 1140Sstevel@tonic-gate struct mod_ops mod_cryptoops = { 1150Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1160Sstevel@tonic-gate }; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * IP Policy Modules 1200Sstevel@tonic-gate */ 1210Sstevel@tonic-gate static int mod_installipp(struct modlipp *, struct modlinkage *); 1220Sstevel@tonic-gate static int mod_removeipp(struct modlipp *, struct modlinkage *); 1230Sstevel@tonic-gate static int mod_infoipp(struct modlipp *, struct modlinkage *, int *); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate struct mod_ops mod_ippops = { 1260Sstevel@tonic-gate mod_installipp, mod_removeipp, mod_infoipp 1270Sstevel@tonic-gate }; 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * Device drivers 1310Sstevel@tonic-gate */ 1320Sstevel@tonic-gate static int mod_infodrv(struct modldrv *, struct modlinkage *, int *); 1330Sstevel@tonic-gate static int mod_installdrv(struct modldrv *, struct modlinkage *); 1340Sstevel@tonic-gate static int mod_removedrv(struct modldrv *, struct modlinkage *); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate struct mod_ops mod_driverops = { 1370Sstevel@tonic-gate mod_installdrv, mod_removedrv, mod_infodrv 1380Sstevel@tonic-gate }; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * System calls (new interface) 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate static int mod_infosys(struct modlsys *, struct modlinkage *, int *); 1440Sstevel@tonic-gate static int mod_installsys(struct modlsys *, struct modlinkage *); 1450Sstevel@tonic-gate static int mod_removesys(struct modlsys *, struct modlinkage *); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate struct mod_ops mod_syscallops = { 1480Sstevel@tonic-gate mod_installsys, mod_removesys, mod_infosys 1490Sstevel@tonic-gate }; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * 32-bit system calls in 64-bit kernel 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate static int mod_infosys32(struct modlsys *, struct modlinkage *, int *); 1560Sstevel@tonic-gate static int mod_installsys32(struct modlsys *, struct modlinkage *); 1570Sstevel@tonic-gate static int mod_removesys32(struct modlsys *, struct modlinkage *); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate struct mod_ops mod_syscallops32 = { 1600Sstevel@tonic-gate mod_installsys32, mod_removesys32, mod_infosys32 1610Sstevel@tonic-gate }; 1620Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * Filesystems 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate static int mod_infofs(struct modlfs *, struct modlinkage *, int *); 1680Sstevel@tonic-gate static int mod_installfs(struct modlfs *, struct modlinkage *); 1690Sstevel@tonic-gate static int mod_removefs(struct modlfs *, struct modlinkage *); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate struct mod_ops mod_fsops = { 1720Sstevel@tonic-gate mod_installfs, mod_removefs, mod_infofs 1730Sstevel@tonic-gate }; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * Streams modules. 1770Sstevel@tonic-gate */ 1780Sstevel@tonic-gate static int mod_infostrmod(struct modlstrmod *, struct modlinkage *, int *); 1790Sstevel@tonic-gate static int mod_installstrmod(struct modlstrmod *, struct modlinkage *); 1800Sstevel@tonic-gate static int mod_removestrmod(struct modlstrmod *, struct modlinkage *); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate struct mod_ops mod_strmodops = { 1830Sstevel@tonic-gate mod_installstrmod, mod_removestrmod, mod_infostrmod 1840Sstevel@tonic-gate }; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1878348SEric.Yu@Sun.COM * Socket modules. 1888348SEric.Yu@Sun.COM */ 1898348SEric.Yu@Sun.COM static int mod_infosockmod(struct modlsockmod *, struct modlinkage *, int *); 1908348SEric.Yu@Sun.COM static int mod_installsockmod(struct modlsockmod *, struct modlinkage *); 1918348SEric.Yu@Sun.COM static int mod_removesockmod(struct modlsockmod *, struct modlinkage *); 1928348SEric.Yu@Sun.COM 1938348SEric.Yu@Sun.COM struct mod_ops mod_sockmodops = { 1948348SEric.Yu@Sun.COM mod_installsockmod, mod_removesockmod, mod_infosockmod 1958348SEric.Yu@Sun.COM }; 1968348SEric.Yu@Sun.COM 1978348SEric.Yu@Sun.COM /* 1980Sstevel@tonic-gate * Scheduling classes. 1990Sstevel@tonic-gate */ 2000Sstevel@tonic-gate static int mod_infosched(struct modlsched *, struct modlinkage *, int *); 2010Sstevel@tonic-gate static int mod_installsched(struct modlsched *, struct modlinkage *); 2020Sstevel@tonic-gate static int mod_removesched(struct modlsched *, struct modlinkage *); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate struct mod_ops mod_schedops = { 2050Sstevel@tonic-gate mod_installsched, mod_removesched, mod_infosched 2060Sstevel@tonic-gate }; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * Exec file type (like ELF, ...). 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate static int mod_infoexec(struct modlexec *, struct modlinkage *, int *); 2120Sstevel@tonic-gate static int mod_installexec(struct modlexec *, struct modlinkage *); 2130Sstevel@tonic-gate static int mod_removeexec(struct modlexec *, struct modlinkage *); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate struct mod_ops mod_execops = { 2160Sstevel@tonic-gate mod_installexec, mod_removeexec, mod_infoexec 2170Sstevel@tonic-gate }; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * Dacf (Dynamic Autoconfiguration) modules. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate static int mod_infodacf(struct modldacf *, struct modlinkage *, int *); 2230Sstevel@tonic-gate static int mod_installdacf(struct modldacf *, struct modlinkage *); 2240Sstevel@tonic-gate static int mod_removedacf(struct modldacf *, struct modlinkage *); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate struct mod_ops mod_dacfops = { 2270Sstevel@tonic-gate mod_installdacf, mod_removedacf, mod_infodacf 2280Sstevel@tonic-gate }; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * PCBE (Performance Counter BackEnd) modules. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate static int mod_installpcbe(struct modlpcbe *, struct modlinkage *); 2340Sstevel@tonic-gate static int mod_removepcbe(struct modlpcbe *, struct modlinkage *); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate struct mod_ops mod_pcbeops = { 2370Sstevel@tonic-gate mod_installpcbe, mod_removepcbe, mod_infonull 2380Sstevel@tonic-gate }; 2390Sstevel@tonic-gate 2402712Snn35248 /* 2412712Snn35248 * Brand modules. 2422712Snn35248 */ 2432712Snn35248 static int mod_installbrand(struct modlbrand *, struct modlinkage *); 2442712Snn35248 static int mod_removebrand(struct modlbrand *, struct modlinkage *); 2452712Snn35248 2462712Snn35248 struct mod_ops mod_brandops = { 2472712Snn35248 mod_installbrand, mod_removebrand, mod_infonull 2482712Snn35248 }; 2492712Snn35248 2505206Sis /* 2515206Sis * kiconv modules. 2525206Sis */ 2535206Sis static int mod_installkiconv(struct modlkiconv *, struct modlinkage *); 2545206Sis static int mod_removekiconv(struct modlkiconv *, struct modlinkage *); 2555206Sis 2565206Sis struct mod_ops mod_kiconvops = { 2575206Sis mod_installkiconv, mod_removekiconv, mod_infonull 2585206Sis }; 2595206Sis 2600Sstevel@tonic-gate static struct sysent *mod_getsysent(struct modlinkage *, struct sysent *); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate static char uninstall_err[] = "Cannot uninstall %s; not installed"; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * Debugging support 2660Sstevel@tonic-gate */ 2670Sstevel@tonic-gate #define DRV_DBG MODDEBUG_LOADMSG2 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /*PRINTFLIKE2*/ 2700Sstevel@tonic-gate static void mod_dprintf(int flag, const char *format, ...) __KPRINTFLIKE(2); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate static void 2730Sstevel@tonic-gate mod_dprintf(int flag, const char *format, ...) 2740Sstevel@tonic-gate { 2750Sstevel@tonic-gate va_list alist; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if ((moddebug & flag) != 0) { 2780Sstevel@tonic-gate va_start(alist, format); 2790Sstevel@tonic-gate (void) vprintf(format, alist); 2800Sstevel@tonic-gate va_end(alist); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* 2850Sstevel@tonic-gate * Install a module. 2860Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate int 2890Sstevel@tonic-gate mod_install(struct modlinkage *modlp) 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate int retval = -1; /* No linkage structures */ 2920Sstevel@tonic-gate struct modlmisc **linkpp; 2930Sstevel@tonic-gate struct modlmisc **linkpp1; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if (modlp->ml_rev != MODREV_1) { 2960Sstevel@tonic-gate printf("mod_install: modlinkage structure is not MODREV_1\n"); 2970Sstevel@tonic-gate return (EINVAL); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate while (*linkpp != NULL) { 3020Sstevel@tonic-gate if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) { 3030Sstevel@tonic-gate linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0]; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate while (linkpp1 != linkpp) { 3060Sstevel@tonic-gate MODL_REMOVE(*linkpp1, modlp); /* clean up */ 3070Sstevel@tonic-gate linkpp1++; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate break; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate linkpp++; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate return (retval); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate static char *reins_err = 3170Sstevel@tonic-gate "Could not reinstall %s\nReboot to correct the problem"; 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * Remove a module. This is called by the module wrapper routine. 3210Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate int 3240Sstevel@tonic-gate mod_remove(struct modlinkage *modlp) 3250Sstevel@tonic-gate { 3260Sstevel@tonic-gate int retval = 0; 3270Sstevel@tonic-gate struct modlmisc **linkpp, *last_linkp; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate while (*linkpp != NULL) { 3320Sstevel@tonic-gate if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) { 3330Sstevel@tonic-gate last_linkp = *linkpp; 3340Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3350Sstevel@tonic-gate while (*linkpp != last_linkp) { 3360Sstevel@tonic-gate if (MODL_INSTALL(*linkpp, modlp) != 0) { 3370Sstevel@tonic-gate cmn_err(CE_WARN, reins_err, 3385206Sis (*linkpp)->misc_linkinfo); 3390Sstevel@tonic-gate break; 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate linkpp++; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate break; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate linkpp++; 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate return (retval); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /* 3510Sstevel@tonic-gate * Get module status. 3520Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3530Sstevel@tonic-gate */ 3540Sstevel@tonic-gate int 3550Sstevel@tonic-gate mod_info(struct modlinkage *modlp, struct modinfo *modinfop) 3560Sstevel@tonic-gate { 3570Sstevel@tonic-gate int i; 3580Sstevel@tonic-gate int retval = 0; 3590Sstevel@tonic-gate struct modspecific_info *msip; 3600Sstevel@tonic-gate struct modlmisc **linkpp; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate modinfop->mi_rev = modlp->ml_rev; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate linkpp = (struct modlmisc **)modlp->ml_linkage; 3650Sstevel@tonic-gate msip = &modinfop->mi_msinfo[0]; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate for (i = 0; i < MODMAXLINK; i++) { 3680Sstevel@tonic-gate if (*linkpp == NULL) { 3690Sstevel@tonic-gate msip->msi_linkinfo[0] = '\0'; 3700Sstevel@tonic-gate } else { 3710Sstevel@tonic-gate (void) strncpy(msip->msi_linkinfo, 3720Sstevel@tonic-gate (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN); 3730Sstevel@tonic-gate retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0); 3740Sstevel@tonic-gate if (retval != 0) 3750Sstevel@tonic-gate break; 3760Sstevel@tonic-gate linkpp++; 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate msip++; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate if (modinfop->mi_info == MI_INFO_LINKAGE) { 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Slight kludge used to extract the address of the 3840Sstevel@tonic-gate * modlinkage structure from the module (just after 3850Sstevel@tonic-gate * loading a module for the very first time) 3860Sstevel@tonic-gate */ 3870Sstevel@tonic-gate modinfop->mi_base = (void *)modlp; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if (retval == 0) 3910Sstevel@tonic-gate return (1); 3920Sstevel@tonic-gate return (0); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * Get module name. 3970Sstevel@tonic-gate */ 3987009Scth const char * 3990Sstevel@tonic-gate mod_modname(struct modlinkage *modlp) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate struct modctl *mcp; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4040Sstevel@tonic-gate return (NULL); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate return (mcp->mod_modname); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Null operation; return 0. 4110Sstevel@tonic-gate */ 4120Sstevel@tonic-gate /*ARGSUSED*/ 4130Sstevel@tonic-gate static int 4140Sstevel@tonic-gate mod_null(struct modldrv *modl, struct modlinkage *modlp) 4150Sstevel@tonic-gate { 4160Sstevel@tonic-gate return (0); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * Status for User modules. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate /*ARGSUSED*/ 4230Sstevel@tonic-gate static int 4240Sstevel@tonic-gate mod_infonull(void *modl, struct modlinkage *modlp, int *p0) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate *p0 = -1; /* for modinfo display */ 4270Sstevel@tonic-gate return (0); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate /* 4310Sstevel@tonic-gate * Driver status info 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate /*ARGSUSED*/ 4340Sstevel@tonic-gate static int 4350Sstevel@tonic-gate mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate struct modctl *mcp; 4380Sstevel@tonic-gate char *mod_name; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 4410Sstevel@tonic-gate *p0 = -1; 4420Sstevel@tonic-gate return (0); /* driver is not yet installed */ 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate mod_name = mcp->mod_modname; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate *p0 = ddi_name_to_major(mod_name); 4480Sstevel@tonic-gate return (0); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * Manage dacf (device autoconfiguration) modules 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /*ARGSUSED*/ 4560Sstevel@tonic-gate static int 4570Sstevel@tonic-gate mod_infodacf(struct modldacf *modl, struct modlinkage *modlp, int *p0) 4580Sstevel@tonic-gate { 4590Sstevel@tonic-gate if (mod_getctl(modlp) == NULL) { 4600Sstevel@tonic-gate *p0 = -1; 4610Sstevel@tonic-gate return (0); /* module is not yet installed */ 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate *p0 = 0; 4650Sstevel@tonic-gate return (0); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate static int 4690Sstevel@tonic-gate mod_installdacf(struct modldacf *modl, struct modlinkage *modlp) 4700Sstevel@tonic-gate { 4710Sstevel@tonic-gate struct modctl *mcp; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4740Sstevel@tonic-gate return (EINVAL); 4750Sstevel@tonic-gate return (dacf_module_register(mcp->mod_modname, modl->dacf_dacfsw)); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /*ARGSUSED*/ 4790Sstevel@tonic-gate static int 4800Sstevel@tonic-gate mod_removedacf(struct modldacf *modl, struct modlinkage *modlp) 4810Sstevel@tonic-gate { 4820Sstevel@tonic-gate struct modctl *mcp; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4850Sstevel@tonic-gate return (EINVAL); 4860Sstevel@tonic-gate return (dacf_module_unregister(mcp->mod_modname)); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* 4900Sstevel@tonic-gate * Manage PCBE (Performance Counter BackEnd) modules. 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate /*ARGSUSED*/ 4930Sstevel@tonic-gate static int 4940Sstevel@tonic-gate mod_installpcbe(struct modlpcbe *modl, struct modlinkage *modlp) 4950Sstevel@tonic-gate { 4960Sstevel@tonic-gate if (modl->pcbe_ops->pcbe_ver != PCBE_VER_1) { 4970Sstevel@tonic-gate cmn_err(CE_WARN, "pcbe '%s' version mismatch", 4980Sstevel@tonic-gate modl->pcbe_linkinfo); 4990Sstevel@tonic-gate return (EINVAL); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate kcpc_register_pcbe(modl->pcbe_ops); 5030Sstevel@tonic-gate return (0); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * PCBEs may not be unloaded. It would make CPC locking too complex, and since 5080Sstevel@tonic-gate * PCBEs are loaded once and used for life, there is no harm done in leaving 5090Sstevel@tonic-gate * them in the system. 5100Sstevel@tonic-gate */ 5110Sstevel@tonic-gate /*ARGSUSED*/ 5120Sstevel@tonic-gate static int 5130Sstevel@tonic-gate mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp) 5140Sstevel@tonic-gate { 5150Sstevel@tonic-gate return (EBUSY); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5182621Sllai1 /* 5192712Snn35248 * Manage BrandZ modules. 5202712Snn35248 */ 5212712Snn35248 /*ARGSUSED*/ 5222712Snn35248 static int 5232712Snn35248 mod_installbrand(struct modlbrand *modl, struct modlinkage *modlp) 5242712Snn35248 { 5252712Snn35248 return (brand_register(modl->brand_branddef)); 5262712Snn35248 } 5272712Snn35248 5282712Snn35248 /*ARGSUSED*/ 5292712Snn35248 static int 5302712Snn35248 mod_removebrand(struct modlbrand *modl, struct modlinkage *modlp) 5312712Snn35248 { 5322712Snn35248 return (brand_unregister(modl->brand_branddef)); 5332712Snn35248 } 5342712Snn35248 5352712Snn35248 /* 5360Sstevel@tonic-gate * Install a new driver 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate static int 5390Sstevel@tonic-gate mod_installdrv(struct modldrv *modl, struct modlinkage *modlp) 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate struct modctl *mcp; 5420Sstevel@tonic-gate struct dev_ops *ops; 5430Sstevel@tonic-gate char *modname; 5440Sstevel@tonic-gate major_t major; 5450Sstevel@tonic-gate struct dev_ops *dp; 5460Sstevel@tonic-gate struct devnames *dnp; 5470Sstevel@tonic-gate struct streamtab *str; 5480Sstevel@tonic-gate cdevsw_impl_t *cdp; 5490Sstevel@tonic-gate uint_t sqtype; 5500Sstevel@tonic-gate uint_t qflag; 5510Sstevel@tonic-gate uint_t flag; 5520Sstevel@tonic-gate int err = 0; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* sanity check module */ 5550Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 5560Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: bad module linkage data"); 5570Sstevel@tonic-gate err = ENXIO; 5580Sstevel@tonic-gate goto done; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate modname = mcp->mod_modname; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* Sanity check modname */ 5637009Scth if ((major = ddi_name_to_major(modname)) == DDI_MAJOR_T_NONE) { 5640Sstevel@tonic-gate #ifdef DEBUG 5650Sstevel@tonic-gate cmn_err(CE_WARN, 5660Sstevel@tonic-gate "mod_installdrv: no major number for %s", modname); 5670Sstevel@tonic-gate #endif 5680Sstevel@tonic-gate err = ENXIO; 5690Sstevel@tonic-gate goto done; 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* Verify MP safety flag */ 5730Sstevel@tonic-gate ops = modl->drv_dev_ops; 5740Sstevel@tonic-gate if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL && 5750Sstevel@tonic-gate !(ops->devo_cb_ops->cb_flag & D_MP)) { 5760Sstevel@tonic-gate cmn_err(CE_WARN, 5770Sstevel@tonic-gate "mod_installdrv: MT-unsafe driver '%s' rejected", modname); 5780Sstevel@tonic-gate err = ENXIO; 5790Sstevel@tonic-gate goto done; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* Is bus_map_fault signature correct (version 8 and higher)? */ 5840Sstevel@tonic-gate if (ops->devo_bus_ops != NULL && 5850Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != NULL && 5860Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault && 5870Sstevel@tonic-gate ops->devo_bus_ops->busops_rev < BUSO_REV_8) { 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate cmn_err(CE_WARN, 5900Sstevel@tonic-gate "mod_installdrv: busops' revision of '%s' is too low" 5910Sstevel@tonic-gate " (must be at least 8)", modname); 5920Sstevel@tonic-gate err = ENXIO; 5930Sstevel@tonic-gate goto done; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate /* Make sure the driver is uninstalled */ 5980Sstevel@tonic-gate dnp = &devnamesp[major]; 5990Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 6000Sstevel@tonic-gate dp = devopsp[major]; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate if (dnp->dn_flags & DN_DRIVER_REMOVED) { 6030Sstevel@tonic-gate #ifdef DEBUG 6040Sstevel@tonic-gate cmn_err(CE_NOTE, 6050Sstevel@tonic-gate "mod_installdrv: driver has been removed %s", modname); 6060Sstevel@tonic-gate #endif 6070Sstevel@tonic-gate err = ENXIO; 6080Sstevel@tonic-gate goto unlock; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate if (dp != &nodev_ops && dp != &mod_nodev_ops) { 6120Sstevel@tonic-gate cmn_err(CE_WARN, 6130Sstevel@tonic-gate "mod_installdrv: driver already installed %s", modname); 6140Sstevel@tonic-gate err = EALREADY; 6150Sstevel@tonic-gate goto unlock; 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate devopsp[major] = ops; /* setup devopsp */ 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 6210Sstevel@tonic-gate flag = CBFLAG(major); 6220Sstevel@tonic-gate if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0) 6230Sstevel@tonic-gate goto unlock; 6240Sstevel@tonic-gate cdp = &devimpl[major]; 6250Sstevel@tonic-gate ASSERT(cdp->d_str == NULL); 6260Sstevel@tonic-gate cdp->d_str = str; 6270Sstevel@tonic-gate cdp->d_qflag = qflag | QISDRV; 6280Sstevel@tonic-gate cdp->d_sqtype = sqtype; 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (ops->devo_bus_ops == NULL) 6320Sstevel@tonic-gate dnp->dn_flags |= DN_LEAF_DRIVER; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate unlock: 6350Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 6360Sstevel@tonic-gate done: 6370Sstevel@tonic-gate return (err); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate static int 6410Sstevel@tonic-gate mod_removedrv(struct modldrv *modl, struct modlinkage *modlp) 6420Sstevel@tonic-gate { 6430Sstevel@tonic-gate struct modctl *mcp; 6440Sstevel@tonic-gate struct dev_ops *ops; 6450Sstevel@tonic-gate struct devnames *dnp; 6460Sstevel@tonic-gate struct dev_ops *dp; 6470Sstevel@tonic-gate major_t major; 6480Sstevel@tonic-gate char *modname; 6490Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 6500Sstevel@tonic-gate struct streamtab *str; 6510Sstevel@tonic-gate cdevsw_impl_t *cdp; 6520Sstevel@tonic-gate int err = 0; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* Don't auto unload modules on if moddebug flag is set */ 6550Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) { 6560Sstevel@tonic-gate err = EBUSY; 6570Sstevel@tonic-gate goto done; 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate /* Verify modname has a driver major */ 6610Sstevel@tonic-gate mcp = mod_getctl(modlp); 6620Sstevel@tonic-gate ASSERT(mcp != NULL); 6630Sstevel@tonic-gate modname = mcp->mod_modname; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate if ((major = ddi_name_to_major(modname)) == -1) { 6660Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 6670Sstevel@tonic-gate err = EINVAL; 6680Sstevel@tonic-gate goto done; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate ops = modl->drv_dev_ops; 6720Sstevel@tonic-gate dnp = &(devnamesp[major]); 6730Sstevel@tonic-gate LOCK_DEV_OPS(&(dnp->dn_lock)); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate dp = devopsp[major]; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate if (dp != ops) { 6780Sstevel@tonic-gate cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s", 6790Sstevel@tonic-gate modname); 6800Sstevel@tonic-gate err = EBUSY; 6810Sstevel@tonic-gate goto unlock; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate /* 6850Sstevel@tonic-gate * A driver is not unloadable if its dev_ops are held 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate if (!DRV_UNLOADABLE(dp)) { 6880Sstevel@tonic-gate mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>," 6890Sstevel@tonic-gate " refcnt %d\n", modname, dp->devo_refcnt); 6900Sstevel@tonic-gate err = EBUSY; 6910Sstevel@tonic-gate goto unlock; 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * OK to unload. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 6980Sstevel@tonic-gate cdp = &devimpl[major]; 6990Sstevel@tonic-gate ASSERT(cdp->d_str == str); 7000Sstevel@tonic-gate cdp->d_str = NULL; 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* check for reference to per-dev syncq */ 7030Sstevel@tonic-gate if (cdp->d_dmp != NULL) { 7040Sstevel@tonic-gate rele_dm(cdp->d_dmp); 7050Sstevel@tonic-gate cdp->d_dmp = NULL; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate devopsp[major] = &mod_nodev_ops; 7100Sstevel@tonic-gate dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate unlock: 7130Sstevel@tonic-gate UNLOCK_DEV_OPS(&(dnp->dn_lock)); 7140Sstevel@tonic-gate done: 7150Sstevel@tonic-gate return (err); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* 7190Sstevel@tonic-gate * System call subroutines 7200Sstevel@tonic-gate */ 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * Compute system call number for given sysent and sysent table 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate static int 7260Sstevel@tonic-gate mod_infosysnum(struct modlinkage *modlp, struct sysent table[]) 7270Sstevel@tonic-gate { 7280Sstevel@tonic-gate struct sysent *sysp; 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 7310Sstevel@tonic-gate return (-1); 7320Sstevel@tonic-gate return ((int)(sysp - table)); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* 7360Sstevel@tonic-gate * Put a loadable system call entry into a sysent table. 7370Sstevel@tonic-gate */ 7380Sstevel@tonic-gate static int 7390Sstevel@tonic-gate mod_installsys_sysent( 7400Sstevel@tonic-gate struct modlsys *modl, 7410Sstevel@tonic-gate struct modlinkage *modlp, 7420Sstevel@tonic-gate struct sysent table[]) 7430Sstevel@tonic-gate { 7440Sstevel@tonic-gate struct sysent *sysp; 7450Sstevel@tonic-gate struct sysent *mp; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate #ifdef DEBUG 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Before we even play with the sysent table, sanity check the 7500Sstevel@tonic-gate * incoming flags to make sure the entry is valid 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate switch (modl->sys_sysent->sy_flags & SE_RVAL_MASK) { 7530Sstevel@tonic-gate case SE_32RVAL1: 7540Sstevel@tonic-gate /* only r_val1 returned */ 7550Sstevel@tonic-gate case SE_32RVAL1 | SE_32RVAL2: 7560Sstevel@tonic-gate /* r_val1 and r_val2 returned */ 7570Sstevel@tonic-gate case SE_64RVAL: 7580Sstevel@tonic-gate /* 64-bit rval returned */ 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate default: 7610Sstevel@tonic-gate cmn_err(CE_WARN, "loadable syscall: %p: bad rval flags %x", 7620Sstevel@tonic-gate (void *)modl, modl->sys_sysent->sy_flags); 7630Sstevel@tonic-gate return (ENOSYS); 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate #endif 7660Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 7670Sstevel@tonic-gate return (ENOSPC); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* 7700Sstevel@tonic-gate * We should only block here until the reader in syscall gives 7710Sstevel@tonic-gate * up the lock. Multiple writers are prevented in the mod layer. 7720Sstevel@tonic-gate */ 7730Sstevel@tonic-gate rw_enter(sysp->sy_lock, RW_WRITER); 7740Sstevel@tonic-gate mp = modl->sys_sysent; 7750Sstevel@tonic-gate sysp->sy_narg = mp->sy_narg; 7760Sstevel@tonic-gate sysp->sy_call = mp->sy_call; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * clear the old call method flag, and get the new one from the module. 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate sysp->sy_flags &= ~SE_ARGC; 7820Sstevel@tonic-gate sysp->sy_flags |= SE_LOADED | 7830Sstevel@tonic-gate (mp->sy_flags & (SE_ARGC | SE_NOUNLOAD | SE_RVAL_MASK)); 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate /* 7860Sstevel@tonic-gate * If the syscall doesn't need or want unloading, it can avoid 7870Sstevel@tonic-gate * the locking overhead on each entry. Convert the sysent to a 7880Sstevel@tonic-gate * normal non-loadable entry in that case. 7890Sstevel@tonic-gate */ 7900Sstevel@tonic-gate if (mp->sy_flags & SE_NOUNLOAD) { 7910Sstevel@tonic-gate if (mp->sy_flags & SE_ARGC) { 7920Sstevel@tonic-gate sysp->sy_callc = (int64_t (*)())mp->sy_call; 7930Sstevel@tonic-gate } else { 7940Sstevel@tonic-gate sysp->sy_callc = syscall_ap; 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADABLE; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate rw_exit(sysp->sy_lock); 7990Sstevel@tonic-gate return (0); 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* 8030Sstevel@tonic-gate * Remove a loadable system call entry from a sysent table. 8040Sstevel@tonic-gate */ 8050Sstevel@tonic-gate static int 8060Sstevel@tonic-gate mod_removesys_sysent( 8070Sstevel@tonic-gate struct modlsys *modl, 8080Sstevel@tonic-gate struct modlinkage *modlp, 8090Sstevel@tonic-gate struct sysent table[]) 8100Sstevel@tonic-gate { 8110Sstevel@tonic-gate struct sysent *sysp; 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL || 8140Sstevel@tonic-gate (sysp->sy_flags & (SE_LOADABLE | SE_NOUNLOAD)) == 0 || 8150Sstevel@tonic-gate sysp->sy_call != modl->sys_sysent->sy_call) { 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 8180Sstevel@tonic-gate char *modname = mcp->mod_modname; 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 8210Sstevel@tonic-gate return (EINVAL); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* If we can't get the write lock, we can't unlink from the system */ 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate if (!(moddebug & MODDEBUG_NOAUL_SYS) && 8270Sstevel@tonic-gate rw_tryenter(sysp->sy_lock, RW_WRITER)) { 8280Sstevel@tonic-gate /* 8290Sstevel@tonic-gate * Check the flags to be sure the syscall is still 8300Sstevel@tonic-gate * (un)loadable. 8310Sstevel@tonic-gate * If SE_NOUNLOAD is set, SE_LOADABLE will not be. 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate if ((sysp->sy_flags & (SE_LOADED | SE_LOADABLE)) == 8340Sstevel@tonic-gate (SE_LOADED | SE_LOADABLE)) { 8350Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADED; 8360Sstevel@tonic-gate sysp->sy_callc = loadable_syscall; 8370Sstevel@tonic-gate sysp->sy_call = (int (*)())nosys; 8380Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8390Sstevel@tonic-gate return (0); 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate return (EBUSY); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * System call status info 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate /*ARGSUSED*/ 8500Sstevel@tonic-gate static int 8510Sstevel@tonic-gate mod_infosys(struct modlsys *modl, struct modlinkage *modlp, int *p0) 8520Sstevel@tonic-gate { 8530Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent); 8540Sstevel@tonic-gate return (0); 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate /* 8580Sstevel@tonic-gate * Link a system call into the system by setting the proper sysent entry. 8590Sstevel@tonic-gate * Called from the module's _init routine. 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate static int 8620Sstevel@tonic-gate mod_installsys(struct modlsys *modl, struct modlinkage *modlp) 8630Sstevel@tonic-gate { 8640Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent)); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Unlink a system call from the system. 8690Sstevel@tonic-gate * Called from a modules _fini routine. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate static int 8720Sstevel@tonic-gate mod_removesys(struct modlsys *modl, struct modlinkage *modlp) 8730Sstevel@tonic-gate { 8740Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent)); 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * 32-bit system call status info 8810Sstevel@tonic-gate */ 8820Sstevel@tonic-gate /*ARGSUSED*/ 8830Sstevel@tonic-gate static int 8840Sstevel@tonic-gate mod_infosys32(struct modlsys *modl, struct modlinkage *modlp, int *p0) 8850Sstevel@tonic-gate { 8860Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent32); 8870Sstevel@tonic-gate return (0); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Link the 32-bit syscall into the system by setting the proper sysent entry. 8920Sstevel@tonic-gate * Also called from the module's _init routine. 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate static int 8950Sstevel@tonic-gate mod_installsys32(struct modlsys *modl, struct modlinkage *modlp) 8960Sstevel@tonic-gate { 8970Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent32)); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate /* 9010Sstevel@tonic-gate * Unlink the 32-bit flavor of a system call from the system. 9020Sstevel@tonic-gate * Also called from a module's _fini routine. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate static int 9050Sstevel@tonic-gate mod_removesys32(struct modlsys *modl, struct modlinkage *modlp) 9060Sstevel@tonic-gate { 9070Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent32)); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate /* 9130Sstevel@tonic-gate * Filesystem status info 9140Sstevel@tonic-gate */ 9150Sstevel@tonic-gate /*ARGSUSED*/ 9160Sstevel@tonic-gate static int 9170Sstevel@tonic-gate mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0) 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate struct vfssw *vswp; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate RLOCK_VFSSW(); 9220Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) 9230Sstevel@tonic-gate *p0 = -1; 9240Sstevel@tonic-gate else { 9250Sstevel@tonic-gate *p0 = vswp - vfssw; 9260Sstevel@tonic-gate vfs_unrefvfssw(vswp); 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate RUNLOCK_VFSSW(); 9290Sstevel@tonic-gate return (0); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* 9330Sstevel@tonic-gate * Install a filesystem. 9340Sstevel@tonic-gate */ 9350Sstevel@tonic-gate /*ARGSUSED1*/ 9360Sstevel@tonic-gate static int 9370Sstevel@tonic-gate mod_installfs(struct modlfs *modl, struct modlinkage *modlp) 9380Sstevel@tonic-gate { 9390Sstevel@tonic-gate struct vfssw *vswp; 9400Sstevel@tonic-gate struct modctl *mcp; 9410Sstevel@tonic-gate char *fsname; 9421488Srsb char ksname[KSTAT_STRLEN + 1]; 9431488Srsb int fstype; /* index into vfssw[] and vsanchor_fstype[] */ 9440Sstevel@tonic-gate int allocated; 9450Sstevel@tonic-gate int err; 9461488Srsb int vsw_stats_enabled; 9471488Srsb /* Not for public consumption so these aren't in a header file */ 9481488Srsb extern int vopstats_enabled; 9491488Srsb extern vopstats_t **vopstats_fstype; 9501488Srsb extern kstat_t *new_vskstat(char *, vopstats_t *); 9511488Srsb extern void initialize_vopstats(vopstats_t *); 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) { 9540Sstevel@tonic-gate /* Version matched */ 9550Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 9560Sstevel@tonic-gate } else { 9570Sstevel@tonic-gate if ((modl->fs_vfsdef->def_version > 0) && 9580Sstevel@tonic-gate (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) { 9590Sstevel@tonic-gate /* Older VFSDEF_VERSION */ 9600Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 9610Sstevel@tonic-gate } else if ((mcp = mod_getctl(modlp)) != NULL) { 9620Sstevel@tonic-gate /* Pre-VFSDEF_VERSION */ 9630Sstevel@tonic-gate fsname = mcp->mod_modname; 9640Sstevel@tonic-gate } else { 9650Sstevel@tonic-gate /* If all else fails... */ 9660Sstevel@tonic-gate fsname = "<unknown file system type>"; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate cmn_err(CE_WARN, "file system '%s' version mismatch", fsname); 9700Sstevel@tonic-gate return (ENXIO); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate allocated = 0; 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate WLOCK_VFSSW(); 9760Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) { 9770Sstevel@tonic-gate if ((vswp = allocate_vfssw(fsname)) == NULL) { 9780Sstevel@tonic-gate WUNLOCK_VFSSW(); 9790Sstevel@tonic-gate /* 9800Sstevel@tonic-gate * See 1095689. If this message appears, then 9810Sstevel@tonic-gate * we either need to make the vfssw table bigger 9820Sstevel@tonic-gate * statically, or make it grow dynamically. 9830Sstevel@tonic-gate */ 9840Sstevel@tonic-gate cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname); 9850Sstevel@tonic-gate return (ENXIO); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate allocated = 1; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate ASSERT(vswp != NULL); 9900Sstevel@tonic-gate 9911488Srsb fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */ 9921488Srsb 9931488Srsb /* Turn on everything by default *except* VSW_STATS */ 9941488Srsb vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS); 9951488Srsb 9960Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_HASPROTO) { 9970Sstevel@tonic-gate vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto, 9980Sstevel@tonic-gate &vswp->vsw_optproto); 9990Sstevel@tonic-gate } else { 10000Sstevel@tonic-gate vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_CANRWRO) { 10040Sstevel@tonic-gate /* 10050Sstevel@tonic-gate * This obviously implies VSW_CANREMOUNT. 10060Sstevel@tonic-gate */ 10070Sstevel@tonic-gate vswp->vsw_flag |= VSW_CANREMOUNT; 10080Sstevel@tonic-gate } 10091488Srsb 10101488Srsb /* 10111488Srsb * If stats are enabled system wide and for this fstype, then 10121488Srsb * set the VSW_STATS flag in the proper vfssw[] table entry. 10131488Srsb */ 10141488Srsb if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) { 10151488Srsb vswp->vsw_flag |= VSW_STATS; 10161488Srsb } 10171488Srsb 10180Sstevel@tonic-gate if (modl->fs_vfsdef->init == NULL) 10190Sstevel@tonic-gate err = EFAULT; 10200Sstevel@tonic-gate else 10211488Srsb err = (*(modl->fs_vfsdef->init))(fstype, fsname); 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate if (err != 0) { 10240Sstevel@tonic-gate if (allocated) { 10250Sstevel@tonic-gate kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1); 10260Sstevel@tonic-gate vswp->vsw_name = ""; 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate vswp->vsw_flag = 0; 10290Sstevel@tonic-gate vswp->vsw_init = NULL; 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10321488Srsb /* We don't want to hold the vfssw[] write lock over a kmem_alloc() */ 10331488Srsb vsw_stats_enabled = vswp->vsw_flag & VSW_STATS; 10341488Srsb 10350Sstevel@tonic-gate vfs_unrefvfssw(vswp); 10360Sstevel@tonic-gate WUNLOCK_VFSSW(); 10370Sstevel@tonic-gate 10381488Srsb /* If everything is on, set up the per-fstype vopstats */ 10391488Srsb if (vsw_stats_enabled && vopstats_enabled && 10401488Srsb vopstats_fstype && vopstats_fstype[fstype] == NULL) { 10411488Srsb (void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname)); 10421488Srsb (void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname)); 10431488Srsb vopstats_fstype[fstype] = 10441488Srsb kmem_alloc(sizeof (vopstats_t), KM_SLEEP); 10451488Srsb initialize_vopstats(vopstats_fstype[fstype]); 10461488Srsb (void) new_vskstat(ksname, vopstats_fstype[fstype]); 10471488Srsb } 10480Sstevel@tonic-gate return (err); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate /* 10520Sstevel@tonic-gate * Remove a filesystem 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate static int 10550Sstevel@tonic-gate mod_removefs(struct modlfs *modl, struct modlinkage *modlp) 10560Sstevel@tonic-gate { 10570Sstevel@tonic-gate struct vfssw *vswp; 10580Sstevel@tonic-gate struct modctl *mcp; 10590Sstevel@tonic-gate char *modname; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_FS) 10620Sstevel@tonic-gate return (EBUSY); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate WLOCK_VFSSW(); 10650Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) { 10660Sstevel@tonic-gate mcp = mod_getctl(modlp); 10670Sstevel@tonic-gate ASSERT(mcp != NULL); 10680Sstevel@tonic-gate modname = mcp->mod_modname; 10690Sstevel@tonic-gate WUNLOCK_VFSSW(); 10700Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 10710Sstevel@tonic-gate return (EINVAL); 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate if (vswp->vsw_count != 1) { 10740Sstevel@tonic-gate vfs_unrefvfssw(vswp); 10750Sstevel@tonic-gate WUNLOCK_VFSSW(); 10760Sstevel@tonic-gate return (EBUSY); 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10792712Snn35248 /* 10802712Snn35248 * A mounted filesystem could still have vsw_count = 0 10812712Snn35248 * so we must check whether anyone is actually using our ops 10822712Snn35248 */ 10830Sstevel@tonic-gate if (vfs_opsinuse(&vswp->vsw_vfsops)) { 10841403Ssp92102 vfs_unrefvfssw(vswp); 10850Sstevel@tonic-gate WUNLOCK_VFSSW(); 10860Sstevel@tonic-gate return (EBUSY); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate vfs_freeopttbl(&vswp->vsw_optproto); 10900Sstevel@tonic-gate vswp->vsw_optproto.mo_count = 0; 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate vswp->vsw_flag = 0; 10930Sstevel@tonic-gate vswp->vsw_init = NULL; 10940Sstevel@tonic-gate vfs_unrefvfssw(vswp); 10950Sstevel@tonic-gate WUNLOCK_VFSSW(); 10960Sstevel@tonic-gate return (0); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * Get status of a streams module. 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate /*ARGSUSED*/ 11030Sstevel@tonic-gate static int 11040Sstevel@tonic-gate mod_infostrmod(struct modlstrmod *modl, struct modlinkage *modlp, int *p0) 11050Sstevel@tonic-gate { 11060Sstevel@tonic-gate *p0 = -1; /* no useful info */ 11070Sstevel@tonic-gate return (0); 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate /* 11120Sstevel@tonic-gate * Install a streams module. 11130Sstevel@tonic-gate */ 11140Sstevel@tonic-gate /*ARGSUSED*/ 11150Sstevel@tonic-gate static int 11160Sstevel@tonic-gate mod_installstrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11170Sstevel@tonic-gate { 11180Sstevel@tonic-gate struct fmodsw *fp = modl->strmod_fmodsw; 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate if (!(fp->f_flag & D_MP)) { 11210Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: MT-unsafe strmod '%s' rejected", 11220Sstevel@tonic-gate fp->f_name); 11230Sstevel@tonic-gate return (ENXIO); 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate return (fmodsw_register(fp->f_name, fp->f_str, fp->f_flag)); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* 11300Sstevel@tonic-gate * Remove a streams module. 11310Sstevel@tonic-gate */ 11320Sstevel@tonic-gate /*ARGSUSED*/ 11330Sstevel@tonic-gate static int 11340Sstevel@tonic-gate mod_removestrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11350Sstevel@tonic-gate { 11360Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_STR) 11370Sstevel@tonic-gate return (EBUSY); 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate return (fmodsw_unregister(modl->strmod_fmodsw->f_name)); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate /* 11438348SEric.Yu@Sun.COM * Get status of a socket module. 11448348SEric.Yu@Sun.COM */ 11458348SEric.Yu@Sun.COM /*ARGSUSED*/ 11468348SEric.Yu@Sun.COM static int 11478348SEric.Yu@Sun.COM mod_infosockmod(struct modlsockmod *modl, struct modlinkage *modlp, int *p0) 11488348SEric.Yu@Sun.COM { 11498348SEric.Yu@Sun.COM *p0 = -1; /* no useful info */ 11508348SEric.Yu@Sun.COM return (0); 11518348SEric.Yu@Sun.COM } 11528348SEric.Yu@Sun.COM 11538348SEric.Yu@Sun.COM /* 11548348SEric.Yu@Sun.COM * Install a socket module. 11558348SEric.Yu@Sun.COM */ 11568348SEric.Yu@Sun.COM /*ARGSUSED*/ 11578348SEric.Yu@Sun.COM static int 11588348SEric.Yu@Sun.COM mod_installsockmod(struct modlsockmod *modl, struct modlinkage *modlp) 11598348SEric.Yu@Sun.COM { 11608348SEric.Yu@Sun.COM struct modctl *mcp; 11618348SEric.Yu@Sun.COM char *mod_name; 11628348SEric.Yu@Sun.COM 11638348SEric.Yu@Sun.COM mcp = mod_getctl(modlp); 11648348SEric.Yu@Sun.COM ASSERT(mcp != NULL); 11658348SEric.Yu@Sun.COM mod_name = mcp->mod_modname; 11668348SEric.Yu@Sun.COM if (strcmp(mod_name, modl->sockmod_reg_info->smod_name) != 0) { 11678348SEric.Yu@Sun.COM #ifdef DEBUG 11688348SEric.Yu@Sun.COM cmn_err(CE_CONT, "mod_installsockmod: different names" 11698348SEric.Yu@Sun.COM " %s != %s \n", mod_name, 11708348SEric.Yu@Sun.COM modl->sockmod_reg_info->smod_name); 11718348SEric.Yu@Sun.COM #endif 11728348SEric.Yu@Sun.COM return (EINVAL); 11738348SEric.Yu@Sun.COM } 11748348SEric.Yu@Sun.COM 11758348SEric.Yu@Sun.COM /* 11768348SEric.Yu@Sun.COM * Register module. 11778348SEric.Yu@Sun.COM */ 11788348SEric.Yu@Sun.COM return (smod_register(modl->sockmod_reg_info)); 11798348SEric.Yu@Sun.COM } 11808348SEric.Yu@Sun.COM 11818348SEric.Yu@Sun.COM /* 11828348SEric.Yu@Sun.COM * Remove a socket module. 11838348SEric.Yu@Sun.COM */ 11848348SEric.Yu@Sun.COM /*ARGSUSED*/ 11858348SEric.Yu@Sun.COM static int 11868348SEric.Yu@Sun.COM mod_removesockmod(struct modlsockmod *modl, struct modlinkage *modlp) 11878348SEric.Yu@Sun.COM { 11888348SEric.Yu@Sun.COM /* 11898348SEric.Yu@Sun.COM * unregister from the global socket creation table 11908348SEric.Yu@Sun.COM * check the refcnt in the lookup table 11918348SEric.Yu@Sun.COM */ 11928348SEric.Yu@Sun.COM return (smod_unregister(modl->sockmod_reg_info->smod_name)); 11938348SEric.Yu@Sun.COM } 11948348SEric.Yu@Sun.COM 11958348SEric.Yu@Sun.COM /* 11960Sstevel@tonic-gate * Get status of a scheduling class module. 11970Sstevel@tonic-gate */ 11980Sstevel@tonic-gate /*ARGSUSED1*/ 11990Sstevel@tonic-gate static int 12000Sstevel@tonic-gate mod_infosched(struct modlsched *modl, struct modlinkage *modlp, int *p0) 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate int status; 12030Sstevel@tonic-gate auto id_t cid; 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate if (status != 0) 12080Sstevel@tonic-gate *p0 = -1; 12090Sstevel@tonic-gate else 12100Sstevel@tonic-gate *p0 = cid; 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate return (0); 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate /* 12160Sstevel@tonic-gate * Install a scheduling class module. 12170Sstevel@tonic-gate */ 12180Sstevel@tonic-gate /*ARGSUSED1*/ 12190Sstevel@tonic-gate static int 12200Sstevel@tonic-gate mod_installsched(struct modlsched *modl, struct modlinkage *modlp) 12210Sstevel@tonic-gate { 12220Sstevel@tonic-gate sclass_t *clp; 12230Sstevel@tonic-gate int status; 12240Sstevel@tonic-gate id_t cid; 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate /* 12270Sstevel@tonic-gate * See if module is already installed. 12280Sstevel@tonic-gate */ 12290Sstevel@tonic-gate mutex_enter(&class_lock); 12300Sstevel@tonic-gate status = alloc_cid(modl->sched_class->cl_name, &cid); 12310Sstevel@tonic-gate mutex_exit(&class_lock); 12320Sstevel@tonic-gate ASSERT(status == 0); 12330Sstevel@tonic-gate clp = &sclass[cid]; 12340Sstevel@tonic-gate rw_enter(clp->cl_lock, RW_WRITER); 12350Sstevel@tonic-gate if (SCHED_INSTALLED(clp)) { 12360Sstevel@tonic-gate printf("scheduling class %s is already installed\n", 12375206Sis modl->sched_class->cl_name); 12380Sstevel@tonic-gate rw_exit(clp->cl_lock); 12390Sstevel@tonic-gate return (EBUSY); /* it's already there */ 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate clp->cl_init = modl->sched_class->cl_init; 12430Sstevel@tonic-gate clp->cl_funcs = modl->sched_class->cl_funcs; 12440Sstevel@tonic-gate modl->sched_class = clp; 12450Sstevel@tonic-gate disp_add(clp); 12460Sstevel@tonic-gate loaded_classes++; /* for priocntl system call */ 12470Sstevel@tonic-gate rw_exit(clp->cl_lock); 12480Sstevel@tonic-gate return (0); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * Remove a scheduling class module. 12530Sstevel@tonic-gate * 12540Sstevel@tonic-gate * we only null out the init func and the class functions because 12550Sstevel@tonic-gate * once a class has been loaded it has that slot in the class 12560Sstevel@tonic-gate * array until the next reboot. We don't decrement loaded_classes 12570Sstevel@tonic-gate * because this keeps count of the number of classes that have 12580Sstevel@tonic-gate * been loaded for this session. It will have to be this way until 12590Sstevel@tonic-gate * we implement the class array as a linked list and do true 12600Sstevel@tonic-gate * dynamic allocation. 12610Sstevel@tonic-gate */ 12620Sstevel@tonic-gate static int 12630Sstevel@tonic-gate mod_removesched(struct modlsched *modl, struct modlinkage *modlp) 12640Sstevel@tonic-gate { 12650Sstevel@tonic-gate int status; 12660Sstevel@tonic-gate sclass_t *clp; 12670Sstevel@tonic-gate struct modctl *mcp; 12680Sstevel@tonic-gate char *modname; 12690Sstevel@tonic-gate id_t cid; 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 12720Sstevel@tonic-gate if (status != 0) { 12730Sstevel@tonic-gate mcp = mod_getctl(modlp); 12740Sstevel@tonic-gate ASSERT(mcp != NULL); 12750Sstevel@tonic-gate modname = mcp->mod_modname; 12760Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 12770Sstevel@tonic-gate return (EINVAL); 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate clp = &sclass[cid]; 12800Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_SCHED || 12810Sstevel@tonic-gate !rw_tryenter(clp->cl_lock, RW_WRITER)) 12820Sstevel@tonic-gate return (EBUSY); 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate clp->cl_init = NULL; 12850Sstevel@tonic-gate clp->cl_funcs = NULL; 12860Sstevel@tonic-gate rw_exit(clp->cl_lock); 12870Sstevel@tonic-gate return (0); 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate /* 12910Sstevel@tonic-gate * Get status of an exec module. 12920Sstevel@tonic-gate */ 12930Sstevel@tonic-gate /*ARGSUSED1*/ 12940Sstevel@tonic-gate static int 12950Sstevel@tonic-gate mod_infoexec(struct modlexec *modl, struct modlinkage *modlp, int *p0) 12960Sstevel@tonic-gate { 12970Sstevel@tonic-gate struct execsw *eswp; 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) 13000Sstevel@tonic-gate *p0 = -1; 13010Sstevel@tonic-gate else 13020Sstevel@tonic-gate *p0 = eswp - execsw; 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate return (0); 13050Sstevel@tonic-gate } 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate /* 13080Sstevel@tonic-gate * Install an exec module. 13090Sstevel@tonic-gate */ 13100Sstevel@tonic-gate static int 13110Sstevel@tonic-gate mod_installexec(struct modlexec *modl, struct modlinkage *modlp) 13120Sstevel@tonic-gate { 13130Sstevel@tonic-gate struct execsw *eswp; 13140Sstevel@tonic-gate struct modctl *mcp; 13150Sstevel@tonic-gate char *modname; 13160Sstevel@tonic-gate char *magic; 13170Sstevel@tonic-gate size_t magic_size; 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate /* 13200Sstevel@tonic-gate * See if execsw entry is already allocated. Can't use findexectype() 13210Sstevel@tonic-gate * because we may get a recursive call to here. 13220Sstevel@tonic-gate */ 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) { 13250Sstevel@tonic-gate mcp = mod_getctl(modlp); 13260Sstevel@tonic-gate ASSERT(mcp != NULL); 13270Sstevel@tonic-gate modname = mcp->mod_modname; 13280Sstevel@tonic-gate magic = modl->exec_execsw->exec_magic; 13290Sstevel@tonic-gate magic_size = modl->exec_execsw->exec_maglen; 13300Sstevel@tonic-gate if ((eswp = allocate_execsw(modname, magic, magic_size)) == 13310Sstevel@tonic-gate NULL) { 13320Sstevel@tonic-gate printf("no unused entries in 'execsw'\n"); 13330Sstevel@tonic-gate return (ENOSPC); 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate } 13360Sstevel@tonic-gate if (eswp->exec_func != NULL) { 13370Sstevel@tonic-gate printf("exec type %x is already installed\n", 13385206Sis *eswp->exec_magic); 13390Sstevel@tonic-gate return (EBUSY); /* it's already there! */ 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate rw_enter(eswp->exec_lock, RW_WRITER); 13430Sstevel@tonic-gate eswp->exec_func = modl->exec_execsw->exec_func; 13440Sstevel@tonic-gate eswp->exec_core = modl->exec_execsw->exec_core; 13450Sstevel@tonic-gate rw_exit(eswp->exec_lock); 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate return (0); 13480Sstevel@tonic-gate } 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate /* 13510Sstevel@tonic-gate * Remove an exec module. 13520Sstevel@tonic-gate */ 13530Sstevel@tonic-gate static int 13540Sstevel@tonic-gate mod_removeexec(struct modlexec *modl, struct modlinkage *modlp) 13550Sstevel@tonic-gate { 13560Sstevel@tonic-gate struct execsw *eswp; 13570Sstevel@tonic-gate struct modctl *mcp; 13580Sstevel@tonic-gate char *modname; 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate eswp = findexecsw(modl->exec_execsw->exec_magic); 13610Sstevel@tonic-gate if (eswp == NULL) { 13620Sstevel@tonic-gate mcp = mod_getctl(modlp); 13630Sstevel@tonic-gate ASSERT(mcp != NULL); 13640Sstevel@tonic-gate modname = mcp->mod_modname; 13650Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 13660Sstevel@tonic-gate return (EINVAL); 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_EXEC || 13690Sstevel@tonic-gate !rw_tryenter(eswp->exec_lock, RW_WRITER)) 13700Sstevel@tonic-gate return (EBUSY); 13710Sstevel@tonic-gate eswp->exec_func = NULL; 13720Sstevel@tonic-gate eswp->exec_core = NULL; 13730Sstevel@tonic-gate rw_exit(eswp->exec_lock); 13740Sstevel@tonic-gate return (0); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate * Find a free sysent entry or check if the specified one is free. 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate static struct sysent * 13810Sstevel@tonic-gate mod_getsysent(struct modlinkage *modlp, struct sysent *se) 13820Sstevel@tonic-gate { 13830Sstevel@tonic-gate int sysnum; 13840Sstevel@tonic-gate struct modctl *mcp; 13850Sstevel@tonic-gate char *mod_name; 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 13880Sstevel@tonic-gate /* 13890Sstevel@tonic-gate * This happens when we're looking up the module 13900Sstevel@tonic-gate * pointer as part of a stub installation. So 13910Sstevel@tonic-gate * there's no need to whine at this point. 13920Sstevel@tonic-gate */ 13930Sstevel@tonic-gate return (NULL); 13940Sstevel@tonic-gate } 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate mod_name = mcp->mod_modname; 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate if ((sysnum = mod_getsysnum(mod_name)) == -1) { 13990Sstevel@tonic-gate cmn_err(CE_WARN, "system call missing from bind file"); 14000Sstevel@tonic-gate return (NULL); 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate if (sysnum > 0 && sysnum < NSYSCALL && 14040Sstevel@tonic-gate (se[sysnum].sy_flags & (SE_LOADABLE | SE_NOUNLOAD))) 14050Sstevel@tonic-gate return (se + sysnum); 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate cmn_err(CE_WARN, "system call entry %d is already in use", sysnum); 14080Sstevel@tonic-gate return (NULL); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate /* 14120Sstevel@tonic-gate * IP Policy Modules. 14130Sstevel@tonic-gate */ 14140Sstevel@tonic-gate /*ARGSUSED*/ 14150Sstevel@tonic-gate static int 14160Sstevel@tonic-gate mod_infoipp(struct modlipp *modl, struct modlinkage *modlp, int *p0) 14170Sstevel@tonic-gate { 14180Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14190Sstevel@tonic-gate ipp_mod_id_t mid; 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate if (mcp == NULL) { 14220Sstevel@tonic-gate *p0 = -1; 14230Sstevel@tonic-gate return (0); /* module is not yet installed */ 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate *p0 = mid; 14290Sstevel@tonic-gate return (0); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate static int 14330Sstevel@tonic-gate mod_installipp(struct modlipp *modl, struct modlinkage *modlp) 14340Sstevel@tonic-gate { 14350Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate ASSERT(mcp != NULL); 14380Sstevel@tonic-gate return (ipp_mod_register(mcp->mod_modname, modl->ipp_ops)); 14390Sstevel@tonic-gate } 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate /*ARGSUSED*/ 14420Sstevel@tonic-gate static int 14430Sstevel@tonic-gate mod_removeipp(struct modlipp *modl, struct modlinkage *modlp) 14440Sstevel@tonic-gate { 14450Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14460Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 14470Sstevel@tonic-gate ipp_mod_id_t mid; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate ASSERT(mcp != NULL); 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_IPP) && (mod_aul_thread == curthread)) 14520Sstevel@tonic-gate return (EBUSY); 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 14550Sstevel@tonic-gate ASSERT(mid != IPP_MOD_INVAL); 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate return (ipp_mod_unregister(mid)); 14580Sstevel@tonic-gate } 14595206Sis 14605206Sis /* 14615206Sis * Manage kiconv modules. 14625206Sis */ 14635206Sis /*ARGSUSED*/ 14645206Sis static int 14655206Sis mod_installkiconv(struct modlkiconv *modl, struct modlinkage *modlp) 14665206Sis { 14675206Sis return (kiconv_register_module(modl->kiconv_moddef)); 14685206Sis } 14695206Sis 14705206Sis /*ARGSUSED*/ 14715206Sis static int 14725206Sis mod_removekiconv(struct modlkiconv *modl, struct modlinkage *modlp) 14735206Sis { 14745206Sis return (kiconv_unregister_module(modl->kiconv_moddef)); 14755206Sis } 1476