1
0
Files
irix-657m-src/irix/cmd/lboot/ml.c
2022-09-29 17:59:04 +03:00

815 lines
18 KiB
C

/*
* ml.c - loadable module support functions
*
* $Revision: 1.49 $
*/
#include "lboot.h"
#include "boothdr.h"
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/syssgi.h>
#include <sys/param.h>
#include <syslog.h>
#include <sys/conf.h>
#include <sys/fstyp.h>
#include <sys/edt.h>
#include <sys/vmereg.h>
#include <sys/mload.h>
#include <sys/capability.h>
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; i<dp->opthdr->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; i<NBASE; i++, iosp++, liosp++) {
iosp->ios_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; i<mod->m_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");
}
}