This commit is contained in:
seta75D
2021-10-11 18:37:13 -03:00
commit ff309bfe1c
14130 changed files with 3180272 additions and 0 deletions

63
usr.etc/mod/Makefile Normal file
View File

@@ -0,0 +1,63 @@
#
# @(#)Makefile 1.1 94/10/31 SMI
#
# makefile for loadable module utilities
# ASP is Architecture Specific; modload (specifically, modloadconf.c)
# depends upon the kernel sub-architecture
BIN = modunload modstat
ASP = modload
ALL = ${BIN} ${ASP}
ARCH:sh = arch
KARCH:sh = arch -k
COMMON = modsubr.o
MODLOAD = modload.o modloadconf.o modloadsym.o modloadhdr.o
OBJ = ${MODLOAD} modunload.o modstat.o ${COMMON}
ASOBJ = modloadconf.o
DESTDIR =
BINDIR = /usr/etc
OWNER = root
# Install directory for architecture-specific programs, absolute path
#
ASDIR= /usr/kvm
# Install directory for architecture-specific programs, relative path
#
RELASDIR= ../kvm
CFLAGS = -O
${ASOBJ} := CFLAGS += -U${ARCH} -D${KARCH}
all: ${ALL}
modload: ${MODLOAD} ${COMMON}
${CC} -o modload ${MODLOAD} ${COMMON} -lkvm
modunload: modunload.o ${COMMON}
${CC} -o modunload modunload.o ${COMMON}
modstat: modstat.o ${COMMON}
${CC} -o modstat modstat.o ${COMMON}
install: ${ALL}
for i in ${BIN}; do \
${RM} ${DESTDIR}${BINDIR}/$$i; \
install -c -s -m 755 -o ${OWNER} \
$$i ${DESTDIR}${BINDIR}/$$i ; \
done
for i in ${ASP}; do \
${RM} ${DESTDIR}${BINDIR}/$$i; \
install -c -s -m 755 -o ${OWNER} \
$$i ${DESTDIR}${ASDIR}/$$i; \
ln -s ${RELASDIR}/$$i ${DESTDIR}${BINDIR}/$$i ; \
done
clean:
rm -f ${OBJ} ${ALL}

558
usr.etc/mod/modload.c Normal file
View File

@@ -0,0 +1,558 @@
/* @(#)modload.c 1.1 94/10/31 SMI */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sun/vddrv.h>
#include <nlist.h>
#include <fcntl.h>
#include <string.h>
#include <kvm.h>
char *rawinputfile = NULL; /* input file as specified by the user */
char *inputfilename = NULL; /* input file name without any extension */
char *outputfile = NULL; /* name of output file */
char *unixfile = "/vmunix"; /* default kernel image to link with */
char *entrypoint; /* module entry point routine */
char *execfile; /* name of user file to exec after loading */
char *conffile; /* name of user configuration file */
int dopt = 0; /* debug option */
int sopt = 0; /* option to generate a symbol table */
int vopt = 0; /* verbose option */
int mod_id = 0; /* module ID returned by driver */
u_long mod_addr; /* virtual address at which module is loaded */
u_int mod_size; /* size in bytes of module */
int vd; /* file descriptor for /dev/vd */
void quit(), usage(), error(), fatal(), vinfo();
static caddr_t linkmodule();
static int checkversion();
static void getargs(), exec_userfile();
static void strip(), ld(), exec_ld();
extern struct vdconf *getconfinfo();
extern char *malloc();
/*
* Load a module.
*/
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
struct vdioctl_load vdiload; /* structure used with VDLOAD ioctl */
/*
* Get arguments
*/
getargs(argc, argv);
/*
* Open the pseudo driver to load the module
*/
if ((vd = open("/dev/vd", O_RDWR)) < 0)
error("can't open /dev/vd");
/*
* Catch signals so we can cleanup
*/
(void) signal(SIGINT, quit);
/*
* Link the module at its proper virtual address.
* Verify this it is being linked with the proper kernel.
* Generate the symbol table.
*/
vdiload.vdi_mmapaddr = linkmodule(vd, &vdiload.vdi_symtabsize);
vdiload.vdi_id = mod_id;
/*
* Get configuration information
*/
vdiload.vdi_userconf = getconfinfo(conffile);
/*
* Now load the module into the system
*/
if (!sopt)
strip(outputfile);
if (ioctl(vd, VDLOAD, &vdiload) < 0)
error("can't load this module");
/*
* Exec the user's file (if any)
*/
if (execfile)
exec_userfile(vd, mod_id, envp);
printf("module loaded; id = %d\n", mod_id);
exit(0); /* success */
}
/*
* Link the module at its proper virtual address.
*
* First we have to link the module (any address will do!) to find out its size.
* This is because the size of the bss is not determined until the final link.
* After we know the size, we can ask the kernel (VDGETVADDR ioctl) for the
* next available address of this size. Then we link the module at its
* final virtual address.
*
* In order to get the actual module size, we have to generate the symbol
* table here.
*/
static caddr_t
linkmodule(vd, symtabsize)
int vd;
u_int *symtabsize;
{
register int fd;
register caddr_t mmapaddr;
struct vdioctl_getvaddr vdigetvaddr;
struct stat statbuf;
u_int tvaddr, tsize, toffset;
u_int dvaddr, dsize, doffset;
u_int bvaddr, bsize;
/*
* Link at any address just so we can find out the size of the bss.
*/
ld((u_long)0);
/*
* Make sure the version of unix that the module was linked with
* is the same as the running version of unix.
*/
if (checkversion() != 0)
fatal(
"Module must be relinked with the running kernel (use modload -A option)\n");
if (!sopt)
strip(outputfile);
if ((fd = open(outputfile, 0)) < 0)
error("can't open %s", outputfile);
if (fstat(fd, &statbuf) < 0)
error("can't stat %s", outputfile);
/*
* mmap the module image file
*/
mmapaddr = mmap((caddr_t)0, (int)statbuf.st_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0);
if (mmapaddr == (caddr_t)-1)
error("can't mmap %s", outputfile);
readhdr(mmapaddr, &tvaddr, &tsize, &toffset,
&dvaddr, &dsize, &doffset, &bvaddr, &bsize);
checkhdr(tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize);
vdigetvaddr.vdi_size = (bvaddr - tvaddr + bsize);
if (sopt) {
/*
* Generate symbol table and get its size.
*/
vdigetvaddr.vdi_size +=
getsymtab(outputfile, mmapaddr,
(u_long)0, vdigetvaddr.vdi_size);
}
close(fd); /* close and munmap the image */
/*
* Now that we know the module size, we ask the kernel for
* the virtual address at which to link the module.
*/
if (ioctl(vd, VDGETVADDR, &vdigetvaddr) < 0)
error("can't get a virtual address for this module");
/*
* Add header sizes to the virtual address. This is the final
* link address for the module.
*/
vdigetvaddr.vdi_vaddr += gethdrsize();
/*
* Save module info for later use
*/
mod_id = vdigetvaddr.vdi_id;
mod_addr = vdigetvaddr.vdi_vaddr;
mod_size = vdigetvaddr.vdi_size;
vinfo("module id = %d, vaddr = %x, size = %x\n",
mod_id, mod_addr, mod_size);
ld(mod_addr); /* link the module again */
if ((fd = open(outputfile, 0)) < 0)
error("can't open %s", outputfile);
if (fstat(fd, &statbuf) < 0)
error("can't stat %s", outputfile);
/*
* mmap the module image file again now that we've relinked.
*/
mmapaddr = mmap((caddr_t)0, (int)statbuf.st_size,
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0);
if (mmapaddr == (caddr_t)-1)
error("can't mmap %s", outputfile);
*symtabsize = (sopt) ?
getsymtab(outputfile, mmapaddr, mod_addr, mod_size)
: 0;
return (mmapaddr);
}
/*
* Exec "ld" to link the module at a specified virtual address.
*/
static void
ld(vaddr)
u_long vaddr;
{
int child;
union wait status;
vinfo("Linking the module...\n");
child = fork();
if (child == -1)
error("can't fork ld");
else if (child == 0)
exec_ld(vaddr);
else {
wait(&status); /* wait for ld to finish */
if (status.w_retcode != 0) {
vinfo("ld failed, status = %x\n", status.w_retcode);
exit(-2); /* ld already printed messages */
}
}
}
static void
strip(file)
char *file;
{
int child;
union wait status;
vinfo("Removing symbol table...\n");
child = fork();
if (child == -1)
error("can't fork strip");
else if (child == 0) {
execlp("/bin/strip", "strip", file, (char *)0);
error("couldn't exec /bin/strip");
} else {
wait(&status); /* wait for ld to finish */
if (status.w_retcode != 0) {
vinfo("ld failed, status = %x\n", status.w_retcode);
exit(-2); /* ld already printed messages */
}
}
}
/*
* Exec strip to remove symbol table
*/
#ifdef sun386
#define EXECTYPE "-z"
#define DEFAULTENTRY "xxxinit"
#else
#define EXECTYPE "-N"
#define DEFAULTENTRY "_xxxinit"
#endif sun386
static void
exec_ld(vaddr)
u_long vaddr;
{
char addr[12];
sprintf(addr, "%lx", vaddr);
if (entrypoint == NULL)
entrypoint = DEFAULTENTRY;
vinfo("/bin/ld -o %s -Bstatic -T %s -A %s %s -e %s %s %s\n",
outputfile, addr, unixfile, EXECTYPE, entrypoint,
sopt == 0 ? "-s": "", rawinputfile);
execlp("/bin/ld", "ld", "-o", outputfile, "-Bstatic", "-T", addr,
"-A", unixfile, EXECTYPE, "-e", entrypoint,
rawinputfile, (char *)0);
error("couldn't exec /bin/ld");
}
/*
* Make sure that the module is being linked with the running kernel.
*
* The module has been linked with the kernel named <unixfile>.
* This routine finds the version string in <unixfile> and compares
* it to the version string in memory. They must match.
*/
static struct nlist nl[] = {
#ifdef COFF
{ "version" },
#else
{ "_version"},
#endif
"",
};
#define MAXVERSIONLEN 256 /* max length of kernel version string */
static int
checkversion()
{
kvm_t *kd;
int kmemf, unixf;
char *kaddr, *uaddr;
u_int datavaddr, dataoffset, voff;
struct stat statbuf; /* file status buffer */
if ((kmemf = open("/dev/kmem", 0)) < 0)
error("can't open /dev/kmem");
if ((unixf = open(unixfile, 0)) < 0)
error("can't open %s", unixfile);
if (fstat(unixf, &statbuf) < 0)
error("can't stat %s", unixfile);
kd = kvm_open(unixfile, (char *)NULL, (char *)NULL,
O_RDONLY, "kvm_open");
if (kd == NULL)
error("modload failed");
if (kvm_nlist(kd, nl) < 0)
fatal("bad namelist in kernel symbol table\n");
if (nl[0].n_value == 0)
fatal("missing 'version' symbol in kernel symbol table\n");
uaddr = mmap((caddr_t)0, (int)statbuf.st_size, PROT_READ,
MAP_PRIVATE, unixf, (off_t)0);
if (uaddr == (caddr_t)-1)
error("can't mmap %s", unixfile);
kaddr = mmap((caddr_t)0, 2 * MMU_PAGESIZE, PROT_READ, MAP_SHARED,
kmemf, (off_t)(nl[0].n_value & ~PAGEOFFSET));
if (kaddr == (caddr_t)-1)
error("can't mmap /dev/kmem");
/* get data virtual address and offset */
getkerneldata(uaddr, &datavaddr, &dataoffset);
/* offset of version in image file */
voff = nl[0].n_value - datavaddr + dataoffset;
if (strncmp(uaddr + voff, kaddr + (nl[0].n_value & PAGEOFFSET),
MAXVERSIONLEN) != 0)
return (-1);
return (0);
}
/*
* Exec the user's file
*/
static void
exec_userfile(vd, id, envp)
int vd;
int id;
char **envp;
{
struct vdioctl_stat vdistat;
struct vdstat vdstat;
int child;
union wait status;
char module_id[8];
char magic[16];
char blockmajor[8];
char charmajor[8];
char sysnum[8];
child = fork();
if (child == -1)
error("can't fork %s", execfile);
/*
* exec the user program.
*/
if (child == 0) {
vdistat.vdi_vdstat = &vdstat; /* status buf */
vdistat.vdi_vdstatsize = sizeof (struct vdstat); /* size */
vdistat.vdi_id = id; /* module id */
vdistat.vdi_statsubfcn = SUNSTATSUBFCN; /* subfcn */
if (ioctl(vd, VDSTAT, &vdistat) < 0)
error("can't get module status");
sprintf(module_id, "%d", vdstat.vds_id);
sprintf(magic, "%x", vdstat.vds_magic);
if (vdstat.vds_magic == VDMAGIC_DRV ||
vdstat.vds_magic == VDMAGIC_MBDRV ||
vdstat.vds_magic == VDMAGIC_PSEUDO) {
sprintf(blockmajor, "%d", vdstat.vds_modinfo[0] & 0xff);
sprintf(charmajor, "%d", vdstat.vds_modinfo[1] & 0xff);
execle(execfile, execfile, module_id, magic, blockmajor,
charmajor, (char *)0, envp);
} else if (vdstat.vds_magic == VDMAGIC_SYS) {
sprintf(sysnum, "%d", vdstat.vds_modinfo[0] & 0xff);
execle(execfile, execfile, module_id, magic,
sysnum, (char *)0, envp);
} else {
execle(execfile, execfile, module_id, magic,
(char *)0, envp);
}
/* Shouldn't get here if execle was successful */
error("couldn't exec %s", execfile);
} else {
wait(&status); /* wait for exec'd program to finish */
if (status.w_retcode != 0) {
vinfo("%s returned error %d.\n", status.w_retcode);
exit(-2);
}
}
}
/*
* Get user arguments.
*/
static void
getargs(argc, argv)
int argc;
char *argv[];
{
char *ap, *ext;
if (argc < 2)
usage();
argc--; /* skip program name */
argv++;
while (argc--) {
ap = *argv++; /* point at next option */
if (*ap++ == '-') {
if (strcmp(ap, "conf") == 0) {
if (--argc < 0)
usage();
conffile = *argv++;
} else if (strcmp(ap, "d") == 0) {
dopt = 1;
} else if (strcmp(ap, "sym") == 0) {
sopt = 1;
} else if (strcmp(ap, "entry") == 0) {
if (--argc < 0)
usage();
entrypoint = *argv++;
} else if (strcmp(ap, "o") == 0) {
if (--argc < 0)
usage();
outputfile = *argv++;
} else if (strcmp(ap, "A") == 0) {
if (--argc < 0)
usage();
unixfile = *argv++;
} else if (strcmp(ap, "v") == 0) {
vopt = 1;
} else if (strcmp(ap, "exec") == 0) {
if (--argc < 0)
usage();
execfile = *argv++;
} else {
usage();
}
} else if (rawinputfile == NULL) { /* module file */
rawinputfile = *--argv;
argv++;
} else
usage();
}
if (rawinputfile == NULL)
usage();
ext = strrchr(rawinputfile, '.');
if (ext == NULL || strcmp(&ext[1], "o") != 0)
fatal("file_name must end with .o\n");
inputfilename = malloc((u_int)(ext - rawinputfile + 1));
if (inputfilename == NULL)
error("malloc");
(void) strncpy(inputfilename, rawinputfile, ext - rawinputfile);
if (outputfile == NULL)
outputfile = inputfilename;
vinfo("infile %s, infilename %s, outfile %s, execfile %s\n",
rawinputfile, inputfilename, outputfile, execfile);
}
void
usage()
{
printf("usage: modload filename [options]\n");
printf(" where options are:\n");
printf(" -A <vmunix_file>\n");
printf(" -conf <configuration_file>\n");
printf(" -entry <entry_point>\n");
printf(" -exec <exec_file>\n");
printf(" -o <output_file>\n");
printf(" -sym\n"); /* keep symbols */
exit(-1);
}
void
quit()
{
struct vdioctl_freevaddr vdi;
vdi.vdi_id = mod_id;
(void) ioctl(vd, VDFREEVADDR, (caddr_t)&vdi);
exit(-1);
}
#include <varargs.h>
/*VARARGS0*/
void
vinfo(va_alist)
va_dcl
{
va_list args;
char *fmt;
if (!vopt)
return;
va_start(args);
fmt = va_arg(args, char *);
vprintf(fmt, args);
}

917
usr.etc/mod/modloadconf.c Normal file
View File

@@ -0,0 +1,917 @@
/* @(#)modloadconf.c 1.1 94/10/31 */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <nlist.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sundev/mbvar.h>
#include <sun/autoconf.h>
#include <sun/vddrv.h>
/*
* Process the configuration file. You could get as fancy as you like here.
* The code from the config program could be used to do what we have
* to do here. But for now, the simple table driven approach suffices.
*
* getconfinfo() reads each line of the configuration file and produces
* a linked list of confinfo entries. There is one confinfo entry per
* non-comment line in the configuration file. Then, the list of confinfo
* entries is checked for consistency and if it's ok, an array of
* vddrv entries is produced.
*
* The vddrv array is the actual output of this routine. A pointer to
* the start of the array is then used in the VDLOAD ioctl to load the module.
*
* Here are the types of configuration commands that we support:
*
* 0) # a comment line begins with a "#"
* 1) controller <name><number> at {atmem, atio, obmem} <options>
* 2) device <name><number> at {<controller>, atmem, atio, obmem} <options>
* 3) disk <name><number> at {<controller>, atmem, atio, obmem} <options>
* 4) blockmajor <number>
* 5) charmajor <number>
*
* where <options> are
* drive <drive number>
* csr <csr address>
* irq <interrupt request line>
* priority <interrupt priority>
* dmachan <dma channel>
* flags <flags>
*
* and <controller> on the "device" line means the <name><number> of
* a controller. <name> must not have any numbers in it.
*
* For example:
*
* controller fdc0 at atmem ? csr 0x001000 irq 6 priority 3
* controller fdc2 at atmem ? csr 0x002000 irq 5 priority 2
* disk fd0 at fdc0 drive 0
* #disk fd0 at fdc0 drive 1
* disk fd0 at fdc0 drive 2
* device fd0 at fdc2 drive 0
* disk fd0 at fdc2 drive 1
* blockmajor 51
* charmajor 52
*/
extern char *calloc();
extern long strtol();
extern char *outputfile;
#ifndef sun4c
static void conf_controller(), conf_disk(), conf_device();
#endif /* sun4c */
static void conf_blockmajor(), conf_charmajor(), conf_syscallnum();
#ifndef sun4c
static struct mb_ctlr *gen_ctlr();
static struct mb_device *gen_device();
#ifndef sun386
static struct vec *gen_vector();
#endif
#endif /* sun4c */
static void parse_line(), read_literal();
static struct vdconf *gen_vdconf();
static struct confinfo *getcip();
static char *alloc(), *getword(), *getname(), *getstring();
static int getint();
#ifndef sun4c
static int getnum(), getctlrnum();
#endif /* sun4c */
#ifndef sun4c
static void getdrive(), getcsr(), getirq(), getpriority(), getvector();
static void getdmachan(), getflags(), getbusconn();
#endif /* sun4c */
struct veclist { /* List of VME interrupt vectors */
struct veclist *next;
struct vec vec;
};
/*
* An instance of this structure is malloc'd and filled in for each non-comment
* line in the configuration file. After we've read the entire configuration
* file, we go through this array checking for consistency and then generate
* the vdconf array.
*/
static struct confinfo {
struct confinfo *next; /* pointer to next */
int type; /* type of configuration info */
int linenum; /* linenumber this was gen'd for */
char *name; /* controller or device name */
char *conname; /* name of connection (ctlr or bus) */
int disk; /* conf type is "disk" */
int space; /* bus type */
int drive; /* drive number */
int csr; /* csr address */
int irq; /* interrupt request number */
int priority; /* interrupt priority */
struct veclist *vectors; /* VME interrupt vectors */
int dmachan; /* dma channel */
int flags; /* flags */
int majornum; /* major number */
int syscallnum; /* system call number */
caddr_t data; /* pointer to generic data */
} *confinfo;
/*
* Dispatch table for each type of configuration command.
*/
static struct confdispatch {
char *conftype; /* configuration command */
void (*conffcn)(); /* function to process this type */
} confdispatch[] = {
#ifndef sun4c
{ "controller", conf_controller },
{ "device", conf_device },
{ "disk", conf_disk },
#endif /* sun4c */
{ "blockmajor", conf_blockmajor },
{ "charmajor", conf_charmajor },
{ "syscallnum", conf_syscallnum },
{ NULL, 0 },
};
/*
* Various bus types.
*/
static struct bustype {
char *name;
int type;
} bustype[] = {
#ifdef sun386
{ "obmem", SP_OBMEM },
{ "atmem", SP_ATMEM },
{ "atio", SP_ATIO },
{ NULL, 0 }
#else
{ "obmem", SP_OBMEM },
{ "obio", SP_OBIO },
{ "mbmem", SP_MBMEM },
{ "mbio", SP_MBIO },
{ "vme16d16", SP_VME16D16 },
{ "vme24d16", SP_VME24D16 },
{ "vme32d16", SP_VME32D16 },
{ "vme16d32", SP_VME16D32 },
{ "vme24d32", SP_VME24D32 },
{ "vme32d32", SP_VME32D32 },
{ NULL, 0 }
#endif
};
/*
* Configuration options.
*/
static struct options {
char *name;
void (*optfcn)();
} options[] = {
#ifndef sun4c
{ "drive", getdrive },
{ "csr", getcsr },
{ "vector", getvector },
{ "priority", getpriority },
{ "irq", getirq },
#ifdef sun386
{ "dmachan", getdmachan },
#endif
{ "flags", getflags },
#endif /* sun4c */
{ NULL, NULL }
};
#define MAXLINE 1000
#define COMMENT_CHAR '#'
#define streq(a, b) (strcmp(a, b) == 0)
#define new_array(T, n) ((T *)alloc(n, sizeof (T)))
#define new_struct(T) new_array(T, 1)
#define new_string(n) new_array(char, n)
static char line[MAXLINE]; /* current input line */
static int linenum = 0; /* configuration file line number */
static int confentries = 0; /* number of confinfo entries */
extern int dopt; /* debug option */
/*
* Process the configuration file. (See comments above.)
*
* Returns NULL if conffile is NULL.
* Returns vdconf if all is well.
* If there's a fatal error, this routine prints an error message and exits.
*/
struct vdconf *
getconfinfo(conffile)
char *conffile; /* pointer to configuration file name */
{
FILE *fp;
if (conffile == NULL)
return (NULL); /* no configuration file */
if ((fp = fopen(conffile, "r")) == NULL)
error("can't open configuration file");
while (!feof(fp))
parse_line(fp);
return (gen_vdconf(confinfo)); /* generate vdconf table */
}
static void
parse_line(fp)
FILE *fp;
{
struct confdispatch *cdp;
static struct confinfo *cip;
char *word;
int linelen;
linenum++;
if (fgets(line, MAXLINE, fp) == NULL)
return;
linelen = strlen(line);
if (linelen == MAXLINE - 1 && line[linelen] != '\n')
fatal("config file line %d too long\n", linenum);
word = getword(fp); /* get first word of next line */
if (word == NULL) /* empty line */
return;
/*
* dispatch to the appropriate configuration routine
*/
for (cdp = confdispatch; cdp->conftype != NULL; cdp++)
if (streq(cdp->conftype, word))
break;
if (cdp->conftype != NULL) {
if (confinfo == NULL)
confinfo = cip = getcip();
else {
cip->next = getcip();
cip = cip->next;
}
cip->linenum = linenum;
(*cdp->conffcn)(fp, cip);
confentries++;
} else
fatal("Unrecognized config type '%s' on line %d\n",
word, linenum);
}
/*
* Loop through all of the confinfo entries and produce the vdconf array.
*/
static struct vdconf *
gen_vdconf(confinfo)
struct confinfo *confinfo;
{
struct confinfo *cip;
struct vdconf *vdconf, *vdc;
vdconf = new_array(struct vdconf, confentries + 1);
vdconf[confentries].vdc_type = VDCEND; /* terminate table */
for (cip = confinfo, vdc = vdconf; cip; cip = cip->next, vdc++) {
vdc->vdc_type = cip->type;
switch (cip->type) {
#ifndef sun4c
case VDCCONTROLLER:
vdc->vdc_data = (long)gen_ctlr(cip);
break;
case VDCDEVICE:
vdc->vdc_data = (long)gen_device(cip);
break;
#endif /* sun4c */
case VDCBLOCKMAJOR:
vdc->vdc_data = (long)cip->majornum;
break;
case VDCCHARMAJOR:
vdc->vdc_data = (long)cip->majornum;
break;
case VDCSYSCALLNUM:
vdc->vdc_data = (long)cip->syscallnum;
break;
default:
fatal("Internal error: unknown type %x (line %d)\n",
cip->type, cip->linenum);
}
}
return (vdconf);
}
#ifndef sun4c
/*
* Generate an mb_ctlr entry for this controller.
*/
static struct mb_ctlr *
gen_ctlr(cip)
struct confinfo *cip;
{
struct mb_ctlr *mc;
struct confinfo *c;
if (dopt)
printf("gen_ctlr\n");
/*
* Check for duplicate controller names
*/
for (c = confinfo; c != NULL; c = c->next) {
if (c == cip || c->type != VDCCONTROLLER)
continue;
if (streq(c->name, cip->name))
fatal(
"Duplicate controller name '%s' (lines %d and %d)\n",
c->name, c->linenum, cip->linenum);
}
mc = new_struct(struct mb_ctlr);
mc->mc_ctlr = getnum(cip);
mc->mc_addr = (caddr_t)cip->csr;
mc->mc_intpri = cip->priority;
mc->mc_space = cip->space;
#ifdef sun386
mc->mc_intr = cip->irq;
mc->mc_dmachan = cip->dmachan;
#else
mc->mc_intr = gen_vector(cip->vectors);
#endif
return (mc);
}
/*
* Generate an mb_device entry for this device.
*/
static struct mb_device *
gen_device(cip)
struct confinfo *cip;
{
struct mb_device *md;
struct confinfo *c;
if (dopt)
printf("gen_device\n");
/*
* Check for duplicate devices on the same controller
*/
for (c = confinfo; c; c = c->next) {
if (c == cip || c->type != VDCDEVICE ||
c->drive != cip->drive ||
getctlrnum(c) != getctlrnum(cip))
continue;
if (streq(c->name, cip->name))
fatal(
"Duplicate device name '%s' (lines %d and %d)\n",
c->name, c->linenum, cip->linenum);
}
md = new_struct(struct mb_device);
md->md_unit = getnum(cip);
md->md_ctlr = getctlrnum(cip);
md->md_slave = cip->drive;
md->md_addr = (caddr_t)cip->csr;
md->md_intpri = cip->priority;
md->md_space = cip->space;
#ifdef sun386
md->md_intr = cip->irq;
md->md_dmachan = cip->dmachan;
#else
md->md_intr = gen_vector(cip->vectors);
#endif
return (md);
}
#ifndef sun386
static struct vec *
gen_vector(veclist)
struct veclist *veclist;
{
int nvec;
struct veclist *vp, *nvp;
struct vec *v, *v0;
int *ip;
nvec = 0;
for (vp = veclist; vp != NULL; vp = vp->next)
nvec++;
if (nvec == 0)
return (NULL);
v0 = v = new_array(struct vec, nvec + 1);
ip = new_array(int, nvec + 1);
for (vp = veclist; vp != NULL; vp = nvp) {
*v = vp->vec;
v->v_vptr = ip;
*ip++ = v->v_vec;
v++;
nvp = vp->next;
free((char *)vp);
}
v = NULL;
return ((struct vec *)v0);
}
#endif
/*
* Get the number from the controller or device name.
* For example, if the name is fdc2 then this routine will return 2.
*/
static int
getnum(cip)
struct confinfo *cip;
{
char *np = cip->name, *p;
long num;
while (*np != '\0' && !isdigit(*np))
np++;
if (*np == '\0')
fatal("missing unit number in '%s' on line %d\n",
cip->name, cip->linenum);
num = strtol(np, &p, 10);
if (*p != '\0')
fatal("Invalid device or controller name '%s' (line %d)\n",
cip->name, cip->linenum);
return (num);
}
/*
* Get the controller number for this device.
* returns -1 if there is no controller.
*/
static int
getctlrnum(cip)
struct confinfo *cip;
{
struct confinfo *c;
char *name, *cname;
int namelen;
if (dopt)
printf("getctlrnum\n");
if (cip->space != 0)
return (-1); /* no controller */
for (c = confinfo; c; c = c->next) {
if (c->type != VDCCONTROLLER)
continue;
if (streq(cip->conname, c->name)) {
/*
* We've found the controller that we're connected to.
* Now let's make sure that our name makes sense.
* For example, controller "fdc0" is supposed to have
* devices with names such as "fd0", "fd1", etc.
*/
name = getname(cip); /* get dev name without num */
cname = getname(c); /* get ctrl name without num */
namelen = strlen(name);
if (strncmp(name, cname, namelen) != 0 ||
cname[namelen] != 'c')
fatal(
"invalid device name '%s' for controller %s (lines %d and %d)\n",
cip->name, c->name, cip->linenum, c->linenum);
return (getnum(c));
}
}
fatal(
"Device '%s' is connected to an unknown controller '%s' (line %d)\n",
cip->name, cip->conname, cip->linenum);
/*NOTREACHED*/
}
/*
* Get the name (minus the number) of a controller or device.
*/
static char *
getname(cip)
struct confinfo *cip;
{
int len;
char *p;
if (dopt)
printf("getname\n");
p = cip->name;
while (*p != '\0' && !isdigit(*p))
p++;
len = p - cip->name;
p = new_string(len);
strncpy(p, cip->name, len);
p[len] = '\0';
return (p);
}
/*
* Generate a confinfo entry for a controller.
*/
static void
conf_controller(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("conf_controller\n");
cip->type = VDCCONTROLLER;
cip->name = getstring(fp);
read_literal(fp, "at");
getbusconn(fp, cip, VDCCONTROLLER); /* get bus that controller is on */
read_literal(fp, "?");
getoptions(fp, cip);
}
/*
* Generate a confinfo entry for a disk.
*/
static void
conf_disk(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("conf_disk\n");
conf_device(fp, cip);
cip->disk = 1;
}
/*
* Generate a confinfo entry for a device.
*/
static void
conf_device(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("conf_device\n");
cip->type = VDCDEVICE;
cip->name = getstring(fp); /* get device name and number */
read_literal(fp, "at");
getbusconn(fp, cip, VDCDEVICE); /* get bus connection */
if (cip->space != 0)
read_literal(fp, "?");
getoptions(fp, cip); /* get the rest of the options */
}
#endif /* sun4c */
/*
* Generate a confinfo entry for a blockmajor configuration line.
*/
static void
conf_blockmajor(fp, cip)
FILE *fp;
struct confinfo *cip;
{
cip->type = VDCBLOCKMAJOR;
cip->majornum = getint(fp, 0, 255);
}
/*
* Generate a confinfo entry for a charmajor configuration line.
*/
static void
conf_charmajor(fp, cip)
FILE *fp;
struct confinfo *cip;
{
cip->type = VDCCHARMAJOR;
cip->majornum = getint(fp, 0, 255);
}
/*
* Generate a confinfo entry for a system call number configuration line.
*/
static void
conf_syscallnum(fp, cip)
FILE *fp;
struct confinfo *cip;
{
cip->type = VDCSYSCALLNUM;
cip->syscallnum = getint(fp, 0, 255);
}
/*
* Allocate a confinfo entry for this line in the configuration file.
*/
static struct confinfo *
getcip()
{
struct confinfo *cip;
cip = new_struct(struct confinfo);
bzero((char *)cip, sizeof (struct confinfo));
return (cip);
}
#ifndef sun4c
/*
* Get a bus connection. For a controller it must be on the names
* in the table "bustype". For a device it can either be one of
* names in the table "bustype" or the name of a controller.
*/
static void
getbusconn(fp, cip, type)
FILE *fp;
struct confinfo *cip;
int type;
{
register struct bustype *btp;
cip->conname = getstring(fp); /* get bus connection */
for (btp = bustype; btp->name != NULL; btp++) {
if (streq(btp->name, cip->conname))
break;
}
if (btp->name != NULL)
cip->space = btp->type;
else if (type == VDCCONTROLLER) {
fatal("Unrecognized bus type '%s' on line %d\n",
cip->conname, cip->linenum);
} else
cip->space = 0;
}
#endif /* sun4c */
/*
* Copy a string from the configuration file.
*/
static char *
getstring(fp)
FILE *fp;
{
char *word;
word = getword(fp);
if (word == NULL)
fatal("missing string at line %d\n", linenum);
return (strdup(word));
}
/*
* Get an integer from the next word in the configuration file.
*/
static int
getint(fp, min, max)
FILE *fp;
int min, max;
{
char *word, *p;
long n;
if (dopt)
printf("getint\n");
word = getword(fp);
if (word == NULL)
fatal("missing integer at line %d\n", linenum);
n = strtol(word, &p, 0);
if (*p != '\0' || (min != -1 && n < min) || (max != -1 && n > max))
fatal("Invalid number '%s' on line %d\n", word, linenum);
if (dopt)
printf("word: %s, value %x\n", word, n);
return (n);
}
#ifndef sun4c
/*
* Get device and controller options.
*/
static int
getoptions(fp, cip)
FILE *fp;
register struct confinfo *cip;
{
register struct options *opt;
char *word;
if (dopt)
printf("getoptions\n");
while ((word = getword(fp)) != NULL) {
if (dopt)
printf("option: %s\n", word);
for (opt = options; opt->name != NULL; opt++) {
if (streq(opt->name, word))
break;
}
if (opt->name != NULL)
(*opt->optfcn)(fp, cip);
else
fatal("Unrecognized keyword '%s' on line %d\n",
word, cip->linenum);
}
}
/*
* Get the drive number.
*/
static void
getdrive(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getdrive\n");
cip->drive = getint(fp, 0, 255);
}
/*
* Get the csr.
*/
static void
getcsr(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getcsr\n");
cip->csr = getint(fp, -1, -1);
}
/*
* Get the interrupt request number.
*/
static void
getirq(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getirq\n");
cip->irq = getint(fp, 0, 15);
}
/*
* Get VME interrupt vector
*/
static void
getvector(fp, cip)
FILE *fp;
struct confinfo *cip;
{
struct veclist *v;
char *handler_name;
struct nlist n[2];
int vecno;
if (dopt)
printf("getvector\n");
v = new_struct(struct veclist);
handler_name = getstring(fp);
vecno = getint(fp, 0x40, 0xff);
bzero((char *)n, sizeof (n));
n[0].n_name = new_string(strlen(handler_name) + 2);
n[0].n_name[0] = '_';
strcpy(&n[0].n_name[1], handler_name);
if (nlist(outputfile, n) == -1)
fatal("can't read %s symbol table\n", outputfile);
if ((n[0].n_type & N_TYPE) != N_TEXT)
fatal("lookup of %s failed\n", handler_name);
v->vec.v_func = (int (*)()) n[0].n_value;
v->vec.v_vec = vecno;
v->vec.v_vptr = NULL;
v->next = cip->vectors;
cip->vectors = v;
}
/*
* Get the interrupt priority.
*/
static void
getpriority(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getpriority\n");
cip->priority = getint(fp, 0, 7);
}
/*
* Get the dma channel.
*/
static void
getdmachan(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getdmachan\n");
cip->dmachan = getint(fp, -1, -1);
}
/*
* Get the flags.
*/
static void
getflags(fp, cip)
FILE *fp;
struct confinfo *cip;
{
if (dopt)
printf("getflags\n");
cip->flags = getint(fp, -1, -1);
}
#endif /* sun4c */
/*
* Allocate a block of memory.
*/
static char *
alloc(nelem, elsize)
u_int nelem, elsize;
{
register char *addr = calloc(nelem, elsize);
if (addr == NULL)
fatal("out of memory (size = %x)\n", nelem * elsize);
return (addr);
}
/*
* getword
* return next word of current input line; returns NULL on EOF,
* end of line, or comment.
*/
/*ARGSUSED*/
static char *
getword(fp)
FILE *fp;
{
static char *word = NULL;
word = strtok((word == NULL) ? line : NULL, " \t\n");
if (word != NULL && *word == COMMENT_CHAR)
word = NULL; /* skip comments */
return (word);
}
static void
read_literal(fp, literal)
FILE *fp;
char *literal;
{
char *s = getword(fp);
if (s == NULL || !streq(s, literal))
fatal("missing keyword '%s' at line %d\n", literal, linenum);
}

235
usr.etc/mod/modloadhdr.c Normal file
View File

@@ -0,0 +1,235 @@
/* @(#)modloadhdr.c 1.1 94/10/31 SMI */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <sys/types.h>
#include <sys/param.h>
#ifdef sun386
#include <sys/filehdr.h>
#include <sys/scnhdr.h>
#include <sys/aouthdr.h>
#endif
#include <sys/exec.h>
void fatal(), vinfo();
#ifdef sun386
#define NUMSECS 4 /* number of section headers in the image */
/* (text, data, bss, and comment) */
/*
* Get information about an image file. This is called to read
* the headers of either the module being loaded or the kernel image file.
*/
readhdr(mmapaddr, tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
caddr_t mmapaddr;
u_int *tvaddr;
u_int *tsize;
u_int *toffset;
u_int *dvaddr;
u_int *dsize;
u_int *doffset;
u_int *bvaddr;
u_int *bsize;
{
struct filehdr *fhdr;
struct aouthdr *optaout; /* optional a.out header */
struct scnhdr *scn; /* COFF per-section info */
unsigned int numsecs; /* number of COFF sections in file */
unsigned int scns = 0; /* must have all three sections! */
/*
* Read the image file header to get module sizes.
*/
fhdr = (struct filehdr *)mmapaddr;
/* check and see if this is a COFF header. */
if (!ISCOFF(fhdr->f_magic))
fatal("module image is not a valid COFF file\n");
numsecs = fhdr->f_nscns; /* get number of section headers */
if (numsecs != NUMSECS)
fatal("there must be only text, data, bss, and comment sections\n");
if (fhdr->f_opthdr != sizeof(struct aouthdr))
fatal("invalid a.out header\n");
optaout = (struct aouthdr *)(mmapaddr +sizeof(struct filehdr));
/*
* let's get magic number and entry location from optional
* a.out header.
*/
if (optaout->magic != ZMAGIC && optaout->magic != OMAGIC &&
optaout->magic != NMAGIC)
fatal("bad a.out header magic number\n", optaout->magic);
/*
* go through each COFF section header and get
* text, data, and bss sizes.
*/
scn = (struct scnhdr *)(mmapaddr + sizeof(struct filehdr) +
sizeof(struct aouthdr));
while (numsecs-- > 0) {
switch ((int) scn->s_flags) {
case STYP_TEXT:
if (scn->s_size == 0)
fatal("text size is 0\n");
*tvaddr = ptob(btop(scn->s_vaddr));
*tsize = scn->s_size;
if (optaout->magic == ZMAGIC)
*tsize += gethdrsize();
scns |= STYP_TEXT;
break;
case STYP_DATA:
if (scn->s_size == 0)
fatal("data size is 0\n");
*dvaddr = scn->s_vaddr;
*dsize = scn->s_size;
*doffset = scn->s_scnptr;
scns |= STYP_DATA;
break;
case STYP_BSS:
*bvaddr = scn->s_vaddr;
*bsize = ctob(btoc(scn->s_size));
scns |= STYP_BSS;
break;
}
scn++; /* point to next section header */
}
/*
* For now, we assume there must be data and bss sections.
* Someday, we can ease this restriction.
*/
if (scns != (STYP_TEXT|STYP_DATA|STYP_BSS))
fatal("missing text, data, or bss sections\n");
return;
}
/*
* Return the size of the file headers in the memory image for the file.
*/
gethdrsize()
{
return (sizeof(struct filehdr) + sizeof(struct aouthdr) +
NUMSECS * sizeof(struct scnhdr));
}
/*
* Return the virtual address and offset of the kernel data segment
*/
getkerneldata(mmapaddr, daddr, doffset)
caddr_t mmapaddr;
u_int *daddr;
u_int *doffset;
{
u_int xxx;
readhdr(mmapaddr, &xxx, &xxx, &xxx, daddr, &xxx, doffset, &xxx, &xxx);
}
#else
/*
* Get information about an image file. This is called to read
* the headers of either the module being loaded or the kernel image file.
*/
readhdr(mmapaddr, tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
addr_t mmapaddr;
u_int *tvaddr;
u_int *tsize;
u_int *toffset;
u_int *dvaddr;
u_int *dsize;
u_int *doffset;
u_int *bvaddr;
u_int *bsize;
{
register struct exec *exec = (struct exec *)mmapaddr;
extern u_long mod_addr;
if (exec->a_magic != OMAGIC)
fatal("module image is not a valid OMAGIC a.out file\n");
*tvaddr = mod_addr;
*tsize = exec->a_text;
*toffset = sizeof(struct exec);
*dvaddr = *tvaddr + exec->a_text;
*dsize = exec->a_data;
*doffset = *toffset + exec->a_text;
*bvaddr = *dvaddr + exec->a_data;
*bsize = exec->a_bss;
}
/*
* Return the size of the file headers in the memory image for the file.
*/
gethdrsize()
{
return (0); /* OMAGIC has no header in memory */
}
/*
* Return the virtual address and offset of the kernel data segment
*/
getkerneldata(mmapaddr, daddr, doffset)
caddr_t mmapaddr;
u_int *daddr;
u_int *doffset;
{
register struct exec *exec = (struct exec *)mmapaddr;
if (exec->a_magic != OMAGIC)
fatal("module image is not a valid OMAGIC a.out file\n");
*daddr = exec->a_entry + exec->a_text;
*doffset = sizeof(struct exec) + exec->a_text;
}
#endif
/*
* Verify that virtual addresses and sizes are ok.
*/
/*ARGSUSED*/
checkhdr(tvaddr, tsize, toffset, dvaddr, dsize, doffset, bvaddr, bsize)
u_int tvaddr;
u_int tsize;
u_int toffset;
u_int dvaddr;
u_int dsize;
u_int doffset;
u_int bvaddr;
u_int bsize;
{
vinfo("textv %x, ts %x, datav %x, ds %x, bssv %x, bs %x\n",
tvaddr, tsize, dvaddr, dsize, bvaddr, bsize);
if (tsize == 0)
fatal("text size is 0\n");
if (tvaddr + tsize != dvaddr)
fatal("data must immediately follow the text\n");
#ifdef COFF
if (bvaddr < dvaddr || ctob(btoc(dvaddr + dsize)) != bvaddr)
fatal("bss must start in the page following the data\n");
#endif
}

260
usr.etc/mod/modloadsym.c Normal file
View File

@@ -0,0 +1,260 @@
/* @(#)modloadsym.c 1.1 94/10/31 SMI */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#ifdef sun386
#include <sys/types.h>
#include <stdio.h>
#include <filehdr.h>
#include <ldfcn.h>
#include <stab.h>
#include <syms.h>
#include <ar.h>
#include <sun/vddrv.h>
#define SYMESZ 18 /* number of bytes in one symbol table entry */
void fatal();
/*
* Read the symbol table (if any) and keep only those symbols which
* are within the module.
*
* This code from taken from nm.c.
*
* Someday we'll have support from the linker to do all this.
*/
LDFILE *fi;
getsymtab(filename, mmapaddr, modstart, modsize)
char *filename;
addr_t mmapaddr;
u_long modstart;
u_int modsize;
{
long symindx; /* symbol table index */
u_int sym_tab_size; /* symbol table size */
SYMENT *symp; /* pointer to symbol table */
SYMENT sym; /* symbol table entry */
AUXENT aux;
char *malloc();
char *symnametmp; /* ptr to symbol name in file*/
int i;
int nsyms; /* number of symbols we'll keep */
struct vdsym *vdsym; /* start of sym tab in mmap'd image */
int vdstroff; /* offset of sym name in mmap'd image */
char *vdstraddr; /* address of name in mmap'd image */
struct filehdr *fhdr; /* pointer to filehdr in mmap'd image */
extern int ncompare();
if ((fi = ldopen(filename, fi)) == NULL)
fatal("modload: %s: cannot open\n", filename);
if (!ISCOFF(HEADER(fi).f_magic))
fatal("modload: %s: bad magic\n", filename);
if (HEADER(fi).f_nsyms == 0)
return (0); /* no symbols */
/*
* seek to the symbol table
*/
if (ldtbseek(fi) != SUCCESS)
fatal("modload: %s: symbols missing from file", filename);
/*
* allocate symbol table memory
* the amount of memory needed is calculated by the
* number of entries multiplied by the size of each entry
*/
sym_tab_size = HEADER(fi).f_nsyms * sizeof (struct syment);
symp = (struct syment *)malloc(sym_tab_size);
if (symp == NULL)
fatal("ran out of memory processing symbol table", filename);
/*
* read the symbol table
*/
nsyms = 0;
for (symindx = 0L; symindx < HEADER(fi).f_nsyms; ++symindx) {
if (FREAD(&sym, SYMESZ, 1, fi) != 1)
fatal("error reading symbol table", filename);
/*
* read in and skip over any aux entries (if there are any)
*/
for (i = 1; i <= sym.n_numaux; ++i) {
if (FREAD(&aux, AUXESZ, 1, fi) != 1)
fatal("error reading symnbol table", filename);
++symindx;
}
if ((u_int)sym.n_value < modstart ||
(u_int)sym.n_value > modstart + modsize)
continue; /* skip symbols out of range */
if (sym.n_name[0] == '.')
continue; /* skip names starting with '.' */
symp[nsyms++] = sym;
}
qsort((char *)symp, nsyms, sizeof(struct syment), ncompare);
/*
* At this point we have the symbols that we're interested in
* sorted by value. Now we will generate our own symbol table
* and place it in our (private) mmap'd copy of the image.
*
* Our symbol table entry has 2 elements. The first is the offset
* from the start of the symbol table to the name of the symbol.
* This offset is converted to a virtual address by the VDLOAD ioctl
* to /dev/vd. The second element is the symbol value.
*/
vdsym = (struct vdsym *)(mmapaddr + (int)(HEADER(fi).f_symptr));
vdstroff = nsyms * sizeof(struct vdsym);
vdstraddr = (char *)&vdsym[nsyms];
for (i = 0 ; i < nsyms; i++) {
vdsym->vdsym_name = vdstroff;
vdsym->vdsym_value = symp[i].n_value;
vdsym++;
symnametmp = (char *)ldgetname(fi, &symp[i]);
strcpy(vdstraddr, symnametmp);
vdstraddr += strlen(symnametmp) + 1;
vdstroff += strlen(symnametmp) + 1;
}
fhdr = (struct filehdr *)mmapaddr;
fhdr->f_nsyms = nsyms;
ldclose(fi);
return (vdstroff); /* return symbol table size */
}
static int ncompare(p1, p2)
register struct syment *p1, *p2;
{
if (p1->n_value > p2->n_value)
return(1);
if (p1->n_value < p2->n_value)
return(-1);
return (0);
}
#else
#include <sys/types.h>
#include <sys/param.h>
#include <a.out.h>
#include <strings.h>
#include <sun/vddrv.h>
void fatal();
/*
* Read the symbol table (if any) and keep only those symbols which
* are within the module.
*
* Some of this code if from _nlist.c.
*/
getsymtab(filename, mmapaddr, modstart, modsize)
char *filename;
addr_t mmapaddr;
u_long modstart;
u_int modsize;
{
struct nlist *ksymp; /* pointer to symbols we're keeping */
struct nlist *symp; /* pointer to sym table in a.out image*/
struct nlist *symaddr; /* ptr to start of sym tab in image */
char *symnametmp; /* ptr to symbol name in file*/
int i;
int n;
int nsyms; /* number of symbols we'll keep */
struct vdsym *vdsym; /* start of sym tab in mmap'd image */
int vdstroff; /* offset of sym name in mmap'd image */
char *vdstraddr; /* address of name in mmap'd image */
struct exec *exec; /* pointer to hdr in mmap'd image */
long straddr; /* start of strings in a.out image */
extern char *malloc();
extern int ncompare();
exec = (struct exec *)mmapaddr; /* pointer to a.out header */
if (exec->a_magic != OMAGIC)
fatal("modload: %s: bad magic %o\n", filename, exec->a_magic);
if (exec->a_syms == 0)
return (0); /* no symbols */
nsyms = 0; /* number of syms we'll keep */
symaddr = (struct nlist *)(mmapaddr + N_SYMOFF(*exec));
symp = symaddr; /* ptr to first sym tab entry */
ksymp = (struct nlist *)malloc((u_int)exec->a_syms);
if (ksymp == NULL)
fatal("ran out of memory processing symbol table", filename);
for (n = exec->a_syms; n > 0; n -= sizeof(struct nlist), symp++) {
if ((u_int)symp->n_value < modstart ||
(u_int)symp->n_value > modstart + modsize)
continue; /* skip symbols out of range */
ksymp[nsyms++] = *symp; /* keep this symtab entry */
}
qsort((char *)ksymp, nsyms, sizeof(struct nlist), ncompare);
/*
* At this point we have the symbols that we're interested in
* sorted by value. Now we will generate our own symbol table
* and place it in our (private) mmap'd copy of the image.
*
* Our symbol table entry has 2 elements. The first is the offset
* from the start of the symbol table to the name of the symbol.
* This offset is converted to a virtual address by the VDLOAD ioctl
* to /dev/vd. The second element is the symbol value.
*/
vdsym = (struct vdsym *)symaddr;
vdstroff = nsyms * sizeof(struct vdsym);
vdstraddr = (char *)&vdsym[nsyms];
straddr = (long)((long)symaddr + exec->a_syms);
for (i = 0; i < nsyms; i++) {
symnametmp = (char *)(straddr + ksymp[i].n_un.n_strx);
vdsym->vdsym_value = ksymp[i].n_value;
vdsym->vdsym_name = vdstroff;
vdsym++;
strcpy(vdstraddr, symnametmp);
vdstraddr += strlen(symnametmp) + 1;
vdstroff += strlen(symnametmp) + 1;
}
exec->a_syms = nsyms;
return (vdstroff); /* return symbol table size */
}
static int ncompare(p1, p2)
register struct nlist *p1, *p2;
{
if (p1->n_value > p2->n_value)
return(1);
if (p1->n_value < p2->n_value)
return(-1);
return (0);
}
#endif

194
usr.etc/mod/modstat.c Normal file
View File

@@ -0,0 +1,194 @@
/* @(#)modstat.c 1.1 94/10/31 SMI */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <machine/param.h>
#include <sun/vddrv.h>
#include <stdio.h>
extern void error();
struct vdioctl_stat vdistat;
int stat_all, verbose;
/*
* Display status of all loaded modules
*/
main(argc, argv)
int argc;
char **argv;
{
struct vdstat vdstat;
int first_mod = 1, fd;
/*
* Open the pseudo-driver.
*/
if ((fd = open("/dev/vd", O_RDONLY, 0)) < 0)
error("can't open /dev/vd");
get_args(argc, argv);
do {
vdistat.vdi_vdstat = &vdstat; /* status buffer */
vdistat.vdi_vdstatsize = sizeof (struct vdstat); /* buf size*/
/*
* Get info about a loaded module.
*/
if (ioctl(fd, VDSTAT, (char *)&vdistat) < 0)
error("can't get module status");
if (vdistat.vdi_vdstatsize == 0) {
if (verbose)
printf("no modules loaded\n");
exit(0); /* nothing loaded */
}
if (first_mod) {
first_mod = 0;
printf(
"Id Type Loadaddr Size B-major C-major Sysnum Mod Name\n");
}
print_status(&vdstat);
} while (stat_all && vdistat.vdi_id != -1);
exit(0);
/* NOTREACHED */
}
get_args(argc, argv)
int argc;
char **argv;
{
verbose = 0;
stat_all = 1;
vdistat.vdi_id = -1;
while (--argc != 0) {
if (**++argv != '-')
usage("Invalid option %s\n", *argv);
switch ((*argv)[1]) {
case 'i':
if ((*argv)[2] != 'd')
usage("Invalid option %s\n", *argv);
if (--argc == 0)
usage("Missing module id\n");
++argv;
if (sscanf(*argv, "%d", &vdistat.vdi_id) != 1)
usage("Invalid id %s\n", *argv);
if (vdistat.vdi_id <= 0 || vdistat.vdi_id > VD_MAXID)
usage("Invalid id %d\n", vdistat.vdi_id);
stat_all = 0;
break;
case 'v':
verbose = 1;
break;
default:
usage("Invalid option %s\n", *argv);
break;
}
}
}
/*
* Display info about a loaded module.
*/
print_status(vds)
struct vdstat *vds;
{
register int magic = vds->vds_magic;
register char *type;
printf("%2d ", vds->vds_id);
switch (magic) {
case VDMAGIC_DRV:
type = " Drv";
break;
case VDMAGIC_NET:
type = " Net";
break;
case VDMAGIC_SYS:
type = " Sys";
break;
case VDMAGIC_USER:
type = "User";
break;
case VDMAGIC_PSEUDO:
type = "Pdrv";
break;
case VDMAGIC_MBDRV:
type = "Mdrv";
break;
case VDMAGIC_MBNET:
type = "Mnet";
break;
default:
type = "????";
break;
}
printf("%4.4s %8x %8x ", type, vds->vds_vaddr, vds->vds_size);
switch (magic) {
case VDMAGIC_DRV:
case VDMAGIC_PSEUDO:
case VDMAGIC_MBDRV:
if (vds->vds_modinfo[0])
printf("%3d. ", (vds->vds_modinfo[0] & 0xff));
else
printf(" ");
if (vds->vds_modinfo[1])
printf("%3d. ", (vds->vds_modinfo[1] & 0xff));
else
printf(" ");
printf(" ");
break;
case VDMAGIC_SYS:
printf(" %3d ",
(vds->vds_modinfo[0] & 0xff));
break;
default:
printf(" ");
}
vds->vds_modname[VDMAXNAMELEN - 1] = '\0';
printf("%s\n",vds->vds_modname);
}
#include <varargs.h>
/* VARARGS */
usage(va_alist)
va_dcl
{
va_list args;
char *fmt;
va_start(args);
fmt = va_arg(args, char *);
(void)vfprintf(stderr, fmt, args);
va_end(args);
(void)fprintf(stderr, "Usage: modstat [-v] [-id <N>]\n");
exit(1);
}

37
usr.etc/mod/modsubr.c Normal file
View File

@@ -0,0 +1,37 @@
/* @(#)modsubr.c 1.1 94/10/31 SMI */
#include <stdio.h>
#include <varargs.h>
extern int errno;
/*VARARGS0*/
void
error(va_alist)
va_dcl
{
va_list args;
char *fmt;
va_start(args);
fmt = va_arg(args, char *);
vfprintf(stderr, fmt, args);
fprintf(stderr, ": ");
perror("");
exit(errno);
}
/*VARARGS0*/
void
fatal(va_alist)
va_dcl
{
va_list args;
char *fmt;
va_start(args);
fmt = va_arg(args, char *);
(void) vfprintf(stderr, fmt, args);
va_end(args);
exit(-1);
}

151
usr.etc/mod/modunload.c Normal file
View File

@@ -0,0 +1,151 @@
/* @(#)modunload.c 1.1 94/10/31 SMI */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <machine/param.h>
#include <sun/vddrv.h>
void error(), fatal();
char *execfile = NULL;
struct vdioctl_unload vdiunload;
/*
* Unload a loaded module.
*/
main(argc,argv,envp)
int argc;
char *argv[];
char *envp[];
{
int child, fd;
union wait status;
getargs(argc, argv); /* get arguments */
/*
* Open the pseudo driver.
*/
if ((fd = open("/dev/vd",2)) < 0)
error("can't open /dev/vd");
if (execfile) {
child = fork();
if (child == -1)
error("can't fork %s", execfile);
else if (child == 0)
exec_userfile(fd, envp);
else {
wait(&status);
if (status.w_retcode != 0) {
printf("%s returned error %d.\n",
execfile, status.w_retcode);
exit((int)status.w_retcode);
}
}
}
/*
* issue an ioctl to unload the module.
*/
if (ioctl(fd, VDUNLOAD, &vdiunload) < 0)
if (errno == EPERM)
fatal("You must be superuser to unload a module\n");
else
error("can't unload the module");
exit(0); /* success */
}
/*
* Get user arguments.
*/
getargs(argc, argv)
int argc;
char *argv[];
{
char *ap;
if (argc < 3)
usage();
argc--; /* skip program name */
argv++;
while (argc--) {
ap = *argv++; /* point at next option */
if (*ap++ == '-') {
if (strcmp(ap,"id") == 0) {
if (--argc < 0)
usage();
if (sscanf(*argv++,"%d",&vdiunload.vdi_id) != 1)
usage();
} else if (strcmp(ap,"exec") == 0) {
if (--argc < 0)
usage();
execfile = *argv++;
} else
usage();
} else {
usage();
}
}
}
usage()
{
fatal("usage: modunload -id <module_id> [-exec <exec_file>]\n");
}
/*
* exec the user file.
*/
exec_userfile(fd, envp)
int fd;
char **envp;
{
struct vdioctl_stat vdistat;
struct vdstat vdstat;
char id[8];
char magic[16];
char blockmajor[8];
char charmajor[8];
char sysnum[8];
vdistat.vdi_id = vdiunload.vdi_id; /* copy module id */
vdistat.vdi_vdstat = &vdstat; /* status buffer */
vdistat.vdi_vdstatsize = sizeof(struct vdstat); /* buf size */
if (ioctl(fd, VDSTAT, &vdistat) < 0)
error("can't get module status");
sprintf(id, "%d", vdstat.vds_id);
sprintf(magic, "%x", vdstat.vds_magic);
if (vdstat.vds_magic == VDMAGIC_DRV ||
vdstat.vds_magic == VDMAGIC_MBDRV ||
vdstat.vds_magic == VDMAGIC_PSEUDO) {
sprintf(blockmajor, "%d", vdstat.vds_modinfo[0] & 0xff);
sprintf(charmajor, "%d", vdstat.vds_modinfo[1] & 0xff);
execle(execfile, execfile, id, magic, blockmajor,
charmajor, (char *)0, envp);
} else if (vdstat.vds_magic == VDMAGIC_SYS) {
sprintf(sysnum, "%d", vdstat.vds_modinfo[0] & 0xff);
execle(execfile, execfile, id, magic, sysnum, (char *)0, envp);
} else
execle(execfile, execfile, id, magic, (char *)0, envp);
error("couldn't exec %s\n", execfile);
}