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*5206Sis * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/systm.h> 300Sstevel@tonic-gate #include <sys/param.h> 310Sstevel@tonic-gate #include <sys/user.h> 320Sstevel@tonic-gate #include <sys/vm.h> 330Sstevel@tonic-gate #include <sys/conf.h> 340Sstevel@tonic-gate #include <sys/class.h> 350Sstevel@tonic-gate #include <sys/vfs.h> 361488Srsb #include <sys/vnode.h> 370Sstevel@tonic-gate #include <sys/mount.h> 380Sstevel@tonic-gate #include <sys/systm.h> 390Sstevel@tonic-gate #include <sys/modctl.h> 400Sstevel@tonic-gate #include <sys/exec.h> 410Sstevel@tonic-gate #include <sys/exechdr.h> 420Sstevel@tonic-gate #include <sys/devops.h> 430Sstevel@tonic-gate #include <sys/ddi.h> 440Sstevel@tonic-gate #include <sys/sunddi.h> 450Sstevel@tonic-gate #include <sys/cmn_err.h> 460Sstevel@tonic-gate #include <sys/hwconf.h> 470Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 480Sstevel@tonic-gate #include <sys/autoconf.h> 490Sstevel@tonic-gate #include <sys/disp.h> 500Sstevel@tonic-gate #include <sys/kmem.h> 510Sstevel@tonic-gate #include <sys/instance.h> 520Sstevel@tonic-gate #include <sys/modhash.h> 530Sstevel@tonic-gate #include <sys/dacf.h> 540Sstevel@tonic-gate #include <sys/debug.h> 550Sstevel@tonic-gate #include <ipp/ipp.h> 560Sstevel@tonic-gate #include <sys/strsubr.h> 570Sstevel@tonic-gate #include <sys/kcpc.h> 582712Snn35248 #include <sys/brand.h> 590Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 601488Srsb #include <sys/kstat.h> 612621Sllai1 #include <sys/fs/sdev_node.h> 62*5206Sis #include <sys/kiconv.h> 630Sstevel@tonic-gate 640Sstevel@tonic-gate extern int moddebug; 650Sstevel@tonic-gate 660Sstevel@tonic-gate extern struct cb_ops no_cb_ops; 670Sstevel@tonic-gate extern struct dev_ops nodev_ops; 680Sstevel@tonic-gate extern struct dev_ops mod_nodev_ops; 690Sstevel@tonic-gate 700Sstevel@tonic-gate extern struct modctl *mod_getctl(struct modlinkage *); 710Sstevel@tonic-gate extern int errsys(), nodev(), nulldev(); 720Sstevel@tonic-gate 730Sstevel@tonic-gate extern int findmodbyname(char *); 740Sstevel@tonic-gate extern int mod_getsysnum(char *); 750Sstevel@tonic-gate 760Sstevel@tonic-gate extern struct execsw execsw[]; 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * Define dev_ops for unused devopsp entry. 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate struct dev_ops mod_nodev_ops = { 820Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 830Sstevel@tonic-gate 0, /* refcnt */ 840Sstevel@tonic-gate ddi_no_info, /* info */ 850Sstevel@tonic-gate nulldev, /* identify */ 860Sstevel@tonic-gate nulldev, /* probe */ 870Sstevel@tonic-gate ddifail, /* attach */ 880Sstevel@tonic-gate nodev, /* detach */ 890Sstevel@tonic-gate nulldev, /* reset */ 900Sstevel@tonic-gate &no_cb_ops, /* character/block driver operations */ 910Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations for nexus drivers */ 920Sstevel@tonic-gate }; 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * Define mod_ops for each supported module type 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate 980Sstevel@tonic-gate /* 990Sstevel@tonic-gate * Null operations; used for uninitialized and "misc" modules. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate static int mod_null(struct modldrv *, struct modlinkage *); 1020Sstevel@tonic-gate static int mod_infonull(void *, struct modlinkage *, int *); 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate struct mod_ops mod_miscops = { 1050Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1060Sstevel@tonic-gate }; 1070Sstevel@tonic-gate 1081414Scindi /* CPU Modules */ 1091414Scindi struct mod_ops mod_cpuops = { 1101414Scindi mod_null, mod_null, mod_infonull 1111414Scindi }; 1121414Scindi 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * Cryptographic Modules 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate struct mod_ops mod_cryptoops = { 1170Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1180Sstevel@tonic-gate }; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * IP Policy Modules 1220Sstevel@tonic-gate */ 1230Sstevel@tonic-gate static int mod_installipp(struct modlipp *, struct modlinkage *); 1240Sstevel@tonic-gate static int mod_removeipp(struct modlipp *, struct modlinkage *); 1250Sstevel@tonic-gate static int mod_infoipp(struct modlipp *, struct modlinkage *, int *); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate struct mod_ops mod_ippops = { 1280Sstevel@tonic-gate mod_installipp, mod_removeipp, mod_infoipp 1290Sstevel@tonic-gate }; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * Device drivers 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate static int mod_infodrv(struct modldrv *, struct modlinkage *, int *); 1350Sstevel@tonic-gate static int mod_installdrv(struct modldrv *, struct modlinkage *); 1360Sstevel@tonic-gate static int mod_removedrv(struct modldrv *, struct modlinkage *); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate struct mod_ops mod_driverops = { 1390Sstevel@tonic-gate mod_installdrv, mod_removedrv, mod_infodrv 1400Sstevel@tonic-gate }; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /* 1430Sstevel@tonic-gate * System calls (new interface) 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate static int mod_infosys(struct modlsys *, struct modlinkage *, int *); 1460Sstevel@tonic-gate static int mod_installsys(struct modlsys *, struct modlinkage *); 1470Sstevel@tonic-gate static int mod_removesys(struct modlsys *, struct modlinkage *); 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate struct mod_ops mod_syscallops = { 1500Sstevel@tonic-gate mod_installsys, mod_removesys, mod_infosys 1510Sstevel@tonic-gate }; 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * 32-bit system calls in 64-bit kernel 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate static int mod_infosys32(struct modlsys *, struct modlinkage *, int *); 1580Sstevel@tonic-gate static int mod_installsys32(struct modlsys *, struct modlinkage *); 1590Sstevel@tonic-gate static int mod_removesys32(struct modlsys *, struct modlinkage *); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate struct mod_ops mod_syscallops32 = { 1620Sstevel@tonic-gate mod_installsys32, mod_removesys32, mod_infosys32 1630Sstevel@tonic-gate }; 1640Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * Filesystems 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate static int mod_infofs(struct modlfs *, struct modlinkage *, int *); 1700Sstevel@tonic-gate static int mod_installfs(struct modlfs *, struct modlinkage *); 1710Sstevel@tonic-gate static int mod_removefs(struct modlfs *, struct modlinkage *); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate struct mod_ops mod_fsops = { 1740Sstevel@tonic-gate mod_installfs, mod_removefs, mod_infofs 1750Sstevel@tonic-gate }; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate /* 1780Sstevel@tonic-gate * Streams modules. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate static int mod_infostrmod(struct modlstrmod *, struct modlinkage *, int *); 1810Sstevel@tonic-gate static int mod_installstrmod(struct modlstrmod *, struct modlinkage *); 1820Sstevel@tonic-gate static int mod_removestrmod(struct modlstrmod *, struct modlinkage *); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate struct mod_ops mod_strmodops = { 1850Sstevel@tonic-gate mod_installstrmod, mod_removestrmod, mod_infostrmod 1860Sstevel@tonic-gate }; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate /* 1890Sstevel@tonic-gate * Scheduling classes. 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate static int mod_infosched(struct modlsched *, struct modlinkage *, int *); 1920Sstevel@tonic-gate static int mod_installsched(struct modlsched *, struct modlinkage *); 1930Sstevel@tonic-gate static int mod_removesched(struct modlsched *, struct modlinkage *); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate struct mod_ops mod_schedops = { 1960Sstevel@tonic-gate mod_installsched, mod_removesched, mod_infosched 1970Sstevel@tonic-gate }; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * Exec file type (like ELF, ...). 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate static int mod_infoexec(struct modlexec *, struct modlinkage *, int *); 2030Sstevel@tonic-gate static int mod_installexec(struct modlexec *, struct modlinkage *); 2040Sstevel@tonic-gate static int mod_removeexec(struct modlexec *, struct modlinkage *); 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate struct mod_ops mod_execops = { 2070Sstevel@tonic-gate mod_installexec, mod_removeexec, mod_infoexec 2080Sstevel@tonic-gate }; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Dacf (Dynamic Autoconfiguration) modules. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate static int mod_infodacf(struct modldacf *, struct modlinkage *, int *); 2140Sstevel@tonic-gate static int mod_installdacf(struct modldacf *, struct modlinkage *); 2150Sstevel@tonic-gate static int mod_removedacf(struct modldacf *, struct modlinkage *); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate struct mod_ops mod_dacfops = { 2180Sstevel@tonic-gate mod_installdacf, mod_removedacf, mod_infodacf 2190Sstevel@tonic-gate }; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* 2222621Sllai1 * /dev fs modules 2232621Sllai1 */ 2242621Sllai1 static int mod_infodev(struct modldev *, struct modlinkage *, int *); 2252621Sllai1 static int mod_installdev(struct modldev *, struct modlinkage *); 2262621Sllai1 static int mod_removedev(struct modldev *, struct modlinkage *); 2272621Sllai1 2282621Sllai1 struct mod_ops mod_devfsops = { 2292621Sllai1 mod_installdev, mod_removedev, mod_infodev 2302621Sllai1 }; 2312621Sllai1 2322621Sllai1 /* 2330Sstevel@tonic-gate * PCBE (Performance Counter BackEnd) modules. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate static int mod_installpcbe(struct modlpcbe *, struct modlinkage *); 2360Sstevel@tonic-gate static int mod_removepcbe(struct modlpcbe *, struct modlinkage *); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate struct mod_ops mod_pcbeops = { 2390Sstevel@tonic-gate mod_installpcbe, mod_removepcbe, mod_infonull 2400Sstevel@tonic-gate }; 2410Sstevel@tonic-gate 2422712Snn35248 /* 2432712Snn35248 * Brand modules. 2442712Snn35248 */ 2452712Snn35248 static int mod_installbrand(struct modlbrand *, struct modlinkage *); 2462712Snn35248 static int mod_removebrand(struct modlbrand *, struct modlinkage *); 2472712Snn35248 2482712Snn35248 struct mod_ops mod_brandops = { 2492712Snn35248 mod_installbrand, mod_removebrand, mod_infonull 2502712Snn35248 }; 2512712Snn35248 252*5206Sis /* 253*5206Sis * kiconv modules. 254*5206Sis */ 255*5206Sis static int mod_installkiconv(struct modlkiconv *, struct modlinkage *); 256*5206Sis static int mod_removekiconv(struct modlkiconv *, struct modlinkage *); 257*5206Sis 258*5206Sis struct mod_ops mod_kiconvops = { 259*5206Sis mod_installkiconv, mod_removekiconv, mod_infonull 260*5206Sis }; 261*5206Sis 2620Sstevel@tonic-gate static struct sysent *mod_getsysent(struct modlinkage *, struct sysent *); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate static char uninstall_err[] = "Cannot uninstall %s; not installed"; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * Debugging support 2680Sstevel@tonic-gate */ 2690Sstevel@tonic-gate #define DRV_DBG MODDEBUG_LOADMSG2 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /*PRINTFLIKE2*/ 2720Sstevel@tonic-gate static void mod_dprintf(int flag, const char *format, ...) __KPRINTFLIKE(2); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate static void 2750Sstevel@tonic-gate mod_dprintf(int flag, const char *format, ...) 2760Sstevel@tonic-gate { 2770Sstevel@tonic-gate va_list alist; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate if ((moddebug & flag) != 0) { 2800Sstevel@tonic-gate va_start(alist, format); 2810Sstevel@tonic-gate (void) vprintf(format, alist); 2820Sstevel@tonic-gate va_end(alist); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Install a module. 2880Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate int 2910Sstevel@tonic-gate mod_install(struct modlinkage *modlp) 2920Sstevel@tonic-gate { 2930Sstevel@tonic-gate int retval = -1; /* No linkage structures */ 2940Sstevel@tonic-gate struct modlmisc **linkpp; 2950Sstevel@tonic-gate struct modlmisc **linkpp1; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (modlp->ml_rev != MODREV_1) { 2980Sstevel@tonic-gate printf("mod_install: modlinkage structure is not MODREV_1\n"); 2990Sstevel@tonic-gate return (EINVAL); 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate while (*linkpp != NULL) { 3040Sstevel@tonic-gate if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) { 3050Sstevel@tonic-gate linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0]; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate while (linkpp1 != linkpp) { 3080Sstevel@tonic-gate MODL_REMOVE(*linkpp1, modlp); /* clean up */ 3090Sstevel@tonic-gate linkpp1++; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate break; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate linkpp++; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate return (retval); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate static char *reins_err = 3190Sstevel@tonic-gate "Could not reinstall %s\nReboot to correct the problem"; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * Remove a module. This is called by the module wrapper routine. 3230Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate int 3260Sstevel@tonic-gate mod_remove(struct modlinkage *modlp) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate int retval = 0; 3290Sstevel@tonic-gate struct modlmisc **linkpp, *last_linkp; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate while (*linkpp != NULL) { 3340Sstevel@tonic-gate if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) { 3350Sstevel@tonic-gate last_linkp = *linkpp; 3360Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3370Sstevel@tonic-gate while (*linkpp != last_linkp) { 3380Sstevel@tonic-gate if (MODL_INSTALL(*linkpp, modlp) != 0) { 3390Sstevel@tonic-gate cmn_err(CE_WARN, reins_err, 340*5206Sis (*linkpp)->misc_linkinfo); 3410Sstevel@tonic-gate break; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate linkpp++; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate break; 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate linkpp++; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate return (retval); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Get module status. 3540Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate int 3570Sstevel@tonic-gate mod_info(struct modlinkage *modlp, struct modinfo *modinfop) 3580Sstevel@tonic-gate { 3590Sstevel@tonic-gate int i; 3600Sstevel@tonic-gate int retval = 0; 3610Sstevel@tonic-gate struct modspecific_info *msip; 3620Sstevel@tonic-gate struct modlmisc **linkpp; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate modinfop->mi_rev = modlp->ml_rev; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate linkpp = (struct modlmisc **)modlp->ml_linkage; 3670Sstevel@tonic-gate msip = &modinfop->mi_msinfo[0]; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate for (i = 0; i < MODMAXLINK; i++) { 3700Sstevel@tonic-gate if (*linkpp == NULL) { 3710Sstevel@tonic-gate msip->msi_linkinfo[0] = '\0'; 3720Sstevel@tonic-gate } else { 3730Sstevel@tonic-gate (void) strncpy(msip->msi_linkinfo, 3740Sstevel@tonic-gate (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN); 3750Sstevel@tonic-gate retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0); 3760Sstevel@tonic-gate if (retval != 0) 3770Sstevel@tonic-gate break; 3780Sstevel@tonic-gate linkpp++; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate msip++; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate if (modinfop->mi_info == MI_INFO_LINKAGE) { 3840Sstevel@tonic-gate /* 3850Sstevel@tonic-gate * Slight kludge used to extract the address of the 3860Sstevel@tonic-gate * modlinkage structure from the module (just after 3870Sstevel@tonic-gate * loading a module for the very first time) 3880Sstevel@tonic-gate */ 3890Sstevel@tonic-gate modinfop->mi_base = (void *)modlp; 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate if (retval == 0) 3930Sstevel@tonic-gate return (1); 3940Sstevel@tonic-gate return (0); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /* 3980Sstevel@tonic-gate * Get module name. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate char * 4010Sstevel@tonic-gate mod_modname(struct modlinkage *modlp) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate struct modctl *mcp; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4060Sstevel@tonic-gate return (NULL); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate return (mcp->mod_modname); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * Null operation; return 0. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate /*ARGSUSED*/ 4150Sstevel@tonic-gate static int 4160Sstevel@tonic-gate mod_null(struct modldrv *modl, struct modlinkage *modlp) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate return (0); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Status for User modules. 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate /*ARGSUSED*/ 4250Sstevel@tonic-gate static int 4260Sstevel@tonic-gate mod_infonull(void *modl, struct modlinkage *modlp, int *p0) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate *p0 = -1; /* for modinfo display */ 4290Sstevel@tonic-gate return (0); 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * Driver status info 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate /*ARGSUSED*/ 4360Sstevel@tonic-gate static int 4370Sstevel@tonic-gate mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0) 4380Sstevel@tonic-gate { 4390Sstevel@tonic-gate struct modctl *mcp; 4400Sstevel@tonic-gate char *mod_name; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 4430Sstevel@tonic-gate *p0 = -1; 4440Sstevel@tonic-gate return (0); /* driver is not yet installed */ 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate mod_name = mcp->mod_modname; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate *p0 = ddi_name_to_major(mod_name); 4500Sstevel@tonic-gate return (0); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * Manage dacf (device autoconfiguration) modules 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /*ARGSUSED*/ 4580Sstevel@tonic-gate static int 4590Sstevel@tonic-gate mod_infodacf(struct modldacf *modl, struct modlinkage *modlp, int *p0) 4600Sstevel@tonic-gate { 4610Sstevel@tonic-gate if (mod_getctl(modlp) == NULL) { 4620Sstevel@tonic-gate *p0 = -1; 4630Sstevel@tonic-gate return (0); /* module is not yet installed */ 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate *p0 = 0; 4670Sstevel@tonic-gate return (0); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate static int 4710Sstevel@tonic-gate mod_installdacf(struct modldacf *modl, struct modlinkage *modlp) 4720Sstevel@tonic-gate { 4730Sstevel@tonic-gate struct modctl *mcp; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4760Sstevel@tonic-gate return (EINVAL); 4770Sstevel@tonic-gate return (dacf_module_register(mcp->mod_modname, modl->dacf_dacfsw)); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /*ARGSUSED*/ 4810Sstevel@tonic-gate static int 4820Sstevel@tonic-gate mod_removedacf(struct modldacf *modl, struct modlinkage *modlp) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate struct modctl *mcp; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4870Sstevel@tonic-gate return (EINVAL); 4880Sstevel@tonic-gate return (dacf_module_unregister(mcp->mod_modname)); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Manage PCBE (Performance Counter BackEnd) modules. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate /*ARGSUSED*/ 4950Sstevel@tonic-gate static int 4960Sstevel@tonic-gate mod_installpcbe(struct modlpcbe *modl, struct modlinkage *modlp) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate if (modl->pcbe_ops->pcbe_ver != PCBE_VER_1) { 4990Sstevel@tonic-gate cmn_err(CE_WARN, "pcbe '%s' version mismatch", 5000Sstevel@tonic-gate modl->pcbe_linkinfo); 5010Sstevel@tonic-gate return (EINVAL); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate kcpc_register_pcbe(modl->pcbe_ops); 5050Sstevel@tonic-gate return (0); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * PCBEs may not be unloaded. It would make CPC locking too complex, and since 5100Sstevel@tonic-gate * PCBEs are loaded once and used for life, there is no harm done in leaving 5110Sstevel@tonic-gate * them in the system. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate /*ARGSUSED*/ 5140Sstevel@tonic-gate static int 5150Sstevel@tonic-gate mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp) 5160Sstevel@tonic-gate { 5170Sstevel@tonic-gate return (EBUSY); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5202621Sllai1 /* 5212712Snn35248 * Manage BrandZ modules. 5222712Snn35248 */ 5232712Snn35248 /*ARGSUSED*/ 5242712Snn35248 static int 5252712Snn35248 mod_installbrand(struct modlbrand *modl, struct modlinkage *modlp) 5262712Snn35248 { 5272712Snn35248 return (brand_register(modl->brand_branddef)); 5282712Snn35248 } 5292712Snn35248 5302712Snn35248 /*ARGSUSED*/ 5312712Snn35248 static int 5322712Snn35248 mod_removebrand(struct modlbrand *modl, struct modlinkage *modlp) 5332712Snn35248 { 5342712Snn35248 return (brand_unregister(modl->brand_branddef)); 5352712Snn35248 } 5362712Snn35248 5372712Snn35248 /* 5382621Sllai1 * manage /dev fs modules 5392621Sllai1 */ 5402621Sllai1 /*ARGSUSED*/ 5412621Sllai1 static int 5422621Sllai1 mod_infodev(struct modldev *modl, struct modlinkage *modlp, int *p0) 5432621Sllai1 { 5442621Sllai1 if (mod_getctl(modlp) == NULL) { 5452621Sllai1 *p0 = -1; 5462621Sllai1 return (0); /* module is not yet installed */ 5472621Sllai1 } 5482621Sllai1 5492621Sllai1 *p0 = 0; 5502621Sllai1 return (0); 5512621Sllai1 } 5522621Sllai1 5532621Sllai1 static int 5542621Sllai1 mod_installdev(struct modldev *modl, struct modlinkage *modlp) 5552621Sllai1 { 5562621Sllai1 struct modctl *mcp; 5572621Sllai1 5582621Sllai1 if ((mcp = mod_getctl(modlp)) == NULL) 5592621Sllai1 return (EINVAL); 5602621Sllai1 return (sdev_module_register(mcp->mod_modname, modl->dev_ops)); 5612621Sllai1 } 5622621Sllai1 5632621Sllai1 /* 5642621Sllai1 * /dev modules are not unloadable. 5652621Sllai1 */ 5662621Sllai1 /*ARGSUSED*/ 5672621Sllai1 static int 5682621Sllai1 mod_removedev(struct modldev *modl, struct modlinkage *modlp) 5692621Sllai1 { 5702621Sllai1 return (EBUSY); 5712621Sllai1 } 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate /* 5740Sstevel@tonic-gate * Install a new driver 5750Sstevel@tonic-gate */ 5760Sstevel@tonic-gate static int 5770Sstevel@tonic-gate mod_installdrv(struct modldrv *modl, struct modlinkage *modlp) 5780Sstevel@tonic-gate { 5790Sstevel@tonic-gate struct modctl *mcp; 5800Sstevel@tonic-gate struct dev_ops *ops; 5810Sstevel@tonic-gate char *modname; 5820Sstevel@tonic-gate major_t major; 5830Sstevel@tonic-gate struct dev_ops *dp; 5840Sstevel@tonic-gate struct devnames *dnp; 5850Sstevel@tonic-gate struct streamtab *str; 5860Sstevel@tonic-gate cdevsw_impl_t *cdp; 5870Sstevel@tonic-gate uint_t sqtype; 5880Sstevel@tonic-gate uint_t qflag; 5890Sstevel@tonic-gate uint_t flag; 5900Sstevel@tonic-gate int err = 0; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* sanity check module */ 5930Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 5940Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: bad module linkage data"); 5950Sstevel@tonic-gate err = ENXIO; 5960Sstevel@tonic-gate goto done; 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate modname = mcp->mod_modname; 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* Sanity check modname */ 6010Sstevel@tonic-gate if ((major = ddi_name_to_major(modname)) == (major_t)-1) { 6020Sstevel@tonic-gate #ifdef DEBUG 6030Sstevel@tonic-gate cmn_err(CE_WARN, 6040Sstevel@tonic-gate "mod_installdrv: no major number for %s", modname); 6050Sstevel@tonic-gate #endif 6060Sstevel@tonic-gate err = ENXIO; 6070Sstevel@tonic-gate goto done; 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* Verify MP safety flag */ 6110Sstevel@tonic-gate ops = modl->drv_dev_ops; 6120Sstevel@tonic-gate if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL && 6130Sstevel@tonic-gate !(ops->devo_cb_ops->cb_flag & D_MP)) { 6140Sstevel@tonic-gate cmn_err(CE_WARN, 6150Sstevel@tonic-gate "mod_installdrv: MT-unsafe driver '%s' rejected", modname); 6160Sstevel@tonic-gate err = ENXIO; 6170Sstevel@tonic-gate goto done; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate /* Is bus_map_fault signature correct (version 8 and higher)? */ 6220Sstevel@tonic-gate if (ops->devo_bus_ops != NULL && 6230Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != NULL && 6240Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault && 6250Sstevel@tonic-gate ops->devo_bus_ops->busops_rev < BUSO_REV_8) { 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate cmn_err(CE_WARN, 6280Sstevel@tonic-gate "mod_installdrv: busops' revision of '%s' is too low" 6290Sstevel@tonic-gate " (must be at least 8)", modname); 6300Sstevel@tonic-gate err = ENXIO; 6310Sstevel@tonic-gate goto done; 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* Make sure the driver is uninstalled */ 6360Sstevel@tonic-gate dnp = &devnamesp[major]; 6370Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 6380Sstevel@tonic-gate dp = devopsp[major]; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate if (dnp->dn_flags & DN_DRIVER_REMOVED) { 6410Sstevel@tonic-gate #ifdef DEBUG 6420Sstevel@tonic-gate cmn_err(CE_NOTE, 6430Sstevel@tonic-gate "mod_installdrv: driver has been removed %s", modname); 6440Sstevel@tonic-gate #endif 6450Sstevel@tonic-gate err = ENXIO; 6460Sstevel@tonic-gate goto unlock; 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (dp != &nodev_ops && dp != &mod_nodev_ops) { 6500Sstevel@tonic-gate cmn_err(CE_WARN, 6510Sstevel@tonic-gate "mod_installdrv: driver already installed %s", modname); 6520Sstevel@tonic-gate err = EALREADY; 6530Sstevel@tonic-gate goto unlock; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate devopsp[major] = ops; /* setup devopsp */ 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 6590Sstevel@tonic-gate flag = CBFLAG(major); 6600Sstevel@tonic-gate if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0) 6610Sstevel@tonic-gate goto unlock; 6620Sstevel@tonic-gate cdp = &devimpl[major]; 6630Sstevel@tonic-gate ASSERT(cdp->d_str == NULL); 6640Sstevel@tonic-gate cdp->d_str = str; 6650Sstevel@tonic-gate cdp->d_qflag = qflag | QISDRV; 6660Sstevel@tonic-gate cdp->d_sqtype = sqtype; 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate if (ops->devo_bus_ops == NULL) 6700Sstevel@tonic-gate dnp->dn_flags |= DN_LEAF_DRIVER; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate unlock: 6730Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 6740Sstevel@tonic-gate done: 6750Sstevel@tonic-gate return (err); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate static int 6790Sstevel@tonic-gate mod_removedrv(struct modldrv *modl, struct modlinkage *modlp) 6800Sstevel@tonic-gate { 6810Sstevel@tonic-gate struct modctl *mcp; 6820Sstevel@tonic-gate struct dev_ops *ops; 6830Sstevel@tonic-gate struct devnames *dnp; 6840Sstevel@tonic-gate struct dev_ops *dp; 6850Sstevel@tonic-gate major_t major; 6860Sstevel@tonic-gate char *modname; 6870Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 6880Sstevel@tonic-gate struct streamtab *str; 6890Sstevel@tonic-gate cdevsw_impl_t *cdp; 6900Sstevel@tonic-gate int err = 0; 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate /* Don't auto unload modules on if moddebug flag is set */ 6930Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) { 6940Sstevel@tonic-gate err = EBUSY; 6950Sstevel@tonic-gate goto done; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate /* Verify modname has a driver major */ 6990Sstevel@tonic-gate mcp = mod_getctl(modlp); 7000Sstevel@tonic-gate ASSERT(mcp != NULL); 7010Sstevel@tonic-gate modname = mcp->mod_modname; 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if ((major = ddi_name_to_major(modname)) == -1) { 7040Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 7050Sstevel@tonic-gate err = EINVAL; 7060Sstevel@tonic-gate goto done; 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate ops = modl->drv_dev_ops; 7100Sstevel@tonic-gate dnp = &(devnamesp[major]); 7110Sstevel@tonic-gate LOCK_DEV_OPS(&(dnp->dn_lock)); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate dp = devopsp[major]; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate if (dp != ops) { 7160Sstevel@tonic-gate cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s", 7170Sstevel@tonic-gate modname); 7180Sstevel@tonic-gate err = EBUSY; 7190Sstevel@tonic-gate goto unlock; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * A driver is not unloadable if its dev_ops are held 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate if (!DRV_UNLOADABLE(dp)) { 7260Sstevel@tonic-gate mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>," 7270Sstevel@tonic-gate " refcnt %d\n", modname, dp->devo_refcnt); 7280Sstevel@tonic-gate err = EBUSY; 7290Sstevel@tonic-gate goto unlock; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * OK to unload. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 7360Sstevel@tonic-gate cdp = &devimpl[major]; 7370Sstevel@tonic-gate ASSERT(cdp->d_str == str); 7380Sstevel@tonic-gate cdp->d_str = NULL; 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* check for reference to per-dev syncq */ 7410Sstevel@tonic-gate if (cdp->d_dmp != NULL) { 7420Sstevel@tonic-gate rele_dm(cdp->d_dmp); 7430Sstevel@tonic-gate cdp->d_dmp = NULL; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate devopsp[major] = &mod_nodev_ops; 7480Sstevel@tonic-gate dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH); 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate unlock: 7510Sstevel@tonic-gate UNLOCK_DEV_OPS(&(dnp->dn_lock)); 7520Sstevel@tonic-gate done: 7530Sstevel@tonic-gate return (err); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 7570Sstevel@tonic-gate * System call subroutines 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Compute system call number for given sysent and sysent table 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate static int 7640Sstevel@tonic-gate mod_infosysnum(struct modlinkage *modlp, struct sysent table[]) 7650Sstevel@tonic-gate { 7660Sstevel@tonic-gate struct sysent *sysp; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 7690Sstevel@tonic-gate return (-1); 7700Sstevel@tonic-gate return ((int)(sysp - table)); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * Put a loadable system call entry into a sysent table. 7750Sstevel@tonic-gate */ 7760Sstevel@tonic-gate static int 7770Sstevel@tonic-gate mod_installsys_sysent( 7780Sstevel@tonic-gate struct modlsys *modl, 7790Sstevel@tonic-gate struct modlinkage *modlp, 7800Sstevel@tonic-gate struct sysent table[]) 7810Sstevel@tonic-gate { 7820Sstevel@tonic-gate struct sysent *sysp; 7830Sstevel@tonic-gate struct sysent *mp; 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate #ifdef DEBUG 7860Sstevel@tonic-gate /* 7870Sstevel@tonic-gate * Before we even play with the sysent table, sanity check the 7880Sstevel@tonic-gate * incoming flags to make sure the entry is valid 7890Sstevel@tonic-gate */ 7900Sstevel@tonic-gate switch (modl->sys_sysent->sy_flags & SE_RVAL_MASK) { 7910Sstevel@tonic-gate case SE_32RVAL1: 7920Sstevel@tonic-gate /* only r_val1 returned */ 7930Sstevel@tonic-gate case SE_32RVAL1 | SE_32RVAL2: 7940Sstevel@tonic-gate /* r_val1 and r_val2 returned */ 7950Sstevel@tonic-gate case SE_64RVAL: 7960Sstevel@tonic-gate /* 64-bit rval returned */ 7970Sstevel@tonic-gate break; 7980Sstevel@tonic-gate default: 7990Sstevel@tonic-gate cmn_err(CE_WARN, "loadable syscall: %p: bad rval flags %x", 8000Sstevel@tonic-gate (void *)modl, modl->sys_sysent->sy_flags); 8010Sstevel@tonic-gate return (ENOSYS); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate #endif 8040Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 8050Sstevel@tonic-gate return (ENOSPC); 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* 8080Sstevel@tonic-gate * We should only block here until the reader in syscall gives 8090Sstevel@tonic-gate * up the lock. Multiple writers are prevented in the mod layer. 8100Sstevel@tonic-gate */ 8110Sstevel@tonic-gate rw_enter(sysp->sy_lock, RW_WRITER); 8120Sstevel@tonic-gate mp = modl->sys_sysent; 8130Sstevel@tonic-gate sysp->sy_narg = mp->sy_narg; 8140Sstevel@tonic-gate sysp->sy_call = mp->sy_call; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * clear the old call method flag, and get the new one from the module. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate sysp->sy_flags &= ~SE_ARGC; 8200Sstevel@tonic-gate sysp->sy_flags |= SE_LOADED | 8210Sstevel@tonic-gate (mp->sy_flags & (SE_ARGC | SE_NOUNLOAD | SE_RVAL_MASK)); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * If the syscall doesn't need or want unloading, it can avoid 8250Sstevel@tonic-gate * the locking overhead on each entry. Convert the sysent to a 8260Sstevel@tonic-gate * normal non-loadable entry in that case. 8270Sstevel@tonic-gate */ 8280Sstevel@tonic-gate if (mp->sy_flags & SE_NOUNLOAD) { 8290Sstevel@tonic-gate if (mp->sy_flags & SE_ARGC) { 8300Sstevel@tonic-gate sysp->sy_callc = (int64_t (*)())mp->sy_call; 8310Sstevel@tonic-gate } else { 8320Sstevel@tonic-gate sysp->sy_callc = syscall_ap; 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADABLE; 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8370Sstevel@tonic-gate return (0); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * Remove a loadable system call entry from a sysent table. 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate static int 8440Sstevel@tonic-gate mod_removesys_sysent( 8450Sstevel@tonic-gate struct modlsys *modl, 8460Sstevel@tonic-gate struct modlinkage *modlp, 8470Sstevel@tonic-gate struct sysent table[]) 8480Sstevel@tonic-gate { 8490Sstevel@tonic-gate struct sysent *sysp; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL || 8520Sstevel@tonic-gate (sysp->sy_flags & (SE_LOADABLE | SE_NOUNLOAD)) == 0 || 8530Sstevel@tonic-gate sysp->sy_call != modl->sys_sysent->sy_call) { 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 8560Sstevel@tonic-gate char *modname = mcp->mod_modname; 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 8590Sstevel@tonic-gate return (EINVAL); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate /* If we can't get the write lock, we can't unlink from the system */ 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate if (!(moddebug & MODDEBUG_NOAUL_SYS) && 8650Sstevel@tonic-gate rw_tryenter(sysp->sy_lock, RW_WRITER)) { 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Check the flags to be sure the syscall is still 8680Sstevel@tonic-gate * (un)loadable. 8690Sstevel@tonic-gate * If SE_NOUNLOAD is set, SE_LOADABLE will not be. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate if ((sysp->sy_flags & (SE_LOADED | SE_LOADABLE)) == 8720Sstevel@tonic-gate (SE_LOADED | SE_LOADABLE)) { 8730Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADED; 8740Sstevel@tonic-gate sysp->sy_callc = loadable_syscall; 8750Sstevel@tonic-gate sysp->sy_call = (int (*)())nosys; 8760Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8770Sstevel@tonic-gate return (0); 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate return (EBUSY); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate /* 8850Sstevel@tonic-gate * System call status info 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate /*ARGSUSED*/ 8880Sstevel@tonic-gate static int 8890Sstevel@tonic-gate mod_infosys(struct modlsys *modl, struct modlinkage *modlp, int *p0) 8900Sstevel@tonic-gate { 8910Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent); 8920Sstevel@tonic-gate return (0); 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /* 8960Sstevel@tonic-gate * Link a system call into the system by setting the proper sysent entry. 8970Sstevel@tonic-gate * Called from the module's _init routine. 8980Sstevel@tonic-gate */ 8990Sstevel@tonic-gate static int 9000Sstevel@tonic-gate mod_installsys(struct modlsys *modl, struct modlinkage *modlp) 9010Sstevel@tonic-gate { 9020Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent)); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * Unlink a system call from the system. 9070Sstevel@tonic-gate * Called from a modules _fini routine. 9080Sstevel@tonic-gate */ 9090Sstevel@tonic-gate static int 9100Sstevel@tonic-gate mod_removesys(struct modlsys *modl, struct modlinkage *modlp) 9110Sstevel@tonic-gate { 9120Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent)); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * 32-bit system call status info 9190Sstevel@tonic-gate */ 9200Sstevel@tonic-gate /*ARGSUSED*/ 9210Sstevel@tonic-gate static int 9220Sstevel@tonic-gate mod_infosys32(struct modlsys *modl, struct modlinkage *modlp, int *p0) 9230Sstevel@tonic-gate { 9240Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent32); 9250Sstevel@tonic-gate return (0); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate /* 9290Sstevel@tonic-gate * Link the 32-bit syscall into the system by setting the proper sysent entry. 9300Sstevel@tonic-gate * Also called from the module's _init routine. 9310Sstevel@tonic-gate */ 9320Sstevel@tonic-gate static int 9330Sstevel@tonic-gate mod_installsys32(struct modlsys *modl, struct modlinkage *modlp) 9340Sstevel@tonic-gate { 9350Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent32)); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9390Sstevel@tonic-gate * Unlink the 32-bit flavor of a system call from the system. 9400Sstevel@tonic-gate * Also called from a module's _fini routine. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate static int 9430Sstevel@tonic-gate mod_removesys32(struct modlsys *modl, struct modlinkage *modlp) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent32)); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* 9510Sstevel@tonic-gate * Filesystem status info 9520Sstevel@tonic-gate */ 9530Sstevel@tonic-gate /*ARGSUSED*/ 9540Sstevel@tonic-gate static int 9550Sstevel@tonic-gate mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0) 9560Sstevel@tonic-gate { 9570Sstevel@tonic-gate struct vfssw *vswp; 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate RLOCK_VFSSW(); 9600Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) 9610Sstevel@tonic-gate *p0 = -1; 9620Sstevel@tonic-gate else { 9630Sstevel@tonic-gate *p0 = vswp - vfssw; 9640Sstevel@tonic-gate vfs_unrefvfssw(vswp); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate RUNLOCK_VFSSW(); 9670Sstevel@tonic-gate return (0); 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate /* 9710Sstevel@tonic-gate * Install a filesystem. 9720Sstevel@tonic-gate */ 9730Sstevel@tonic-gate /*ARGSUSED1*/ 9740Sstevel@tonic-gate static int 9750Sstevel@tonic-gate mod_installfs(struct modlfs *modl, struct modlinkage *modlp) 9760Sstevel@tonic-gate { 9770Sstevel@tonic-gate struct vfssw *vswp; 9780Sstevel@tonic-gate struct modctl *mcp; 9790Sstevel@tonic-gate char *fsname; 9801488Srsb char ksname[KSTAT_STRLEN + 1]; 9811488Srsb int fstype; /* index into vfssw[] and vsanchor_fstype[] */ 9820Sstevel@tonic-gate int allocated; 9830Sstevel@tonic-gate int err; 9841488Srsb int vsw_stats_enabled; 9851488Srsb /* Not for public consumption so these aren't in a header file */ 9861488Srsb extern int vopstats_enabled; 9871488Srsb extern vopstats_t **vopstats_fstype; 9881488Srsb extern kstat_t *new_vskstat(char *, vopstats_t *); 9891488Srsb extern void initialize_vopstats(vopstats_t *); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) { 9920Sstevel@tonic-gate /* Version matched */ 9930Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 9940Sstevel@tonic-gate } else { 9950Sstevel@tonic-gate if ((modl->fs_vfsdef->def_version > 0) && 9960Sstevel@tonic-gate (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) { 9970Sstevel@tonic-gate /* Older VFSDEF_VERSION */ 9980Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 9990Sstevel@tonic-gate } else if ((mcp = mod_getctl(modlp)) != NULL) { 10000Sstevel@tonic-gate /* Pre-VFSDEF_VERSION */ 10010Sstevel@tonic-gate fsname = mcp->mod_modname; 10020Sstevel@tonic-gate } else { 10030Sstevel@tonic-gate /* If all else fails... */ 10040Sstevel@tonic-gate fsname = "<unknown file system type>"; 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate cmn_err(CE_WARN, "file system '%s' version mismatch", fsname); 10080Sstevel@tonic-gate return (ENXIO); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate allocated = 0; 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate WLOCK_VFSSW(); 10140Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) { 10150Sstevel@tonic-gate if ((vswp = allocate_vfssw(fsname)) == NULL) { 10160Sstevel@tonic-gate WUNLOCK_VFSSW(); 10170Sstevel@tonic-gate /* 10180Sstevel@tonic-gate * See 1095689. If this message appears, then 10190Sstevel@tonic-gate * we either need to make the vfssw table bigger 10200Sstevel@tonic-gate * statically, or make it grow dynamically. 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname); 10230Sstevel@tonic-gate return (ENXIO); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate allocated = 1; 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate ASSERT(vswp != NULL); 10280Sstevel@tonic-gate 10291488Srsb fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */ 10301488Srsb 10311488Srsb /* Turn on everything by default *except* VSW_STATS */ 10321488Srsb vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS); 10331488Srsb 10340Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_HASPROTO) { 10350Sstevel@tonic-gate vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto, 10360Sstevel@tonic-gate &vswp->vsw_optproto); 10370Sstevel@tonic-gate } else { 10380Sstevel@tonic-gate vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto); 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_CANRWRO) { 10420Sstevel@tonic-gate /* 10430Sstevel@tonic-gate * This obviously implies VSW_CANREMOUNT. 10440Sstevel@tonic-gate */ 10450Sstevel@tonic-gate vswp->vsw_flag |= VSW_CANREMOUNT; 10460Sstevel@tonic-gate } 10471488Srsb 10481488Srsb /* 10491488Srsb * If stats are enabled system wide and for this fstype, then 10501488Srsb * set the VSW_STATS flag in the proper vfssw[] table entry. 10511488Srsb */ 10521488Srsb if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) { 10531488Srsb vswp->vsw_flag |= VSW_STATS; 10541488Srsb } 10551488Srsb 10560Sstevel@tonic-gate if (modl->fs_vfsdef->init == NULL) 10570Sstevel@tonic-gate err = EFAULT; 10580Sstevel@tonic-gate else 10591488Srsb err = (*(modl->fs_vfsdef->init))(fstype, fsname); 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate if (err != 0) { 10620Sstevel@tonic-gate if (allocated) { 10630Sstevel@tonic-gate kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1); 10640Sstevel@tonic-gate vswp->vsw_name = ""; 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate vswp->vsw_flag = 0; 10670Sstevel@tonic-gate vswp->vsw_init = NULL; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10701488Srsb /* We don't want to hold the vfssw[] write lock over a kmem_alloc() */ 10711488Srsb vsw_stats_enabled = vswp->vsw_flag & VSW_STATS; 10721488Srsb 10730Sstevel@tonic-gate vfs_unrefvfssw(vswp); 10740Sstevel@tonic-gate WUNLOCK_VFSSW(); 10750Sstevel@tonic-gate 10761488Srsb /* If everything is on, set up the per-fstype vopstats */ 10771488Srsb if (vsw_stats_enabled && vopstats_enabled && 10781488Srsb vopstats_fstype && vopstats_fstype[fstype] == NULL) { 10791488Srsb (void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname)); 10801488Srsb (void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname)); 10811488Srsb vopstats_fstype[fstype] = 10821488Srsb kmem_alloc(sizeof (vopstats_t), KM_SLEEP); 10831488Srsb initialize_vopstats(vopstats_fstype[fstype]); 10841488Srsb (void) new_vskstat(ksname, vopstats_fstype[fstype]); 10851488Srsb } 10860Sstevel@tonic-gate return (err); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate /* 10900Sstevel@tonic-gate * Remove a filesystem 10910Sstevel@tonic-gate */ 10920Sstevel@tonic-gate static int 10930Sstevel@tonic-gate mod_removefs(struct modlfs *modl, struct modlinkage *modlp) 10940Sstevel@tonic-gate { 10950Sstevel@tonic-gate struct vfssw *vswp; 10960Sstevel@tonic-gate struct modctl *mcp; 10970Sstevel@tonic-gate char *modname; 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_FS) 11000Sstevel@tonic-gate return (EBUSY); 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate WLOCK_VFSSW(); 11030Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) { 11040Sstevel@tonic-gate mcp = mod_getctl(modlp); 11050Sstevel@tonic-gate ASSERT(mcp != NULL); 11060Sstevel@tonic-gate modname = mcp->mod_modname; 11070Sstevel@tonic-gate WUNLOCK_VFSSW(); 11080Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 11090Sstevel@tonic-gate return (EINVAL); 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate if (vswp->vsw_count != 1) { 11120Sstevel@tonic-gate vfs_unrefvfssw(vswp); 11130Sstevel@tonic-gate WUNLOCK_VFSSW(); 11140Sstevel@tonic-gate return (EBUSY); 11150Sstevel@tonic-gate } 11160Sstevel@tonic-gate 11172712Snn35248 /* 11182712Snn35248 * A mounted filesystem could still have vsw_count = 0 11192712Snn35248 * so we must check whether anyone is actually using our ops 11202712Snn35248 */ 11210Sstevel@tonic-gate if (vfs_opsinuse(&vswp->vsw_vfsops)) { 11221403Ssp92102 vfs_unrefvfssw(vswp); 11230Sstevel@tonic-gate WUNLOCK_VFSSW(); 11240Sstevel@tonic-gate return (EBUSY); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate vfs_freeopttbl(&vswp->vsw_optproto); 11280Sstevel@tonic-gate vswp->vsw_optproto.mo_count = 0; 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate vswp->vsw_flag = 0; 11310Sstevel@tonic-gate vswp->vsw_init = NULL; 11320Sstevel@tonic-gate vfs_unrefvfssw(vswp); 11330Sstevel@tonic-gate WUNLOCK_VFSSW(); 11340Sstevel@tonic-gate return (0); 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * Get status of a streams module. 11390Sstevel@tonic-gate */ 11400Sstevel@tonic-gate /*ARGSUSED*/ 11410Sstevel@tonic-gate static int 11420Sstevel@tonic-gate mod_infostrmod(struct modlstrmod *modl, struct modlinkage *modlp, int *p0) 11430Sstevel@tonic-gate { 11440Sstevel@tonic-gate *p0 = -1; /* no useful info */ 11450Sstevel@tonic-gate return (0); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* 11500Sstevel@tonic-gate * Install a streams module. 11510Sstevel@tonic-gate */ 11520Sstevel@tonic-gate /*ARGSUSED*/ 11530Sstevel@tonic-gate static int 11540Sstevel@tonic-gate mod_installstrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate struct fmodsw *fp = modl->strmod_fmodsw; 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate if (!(fp->f_flag & D_MP)) { 11590Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: MT-unsafe strmod '%s' rejected", 11600Sstevel@tonic-gate fp->f_name); 11610Sstevel@tonic-gate return (ENXIO); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate return (fmodsw_register(fp->f_name, fp->f_str, fp->f_flag)); 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate /* 11680Sstevel@tonic-gate * Remove a streams module. 11690Sstevel@tonic-gate */ 11700Sstevel@tonic-gate /*ARGSUSED*/ 11710Sstevel@tonic-gate static int 11720Sstevel@tonic-gate mod_removestrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11730Sstevel@tonic-gate { 11740Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_STR) 11750Sstevel@tonic-gate return (EBUSY); 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate return (fmodsw_unregister(modl->strmod_fmodsw->f_name)); 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate /* 11810Sstevel@tonic-gate * Get status of a scheduling class module. 11820Sstevel@tonic-gate */ 11830Sstevel@tonic-gate /*ARGSUSED1*/ 11840Sstevel@tonic-gate static int 11850Sstevel@tonic-gate mod_infosched(struct modlsched *modl, struct modlinkage *modlp, int *p0) 11860Sstevel@tonic-gate { 11870Sstevel@tonic-gate int status; 11880Sstevel@tonic-gate auto id_t cid; 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate if (status != 0) 11930Sstevel@tonic-gate *p0 = -1; 11940Sstevel@tonic-gate else 11950Sstevel@tonic-gate *p0 = cid; 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate return (0); 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate /* 12010Sstevel@tonic-gate * Install a scheduling class module. 12020Sstevel@tonic-gate */ 12030Sstevel@tonic-gate /*ARGSUSED1*/ 12040Sstevel@tonic-gate static int 12050Sstevel@tonic-gate mod_installsched(struct modlsched *modl, struct modlinkage *modlp) 12060Sstevel@tonic-gate { 12070Sstevel@tonic-gate sclass_t *clp; 12080Sstevel@tonic-gate int status; 12090Sstevel@tonic-gate id_t cid; 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate /* 12120Sstevel@tonic-gate * See if module is already installed. 12130Sstevel@tonic-gate */ 12140Sstevel@tonic-gate mutex_enter(&class_lock); 12150Sstevel@tonic-gate status = alloc_cid(modl->sched_class->cl_name, &cid); 12160Sstevel@tonic-gate mutex_exit(&class_lock); 12170Sstevel@tonic-gate ASSERT(status == 0); 12180Sstevel@tonic-gate clp = &sclass[cid]; 12190Sstevel@tonic-gate rw_enter(clp->cl_lock, RW_WRITER); 12200Sstevel@tonic-gate if (SCHED_INSTALLED(clp)) { 12210Sstevel@tonic-gate printf("scheduling class %s is already installed\n", 1222*5206Sis modl->sched_class->cl_name); 12230Sstevel@tonic-gate rw_exit(clp->cl_lock); 12240Sstevel@tonic-gate return (EBUSY); /* it's already there */ 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate clp->cl_init = modl->sched_class->cl_init; 12280Sstevel@tonic-gate clp->cl_funcs = modl->sched_class->cl_funcs; 12290Sstevel@tonic-gate modl->sched_class = clp; 12300Sstevel@tonic-gate disp_add(clp); 12310Sstevel@tonic-gate loaded_classes++; /* for priocntl system call */ 12320Sstevel@tonic-gate rw_exit(clp->cl_lock); 12330Sstevel@tonic-gate return (0); 12340Sstevel@tonic-gate } 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate /* 12370Sstevel@tonic-gate * Remove a scheduling class module. 12380Sstevel@tonic-gate * 12390Sstevel@tonic-gate * we only null out the init func and the class functions because 12400Sstevel@tonic-gate * once a class has been loaded it has that slot in the class 12410Sstevel@tonic-gate * array until the next reboot. We don't decrement loaded_classes 12420Sstevel@tonic-gate * because this keeps count of the number of classes that have 12430Sstevel@tonic-gate * been loaded for this session. It will have to be this way until 12440Sstevel@tonic-gate * we implement the class array as a linked list and do true 12450Sstevel@tonic-gate * dynamic allocation. 12460Sstevel@tonic-gate */ 12470Sstevel@tonic-gate static int 12480Sstevel@tonic-gate mod_removesched(struct modlsched *modl, struct modlinkage *modlp) 12490Sstevel@tonic-gate { 12500Sstevel@tonic-gate int status; 12510Sstevel@tonic-gate sclass_t *clp; 12520Sstevel@tonic-gate struct modctl *mcp; 12530Sstevel@tonic-gate char *modname; 12540Sstevel@tonic-gate id_t cid; 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 12570Sstevel@tonic-gate if (status != 0) { 12580Sstevel@tonic-gate mcp = mod_getctl(modlp); 12590Sstevel@tonic-gate ASSERT(mcp != NULL); 12600Sstevel@tonic-gate modname = mcp->mod_modname; 12610Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 12620Sstevel@tonic-gate return (EINVAL); 12630Sstevel@tonic-gate } 12640Sstevel@tonic-gate clp = &sclass[cid]; 12650Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_SCHED || 12660Sstevel@tonic-gate !rw_tryenter(clp->cl_lock, RW_WRITER)) 12670Sstevel@tonic-gate return (EBUSY); 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate clp->cl_init = NULL; 12700Sstevel@tonic-gate clp->cl_funcs = NULL; 12710Sstevel@tonic-gate rw_exit(clp->cl_lock); 12720Sstevel@tonic-gate return (0); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * Get status of an exec module. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate /*ARGSUSED1*/ 12790Sstevel@tonic-gate static int 12800Sstevel@tonic-gate mod_infoexec(struct modlexec *modl, struct modlinkage *modlp, int *p0) 12810Sstevel@tonic-gate { 12820Sstevel@tonic-gate struct execsw *eswp; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) 12850Sstevel@tonic-gate *p0 = -1; 12860Sstevel@tonic-gate else 12870Sstevel@tonic-gate *p0 = eswp - execsw; 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate return (0); 12900Sstevel@tonic-gate } 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate /* 12930Sstevel@tonic-gate * Install an exec module. 12940Sstevel@tonic-gate */ 12950Sstevel@tonic-gate static int 12960Sstevel@tonic-gate mod_installexec(struct modlexec *modl, struct modlinkage *modlp) 12970Sstevel@tonic-gate { 12980Sstevel@tonic-gate struct execsw *eswp; 12990Sstevel@tonic-gate struct modctl *mcp; 13000Sstevel@tonic-gate char *modname; 13010Sstevel@tonic-gate char *magic; 13020Sstevel@tonic-gate size_t magic_size; 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate /* 13050Sstevel@tonic-gate * See if execsw entry is already allocated. Can't use findexectype() 13060Sstevel@tonic-gate * because we may get a recursive call to here. 13070Sstevel@tonic-gate */ 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) { 13100Sstevel@tonic-gate mcp = mod_getctl(modlp); 13110Sstevel@tonic-gate ASSERT(mcp != NULL); 13120Sstevel@tonic-gate modname = mcp->mod_modname; 13130Sstevel@tonic-gate magic = modl->exec_execsw->exec_magic; 13140Sstevel@tonic-gate magic_size = modl->exec_execsw->exec_maglen; 13150Sstevel@tonic-gate if ((eswp = allocate_execsw(modname, magic, magic_size)) == 13160Sstevel@tonic-gate NULL) { 13170Sstevel@tonic-gate printf("no unused entries in 'execsw'\n"); 13180Sstevel@tonic-gate return (ENOSPC); 13190Sstevel@tonic-gate } 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate if (eswp->exec_func != NULL) { 13220Sstevel@tonic-gate printf("exec type %x is already installed\n", 1323*5206Sis *eswp->exec_magic); 13240Sstevel@tonic-gate return (EBUSY); /* it's already there! */ 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate rw_enter(eswp->exec_lock, RW_WRITER); 13280Sstevel@tonic-gate eswp->exec_func = modl->exec_execsw->exec_func; 13290Sstevel@tonic-gate eswp->exec_core = modl->exec_execsw->exec_core; 13300Sstevel@tonic-gate rw_exit(eswp->exec_lock); 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate return (0); 13330Sstevel@tonic-gate } 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate /* 13360Sstevel@tonic-gate * Remove an exec module. 13370Sstevel@tonic-gate */ 13380Sstevel@tonic-gate static int 13390Sstevel@tonic-gate mod_removeexec(struct modlexec *modl, struct modlinkage *modlp) 13400Sstevel@tonic-gate { 13410Sstevel@tonic-gate struct execsw *eswp; 13420Sstevel@tonic-gate struct modctl *mcp; 13430Sstevel@tonic-gate char *modname; 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate eswp = findexecsw(modl->exec_execsw->exec_magic); 13460Sstevel@tonic-gate if (eswp == NULL) { 13470Sstevel@tonic-gate mcp = mod_getctl(modlp); 13480Sstevel@tonic-gate ASSERT(mcp != NULL); 13490Sstevel@tonic-gate modname = mcp->mod_modname; 13500Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 13510Sstevel@tonic-gate return (EINVAL); 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_EXEC || 13540Sstevel@tonic-gate !rw_tryenter(eswp->exec_lock, RW_WRITER)) 13550Sstevel@tonic-gate return (EBUSY); 13560Sstevel@tonic-gate eswp->exec_func = NULL; 13570Sstevel@tonic-gate eswp->exec_core = NULL; 13580Sstevel@tonic-gate rw_exit(eswp->exec_lock); 13590Sstevel@tonic-gate return (0); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate /* 13630Sstevel@tonic-gate * Find a free sysent entry or check if the specified one is free. 13640Sstevel@tonic-gate */ 13650Sstevel@tonic-gate static struct sysent * 13660Sstevel@tonic-gate mod_getsysent(struct modlinkage *modlp, struct sysent *se) 13670Sstevel@tonic-gate { 13680Sstevel@tonic-gate int sysnum; 13690Sstevel@tonic-gate struct modctl *mcp; 13700Sstevel@tonic-gate char *mod_name; 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * This happens when we're looking up the module 13750Sstevel@tonic-gate * pointer as part of a stub installation. So 13760Sstevel@tonic-gate * there's no need to whine at this point. 13770Sstevel@tonic-gate */ 13780Sstevel@tonic-gate return (NULL); 13790Sstevel@tonic-gate } 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate mod_name = mcp->mod_modname; 13820Sstevel@tonic-gate 13830Sstevel@tonic-gate if ((sysnum = mod_getsysnum(mod_name)) == -1) { 13840Sstevel@tonic-gate cmn_err(CE_WARN, "system call missing from bind file"); 13850Sstevel@tonic-gate return (NULL); 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate if (sysnum > 0 && sysnum < NSYSCALL && 13890Sstevel@tonic-gate (se[sysnum].sy_flags & (SE_LOADABLE | SE_NOUNLOAD))) 13900Sstevel@tonic-gate return (se + sysnum); 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate cmn_err(CE_WARN, "system call entry %d is already in use", sysnum); 13930Sstevel@tonic-gate return (NULL); 13940Sstevel@tonic-gate } 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate /* 13970Sstevel@tonic-gate * IP Policy Modules. 13980Sstevel@tonic-gate */ 13990Sstevel@tonic-gate /*ARGSUSED*/ 14000Sstevel@tonic-gate static int 14010Sstevel@tonic-gate mod_infoipp(struct modlipp *modl, struct modlinkage *modlp, int *p0) 14020Sstevel@tonic-gate { 14030Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14040Sstevel@tonic-gate ipp_mod_id_t mid; 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate if (mcp == NULL) { 14070Sstevel@tonic-gate *p0 = -1; 14080Sstevel@tonic-gate return (0); /* module is not yet installed */ 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate *p0 = mid; 14140Sstevel@tonic-gate return (0); 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate static int 14180Sstevel@tonic-gate mod_installipp(struct modlipp *modl, struct modlinkage *modlp) 14190Sstevel@tonic-gate { 14200Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate ASSERT(mcp != NULL); 14230Sstevel@tonic-gate return (ipp_mod_register(mcp->mod_modname, modl->ipp_ops)); 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate /*ARGSUSED*/ 14270Sstevel@tonic-gate static int 14280Sstevel@tonic-gate mod_removeipp(struct modlipp *modl, struct modlinkage *modlp) 14290Sstevel@tonic-gate { 14300Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14310Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 14320Sstevel@tonic-gate ipp_mod_id_t mid; 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate ASSERT(mcp != NULL); 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_IPP) && (mod_aul_thread == curthread)) 14370Sstevel@tonic-gate return (EBUSY); 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 14400Sstevel@tonic-gate ASSERT(mid != IPP_MOD_INVAL); 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate return (ipp_mod_unregister(mid)); 14430Sstevel@tonic-gate } 1444*5206Sis 1445*5206Sis /* 1446*5206Sis * Manage kiconv modules. 1447*5206Sis */ 1448*5206Sis /*ARGSUSED*/ 1449*5206Sis static int 1450*5206Sis mod_installkiconv(struct modlkiconv *modl, struct modlinkage *modlp) 1451*5206Sis { 1452*5206Sis return (kiconv_register_module(modl->kiconv_moddef)); 1453*5206Sis } 1454*5206Sis 1455*5206Sis /*ARGSUSED*/ 1456*5206Sis static int 1457*5206Sis mod_removekiconv(struct modlkiconv *modl, struct modlinkage *modlp) 1458*5206Sis { 1459*5206Sis return (kiconv_unregister_module(modl->kiconv_moddef)); 1460*5206Sis } 1461