/* * ml.c - loadable module support functions * * $Revision: 1.49 $ */ #include "lboot.h" #include "boothdr.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void do_mlist(void); void do_mloadreg(int, char *[], int); void do_munloadreg(int, int[], int); void do_mregister(void); static long mloadreg(struct driver *, int); static void prmodule(mod_info_t *); static char *ml_err(int); static medt_t *makeedt(struct lboot_edt *); static int autoreg = 0; /* doing autoreg or manual reg */ extern char *slash_boot; /* path to /usr/sysgen/boot */ extern struct driver *driver; /* head of struct driver linked list */ /* * do_mlist - List out all currently loaded and registered modules */ void do_mlist(void) { int size, i, modcnt; mod_info_t *mod, *modspc; if (!(size = (int)syssgi(SGI_MCONFIG, CF_LIST, 0))) { fprintf(stderr, "No modules loaded or registered.\n"); exit (1); } modspc = (mod_info_t *)malloc(size); if (!modspc) { fprintf(stderr, "No memory for module list.\n"); exit (1); } if (syssgi(SGI_MCONFIG, CF_LIST, modspc, size) != size || errno != 0) { fprintf(stderr, "Error copying module list: %s.\n", ml_err(errno)); exit (1); } if (!size) { fprintf(stderr, "Error reading module list.\n"); exit(1); } if (modspc->m_cfg_version != M_CFG_CURRENT_VERSION) { fprintf(stderr, "Kernel version mismatch.\n"); exit(1); } printf ("\nLoaded Modules:\n"); modcnt = 0; for (mod = modspc, i = 0; i < size/sizeof(mod_info_t); ++i, ++mod) { if ((mod->m_flags & (M_REGISTERED|M_LOADED)) != M_LOADED) continue; modcnt++; prmodule(mod); } if (!modcnt) printf ("None.\n"); printf ("\nRegistered Modules:\n"); modcnt = 0; for (mod = modspc, i = 0; i < size/sizeof(mod_info_t); ++i, ++mod) { if ((mod->m_flags & (M_REGISTERED|M_LOADED)) != M_REGISTERED) continue; modcnt++; prmodule(mod); } if (!modcnt) printf ("None.\n"); printf ("\nRegistered and Currently Loaded Modules:\n"); modcnt = 0; for (mod = modspc, i = 0; i < size/sizeof(mod_info_t); ++i, ++mod) { if ((mod->m_flags & (M_REGISTERED|M_LOADED)) != (M_REGISTERED|M_LOADED)) continue; modcnt++; prmodule(mod); } if (!modcnt) printf ("None.\n"); printf ("\n"); exit(0); } /* * do_mloadreg - Load or Register a list of modules */ void do_mloadreg(int modloadc, char *modloadv[], int cmd) { int i; /* * Parse the system file. Quit if it is bad. */ if (0 != parse_system()) { fprintf (stderr, "System file parse bad.\n"); exit(1); } for ( i = 0; i < modloadc; i++ ) { struct driver *dp; if ( !(dp = searchdriver(modloadv[i])) ) { fprintf(stderr,"Can't find module %s.\n", modloadv[i]); exit(1); } if (!dp->dname) { fprintf (stderr,"Can't find object file %s/%s.[oa]\n", slash_boot, modloadv[i]); continue; } mloadreg(dp, cmd); } } /* * do_munloadreg - Unload or Unregister a list of modules by id number */ void do_munloadreg(int modunldc, int modunldv[], int cmd) { int i; cap_t ocap; cap_value_t cap_device_mgt = CAP_DEVICE_MGT; for ( i = 0; i < modunldc; i++ ) { ocap = cap_acquire(1, &cap_device_mgt); if (syssgi(SGI_MCONFIG, cmd, modunldv[i])) { fprintf(stderr, "Can not %s module id %d: %s.\n", (cmd == CF_UNLOAD) ? "unload" : "unregister", modunldv[i], ml_err(errno)); } cap_surrender(ocap); } } /* * do_mregister - Register all loadable kernel modules that have * an 'R' in their master file. This is called by loadunix only - * if Smart (lboot called from autoconfig), or if Autoreg (lboot -a). */ void do_mregister (void) { long id; register struct driver *dp; cap_t ocap; cap_value_t cap_device_mgt = CAP_DEVICE_MGT; autoreg = 1; dp = driver; /* * First register all of the modules that have major numbers * assigned to them, then register the others. This is * necessary so that we don't grab a major number that * another module requires. */ while (dp) { /* * For modules that add to the h/w inventory in either * init or edtinit, we must load them, then unload and * register them. This is necessary since MAKEDEV will * not make a device file if it doesn't find the device * in hinv. If the module is just registered only, then * its init and edtinit routines have not been run and * hasn't been added to the hinv. If the master file * contains a 'D', then we load it and then unload it. */ if ((dp->dname) && (dp->opthdr->flag & DYNAMIC) && (dp->opthdr->flag & DLDREG)) { id = mloadreg (dp, CF_LOAD); ocap = cap_acquire(1, &cap_device_mgt); syssgi(SGI_MCONFIG, CF_UNLOAD, id); cap_surrender(ocap); } /* * If there's an object file and the master file * contains a 'd' and an 'R', register it. */ if ((dp->dname) && (dp->opthdr->flag & DYNAMIC) && (dp->opthdr->flag & DYNREG) && (dp->opthdr->soft[0] != DONTCARE)) mloadreg (dp, CF_REGISTER); dp = dp->next; } dp = driver; while (dp) { /* * If there's an object file and the master file * contains a 'd' and an 'R', register it. */ if ((dp->dname) && (dp->opthdr->flag & DYNAMIC) && (dp->opthdr->flag & DYNREG) && (dp->opthdr->soft[0] == DONTCARE)) mloadreg (dp, CF_REGISTER); dp = dp->next; } autoreg = 0; } /* * loadreg - load or register a module */ static long mloadreg(struct driver *dp, int cmd) { cfg_desc_t desc; union mod_dep m; char *fname; int error = 0; int i; cap_t ocap; cap_value_t cap_device_mgt = CAP_DEVICE_MGT; bzero(&m, sizeof m); bzero(&desc, sizeof desc); /* create a complete pathname to the module .o for register */ fname = malloc (strlen(slash_boot) + strlen(dp->dname) + 2); strcpy (fname, slash_boot); strcat (fname, "/"); strcat (fname, dp->dname); desc.m_cfg_version = M_CFG_CURRENT_VERSION; desc.m_fname = fname; desc.m_data = &m; strcpy(desc.m_prefix, dp->opthdr->prefix); if (dp->opthdr->flag & (CHAR|BLOCK|FUNDRV)) { /* Module type is driver */ desc.m_type = M_DRIVER; /* Driver type is char, block, or stream */ if ((dp->opthdr->flag & (BLOCK|CHAR)) == (BLOCK|CHAR)) m.d.d_type = MDRV_BLOCK|MDRV_CHAR; else if (dp->opthdr->flag & CHAR) m.d.d_type = MDRV_CHAR; else if (dp->opthdr->flag & BLOCK) m.d.d_type = MDRV_BLOCK; else if (dp->opthdr->flag & FUNDRV) m.d.d_type = MDRV_STREAM; if (dp->edtp) m.d.d_edtp = makeedt (dp->edtp); if (!dp->opthdr->nsoft ) { m.d.d_nmajors = 1; m.d.d_majors[0] = MAJOR_ANY; } else { for (i=0; iopthdr->nsoft; i++) { if (dp->opthdr->soft[i] == DONTCARE) m.d.d_majors[i] = MAJOR_ANY; else m.d.d_majors[i] = dp->opthdr->soft[i]; } m.d.d_nmajors = dp->opthdr->nsoft; } /* Locking only takes place if driver's devflag says so */ m.d.d_cpulock = -1; if ((dp->flag & INEDT) || dp->opthdr->sema == S_PROC ) m.d.d_cpulock = lock_on_cpu(dp->opthdr, dp); } else if (dp->opthdr->flag & FUNMOD) { /* Module type is streams */ desc.m_type = M_STREAMS; strcpy (m.s.s_name, dp->mname); } else if (dp->opthdr->flag & FSTYP) { desc.m_type = M_FILESYS; fprintf(stderr,"Dynamic filesystem loading not supported.\n"); exit(1); } else if (dp->opthdr->flag & ENET) { desc.m_type = M_ENET; if (dp->edtp) m.e.e_edtp = makeedt (dp->edtp); } if (!(dp->opthdr->flag & DYNREG) || (dp->opthdr->flag & NOUNLD)) desc.m_delay = M_NOUNLD; else desc.m_delay = M_UNLDDEFAULT; ocap = cap_acquire(1, &cap_device_mgt); error = (int) syssgi(SGI_MCONFIG, cmd, &desc); cap_surrender(ocap); if (error) { if (!autoreg) fprintf(stderr, "Module %s %s failed: %s.\n", fname, ((cmd == CF_LOAD) ? "load" : "register"), ml_err(errno)); } else { if (!autoreg) syslog (LOG_NOTICE, "Module %s dynamically %s.\n", fname, ((cmd == CF_LOAD) ? "loaded" : "registered")); } free (fname); if (!error) return (desc.m_id); else return error; } /* * makeedt - copy the edt information from lboot's version of the * edt struct to the sys/edt.h version of the struct. */ medt_t * makeedt (struct lboot_edt *ledtp) { int i; struct lboot_edt *ep; medt_t *medtp, *mep; edt_t *edtp; struct vme_intrs *vme; struct iospace *iosp; struct lboot_iospace *liosp; /* * If there are multiple ctrls, then lboot produces a list * of edt structs for each driver. For each edt, copy the * lboot info into the edt struct to be sent to mload. */ ep = ledtp; medtp = mep = malloc (sizeof (medt_t)); while (ep) { mep->edtp = edtp = malloc (sizeof (edt_t)); mep->medt_next = (medt_t *)0; edtp->e_bus_type = ep->e_bus_type; edtp->v_cpuintr = ep->v_cpuintr; edtp->e_adap = ep->e_adap; edtp->e_ctlr = ep->e_ctlr; if (ep->v_next) { vme = edtp->e_bus_info = (void *) malloc (sizeof(struct vme_intrs)); vme->v_vintr = (int (*)(int)) ep->v_next->v_vname; vme->v_vec = ep->v_next->v_vec; vme->v_brl = ep->v_next->v_brl; vme->v_unit = ep->v_next->v_unit; } else edtp->e_bus_info = (void *)0; edtp->e_init = (int (*)(struct edt *))ep->e_init; iosp = &edtp->e_space[0]; liosp = &ep->e_space[0]; for (i=0; iios_type = liosp->ios_type; iosp->ios_iopaddr = liosp->ios_iopaddr; iosp->ios_size = liosp->ios_size; /* Only called on live system, so not an issue * with 32-bit lboot cross-lbooting a 64-bit kernel * (64-bit kernels get a 64-bit lboot). */ iosp->ios_vaddr = (caddr_t)liosp->ios_vaddr; } if (ep = ep->e_next) { mep->medt_next = malloc (sizeof (medt_t)); mep = mep->medt_next; } } return (medtp); } /* * prmodule - print information about the module */ static void prmodule(mod_info_t *mod) { int i; printf ("Id: %d\t", mod->m_id); switch (mod->m_type) { case M_DRIVER: if (mod->m_driver.d_type == MDRV_CHAR) printf ("Character "); else if (mod->m_driver.d_type == MDRV_BLOCK) printf ("Block "); else if (mod->m_driver.d_type == (MDRV_BLOCK|MDRV_CHAR)) printf ("Character/Block "); else if (mod->m_driver.d_type == MDRV_STREAM) printf ("Streams "); else printf ("Unknown "); printf ("device driver: prefix %s, ", mod->m_prefix); for (i=0; im_driver.d_nmajors; i++) printf ("major %d, ", mod->m_driver.d_majors[i]); if (mod->m_delay != M_NOUNLD) { printf ("unload delay %d minutes, ", mod->m_delay); } else printf ("no auto-unload, "); printf ("filename %s\n", mod->m_fname); break; case M_STREAMS: printf ("Streams module: "); printf ("prefix %s, fmodsw name %s, ", mod->m_prefix, mod->m_stream.s_name); if (mod->m_delay != M_NOUNLD) { printf ("unload delay %d minutes, ", mod->m_delay); } else printf ("no auto-unload, "); printf ("filename %s\n", mod->m_fname); break; case M_IDBG: printf ("Idbg module: filename %s\n", mod->m_fname); break; case M_LIB: printf ("Library module: filename %s\n", mod->m_fname); break; case M_SYMTAB: printf ("Symbol Table module: "); if (mod->m_delay != M_NOUNLD) { printf ("unload delay %d minutes, ", mod->m_delay); } else printf ("no auto-unload, "); printf ("filename %s\n", mod->m_fname); break; case M_FILESYS: printf ("File system: filename %s \n", mod->m_fname); break; case M_ENET: printf ("Ethernet module: "); printf ("prefix %s, filename %s\n", mod->m_prefix, mod->m_fname); break; default: printf ("Unknown module type\n"); break; } } static char * ml_err(int error) { switch (error) { case EPERM: return ("Must be super-user to use this command"); case MERR_ENOENT: return ("No such file or directory"); case MERR_ENAMETOOLONG: return ("Path name too long"); case MERR_VREG: return ("File not a regular file"); case EIO: return ("I/O error"); case ENXIO: return ("No such device or address"); case MERR_VOP_OPEN: return ("VOP_OPEN failed"); case MERR_VOP_CLOSE: return ("VOP_CLOSE failed"); case MERR_COPY: return ("Copyin/copyout failed"); case MERR_BADMAGIC: return ("Object file format not ELF"); case MERR_BADFH: return ("Error reading file header"); case MERR_BADAH: return ("Error reading a.out header"); case MERR_BADSH: return ("Error reading section header"); case MERR_BADTEXT: return ("Error reading text section"); case EBUSY: return ("Device busy"); case MERR_BADDATA: return ("Error reading data section"); case MERR_BADREL: return ("Error reading relocation records"); case MERR_BADSYMHEAD: return ("Error reading symbol header"); case MERR_BADEXSTR: return ("Error reading external string table"); case MERR_BADEXSYM: return ("Error reading external symbol table"); case MERR_NOSEC: return ("Error reading file header sections"); case MERR_NOSTRTAB: return ("No string table found for object"); case MERR_NOSYMS: return ("No symbols found for object"); case MERR_BADARCH: return ("Bad EF_MIPS_ARCH arch type"); case MERR_SHSTR: return ("Error reading section header string table"); case MERR_SYMTAB: return ("Error reading section symbol table"); case MERR_STRTAB: return ("Error reading section string table"); case MERR_NOTEXT: return ("No text or textrel section found in object"); case MERR_SHNDX: return ("Bad section index"); case MERR_UNKNOWN_CFCMD: return ("Unknown syssgi command"); case MERR_UNKNOWN_SYMCMD: return ("Unknown syssgi sym command"); case MERR_FINDADDR: return ("Address not found in symbol tables"); case MERR_FINDNAME: return ("Name not found in symbol tables"); case MERR_SYMEFAULT: return ("Address fault on sym command"); case MERR_NOELF: return ("Dynamically loadable ELF modules not supported"); case MERR_UNSUPPORTED: return ("Feature unsupported"); case MERR_LOADOFF: return ("Dynamic loading turned off"); case MERR_BADID: return ("Module id not found"); case MERR_NOTLOADED: return ("Module not loaded"); case MERR_NOTREGED: return ("Module not registered"); case MERR_OPENBUSY: return ("Can not open, device busy"); case MERR_UNLOADBUSY: return ("Can not unload module, device busy"); case MERR_UNREGBUSY: return ("Can not unregister module, device busy"); case MERR_ILLDRVTYPE: return ("Illegal driver type"); case MERR_NOMAJOR: return ("No major passed in cfg information"); case MERR_NOMAJORS: return ("Out of major numbers"); case MERR_ILLMAJOR: return ("Illegal major number"); case MERR_MAJORUSED: return ("Major number already in use"); case MERR_SWTCHFULL: return ("Switch table is full"); case MERR_UNLDFAIL: return ("Unload function failed"); case MERR_DOLD: return ("D_OLD drivers not supported as loadable modules"); case MERR_NODEVFLAG: return ("No xxxdevflag found"); case MERR_NOINFO: return ("No xxxinfo found"); case MERR_NOOPEN: return ("No xxxopen found"); case MERR_NOCLOSE: return ("No xxxclose found"); case MERR_NOMMAP: return ("No xxxmmap found"); case MERR_NOSTRAT: return ("No xxxstrategy found"); case MERR_NOSIZE: return ("No xxxsize found"); case MERR_NOUNLD: return ("No xxxunload found"); case MERR_NOVFSOPS: return ("No xxxvfsops found"); case MERR_NOVNODEOPS: return ("No xxxvnodops found"); case MERR_NOINIT: return ("No xxxinit found"); case MERR_NOINTR: return ("No xxxintr found"); case MERR_NOEDTINIT: return ("No xxxedtinit found"); case MERR_NOSTRNAME: return ("Stream name missing"); case MERR_STRDUP: return ("Duplicate streams name"); case MERR_NOPREFIX: return ("No prefix sent in cfg information"); case MERR_NOMODTYPE: return ("No module type sent in descriptor"); case MERR_BADMODTYPE: return ("Bad module type sent in descriptor"); case MERR_BADCFGVERSION: return ("Lboot version out of date with kernel version"); case MERR_BADVERSION: return ("Module version out of date with kernel version"); case MERR_NOVERSION: return ("Module version string is missing"); case MERR_BADLINK: return ("Can't resolve all symbols in object"); case MERR_BADJMP: return ("Address outside of jal range - use jalr"); case MERR_BADRTYPE: return ("Bad relocation type"); case MERR_GP: return ("GP section unsupported - compile with -G0"); case MERR_BADSC: return ("Unexpected storage class encountered"); case MERR_REFHI: return ("Unexpected REFHI relocation type"); case MERR_NORRECS: return ("No relocation records found in object"); case MERR_SCNDATA: return ("Bad data section encountered in object"); case MERR_COMMON: return ("Common storage class in object not supported"); case MERR_JMP256: return ("Can't relocate j in a 256MB boundary on an R4000"); case MERR_LIBUNLD: return ("Library modules can not be unloaded"); case MERR_LIBREG: return ("Library modules can not be registered/unregistered"); case MERR_NOLIBIDS: return ("Out of library module ids"); case MERR_IDBG: return ("Error loading idbg.o module"); case MERR_IDBGREG: return ("The idbg.o module can not be registered/unregistered"); case MERR_NOENETIDS: return ("Out of ethernet module ids"); case MERR_ENETREG: return ("Ethernet modules can not be registered"); case MERR_ENETUNREG: return ("Ethernet modules can not be unregistered"); case MERR_ENETUNLOAD: return ("Ethernet modules can not be unloaded"); case MERR_NOFSYSNAME: return ("No filesystem name specified"); case MERR_DUPFSYS: return ("filesystem already exists in vfssw table"); case MERR_VECINUSE: return ("Interrupt vector in use"); case MERR_BADADAP: return ("No adapter found"); case MERR_NOEDTDATA: return ("No edt data for ethernet driver"); case MERR_ELF64: return ("A 64bit kernel requires a 64bit loadable module"); case MERR_ELF32: return ("A 32bit kernel requires a 32bit loadable module"); case MERR_ELFN32: return ("An N32 kernel requires an N32 loadable module"); case MERR_ELF64COFF: return ("A 64bit kernel requires a 64bit ELF loadable module"); case MERR_ET_REL: return ("Loadable modules must be built as relocatable"); case MERR_SYMTABREG: return ("Can not reg/unreg a symbol table module"); case MERR_NOSYMTABIDS: return ("Out of symbol table module ids"); case MERR_NOSYMTAB: return ("No symbol table found in object"); case MERR_DUPSYMTAB: return ("Symbol table for this filename already exists"); case MERR_NOSYMTABAVAIL: return ("No runtime symbol table available for running kernel"); case MERR_SYMTABMISMATCH: return ("Symbol table doesn't not match running kernel"); default: return ("Error unknown"); } }