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

2711 lines
66 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
#ident "$Revision: 2.129 $"
#include "tune.h"
#include <a.out.h>
#include <ar.h>
#include <elf.h>
#include <sys/types.h>
#include <sys/param.h>
#include <syslog.h>
#include <sys/sysmacros.h>
#define vme_intrs kernel_vme_intrs
#define iospace kernel_iospace
#define edt kernel_edt
#include <sys/edt.h>
#include <sys/vmereg.h>
#include <sys/conf.h>
#include <limits.h>
#undef vme_intrs
#undef iospace
#undef edt
#include "lboot.h"
#include "boothdr.h"
static char kernel_object[1024]; /* kernel.o */
#define UNKNOWN_FMT 1
#define COFF_FMT 2
#define ELFO32_FMT 3
#define ELFN32_FMT 4
#define ELF64_FMT 5
static char *format_names[] = {
"unknown",
"COFF",
"ELF O32",
"ELF N32",
"64-bit ELF"
};
#define FORMAT_NAME(fmt) (format_names[(fmt)-1])
#define LOAD_RESERVE -1 /* reserve this position in major table
for a loadable driver*/
static void generate(FILE *), edt_gen(FILE *);
#ifdef NEVER
static void devflags_print(FILE *, uint);
#endif
static void load_value_for_object(char *, void *, void *, void *);
extern char any_error; /* any error seen in master.d */
extern void warn(char *, ...);
struct kernel kernel; /* head of object file linked list */
struct driver *driver; /* head of struct driver linked list */
extern char *mtune_kernel; /* mtune/kernel file name */
static int number_drivers; /* total # of drivers to be loaded */
static int got_init, got_halt, got_start, got_reg, got_unreg, got_sanity;
struct rtname {
char *name;
char *routine;
} rtname[] = {
/* functions defined in the UNIX kernel */
/* these must be in one-to-one correspondence with RNULL,RNOSYS,... */
/* [RNOTHING]*/ { "", "{ }" },
/* [RNULL] */ { "nulldev", "{ return(nulldev());}" },
/* [RNOSYS] */ { "nosys", "{ return(nosys());}" },
/* [RNODEV] */ { "nodev", "{ return(nodev());}" },
/* [RTRUE] */ { "true", "{ return(1);}" },
/* [RFALSE] */ { "false", "{ return(0);}" },
/* [RFSNULL]*/ { "fsnull", "{ return(fsnull());}" },
/* [RFSSTRAY]*/ { "fsstray", "{ return(fsstray());}" },
/* [RNOPKG]*/ { "nopkg", "{ return(nopkg());}" },
/* [RNOREACH]*/ { "noreach", "{ noreach(); }" },
/* [RNODEVFLAG]*/{ "nodevflag", "{ }" },
/* [RZERO]*/ { "0", "{ }" },
{ 0, 0 }
};
char Nzero[] = "0";
char Nnofile[] = "nofile";
/*
* private copies of variables that will be generated for UNIX
*/
int cdevcnt;
int bdevcnt;
int fmodcnt;
int nfstype;
char *bootrootfile = NULL;
char *bootswapfile = NULL;
char *bootdumpfile = NULL;
dev_t rootdev = NODEV;
dev_t swapdev = NODEV;
dev_t dumpdev = NODEV;
daddr_t swplo = -1;
int nswap = -1;
int system_version = -1;
int noprobe; /* set means this is a ship kernel */
extern int nointr_count;
extern cpuid_t nointr_list[]; /* CPUs that shouldn't take intrs */
char cpuipl[MAXIPL] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
/*
* structures used to generate io subsystem code
*/
struct Bdevsw {
char *d_prefix;
char *d_flags;
int d_cpulock;
char *d_open;
char *d_close;
char *d_strategy;
char *d_print;
char *d_map;
char *d_unmap;
char *d_dump;
char *d_size;
char *d_size64;
char *d_bdevsw;
};
struct Cdevsw {
char *d_prefix;
char *d_flags;
int d_cpulock;
char *d_open;
char *d_close;
char *d_read;
char *d_write;
char *d_ioctl;
char *d_mmap;
char *d_map;
char *d_unmap;
char *d_poll;
char *d_attach;
char *d_detach;
char *d_enable;
char *d_disable;
char *d_ttys;
char *d_str;
char *d_cdevsw;
};
struct Fmodsw {
char *f_name;
char *f_strmtab;
char *f_flags;
};
struct Vfssw {
char *vfs_name;
char *vfs_init;
char *vfs_vfsops;
char *vfs_vnodeops;
char *vfs_dying_vnodeops;
long vfs_flag;
};
struct Bdevsw *bdevswp;
struct Cdevsw *cdevswp;
int Major[NMAJORS];
struct Fmodsw *fmodswp;
struct Vfssw *vfsswp;
char **io_init;
char **next_init;
char **io_start;
char **next_start;
char **io_reg;
char **next_reg;
char **io_unreg;
char **next_unreg;
char **io_halt;
char **next_halt;
/*
* Static function declarations for this file
*/
static void build_io_subsys(FILE *);
static void dependency(register struct driver *);
static char *dependld(register struct driver *, char *);
static struct driver *finddriver(char *);
static void print_configuration(void);
static void edt_gen(register FILE *);
static void print_configuration(void);
static void dump_source(struct driver *dp, FILE *file);
static void initialize_subsys(void);
static void load_values(struct driver *);
static void generate(register FILE *);
static int get_ar_fmt(int);
static int driver_matches_kernel(struct driver *);
/*
* finddriver()
*
* Search the master directory for master file "name".
*/
static struct driver *
finddriver (char *name)
{
register struct master *mp;
struct driver *dp;
register size_t i;
int fd = -1;
char *tmpstr;
struct stat statbuf;
dp = NULL;
mp = NULL;
dp = (struct driver*)mymalloc(sizeof(struct driver));
dp->flag = 0;
dp->nctl = 0;
dp->edtp = 0;
dp->mname = (char *)NULL;
dp->dname = (char *)NULL;
dp->magic = 0;
if ((dp->opthdr = mp = mkboot(name)) == 0) {
goto badriver;
}
strcpy(mp->name, name);
/*
* SARAH: See comments in mkboot.y. We currently parse the alias
* strings from a master file, if they exist, and place the info
* in the master structure, but don't use this information yet.
* The following code is here for debugging to make sure that
* strings were added.
*/
#ifdef NOTYET
if (mp->naliases) {
register struct alias *al;
register char *sp;
al = (struct alias *) POINTER(mp->o_alias, mp);
for (i=0; i<mp->naliases; i++, al++) {
sp=POINTER(al->str,mp);
printf ("load_value_for_object sp=%s\n", sp);
}
}
#endif
if (mp->flag & KOBJECT)
/*
* ignore kernel objects
*/
goto badriver;
for (i=0; i<mp->nsoft; i++) {
if (mp->soft[i] >= NMAJORS) {
/* Driver <name>: major number greater than NMAJORS */
error(ER13, name);
goto badriver;
}
}
dp->mname = mymalloc( strlen(name) + 1 );
strcpy(dp->mname,name);
/*
* see if we have an object associated with the master
*/
i = strlen(name);
dp->dname = mymalloc(i + 3);
(void) strcat(strcpy(dp->dname,name),".o");
if (stat(dp->dname,&statbuf) == -1) {
dp->dname[i+1] = 'a';
if (stat(dp->dname,&statbuf) == -1) {
free(dp->dname);
dp->dname = (char *) NULL;
goto nodriver;
}
} else {
tmpstr = mymalloc(i + 3);
(void) strcat(strcpy(tmpstr,name),".a");
if (stat(tmpstr,&statbuf) == 0) {
printf ("WARNING: lboot found both %s and %s in the boot directory\n",
dp->dname, tmpstr);
syslog (LOG_WARNING,
"WARNING found both %s and %s in the boot directory\n",
dp->dname, tmpstr);
}
free (tmpstr);
}
if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
goto badriver;
}
nodriver:
/*
* master is OK
*/
dp->next = driver;
driver = dp;
return(dp);
badriver:
if (mp)
free((char*)mp);
if (dp->mname)
free(dp->mname);
if (dp->dname)
free(dp->dname);
if (dp)
free((char*)dp);
if (fd != -1) {
(void) close(fd);
fd = -1;
}
return((struct driver *)0);
}
/*
* Print_configuration()
*
* Print the configuration table; this is only done if Debug is set
*/
static void
print_configuration(void)
{
struct driver *dp;
struct master *mp;
boolean issued;
int i;
printf("\nCONFIGURATION SUMMARY\n=====================\n ----driver---- #devices,imajor,emajor\n");
/*
* handle drivers
*/
for (dp = driver; dp != 0; dp = dp->next) {
if (! (dp->flag & LOAD) ||
((mp=dp->opthdr)->flag & NOTADRV))
continue;
if ((mp->flag & (CHAR|BLOCK|FUNMOD|FUNDRV)) == FUNMOD)
continue;
printf(" %15s %d,%d", dp->mname, dp->nctl, dp->int_major);
if (! (mp->flag & (BLOCK|CHAR|FUNDRV)))
printf("\n");
else {
for (i=0; i<mp->nsoft; i++)
printf(",%d", mp->soft[i]);
printf ("\n");
}
}
/*
* handle modules
*/
issued = FALSE;
for (dp = driver; dp != 0; dp = dp->next) {
mp = dp->opthdr;
if (!(dp->flag & LOAD) ||
!(mp->flag & (NOTADRV | FUNMOD)))
continue;
if (! issued) {
/*
* print heading for first module found
*/
issued = TRUE;
printf("\n ----module----\n");
}
printf(" %s\n", dp->mname);
}
printf("\n");
}
/*
* searchdriver(name)
*
* Search the driver linked-list to locate driver `name'; when found, return
* the pointer to the struct driver entry; if not found return NULL.
*/
struct driver *
searchdriver(char *name)
{
register struct driver *dp;
for (dp = driver; dp != 0; dp = dp->next) {
if (EQUAL(dp->mname,name))
return(dp);
}
return(finddriver(name));
}
/*
* Include(dname, number)
*
* Mark driver `dname' to be included for `number' more controllers.
*
* If the driver was found in the EDT, then `number' is ignored since the
* number of controllers is already determined. Likewise, if the driver
* is a required driver, then the number of controllers must be set to one,
* so `number' is ignored.
*
* If the driver was not found in the EDT, then it cannot be included
* unless it is a software driver, or it is just an independent module.
*/
void
include(register char *dname, int number)
{
register struct driver *dp;
register struct master *mp;
if ((dp=searchdriver(dname)) == NULL)
/* INCLUDE: <dname>; driver not found */
error(ER18, dname);
else {
if (dp->flag & EXCLUDE) {
/* INCLUDE: <dname>; driver is EXCLUDED */
error(ER19, dname);
return;
}
if (dp->flag & INEDT) {
/*
* it will be included based on number of times in EDT
*/
dp->flag |= INCLUDE;
return;
}
mp = dp->opthdr;
if (mp->flag & STUB)
dp->flag |= LOADLAST;
if (mp->flag & (NOTADRV | FUNMOD)) {
dp->flag |= INCLUDE;
dp->nctl += number;
return;
}
if (mp->flag & SOFT) {
dp->flag |= INCLUDE;
if (! (mp->flag & REQ))
dp->nctl += number;
} else
/* INCLUDE: <dname>; device not equipped */
error(ER20, dname);
}
}
/*
* Exclude(dname)
*
* Mark driver `dname' to be excluded
*/
void
exclude(register char *dname)
{
register struct driver *dp;
dp=searchdriver(dname);
if (dp != 0) {
if (dp->flag & INCLUDE)
/* EXCLUDE: <dname>; driver is INCLUDED */
error(ER21, dname);
else
dp->flag |= EXCLUDE;
}
}
/*
* Dependency(pdriver)
*
* Driver *pdriver has dependencies. Find them in the driver linked-list, mark
* them to be loaded, and follow their dependencies.
*/
static void
dependency(register struct driver *pdriver)
{
struct driver *dp;
struct master *m, *mp = pdriver->opthdr;
struct depend *dep;
int count;
char name[MAXNAMLEN+3];
dep = (struct depend*) POINTER(mp->o_depend, mp);
for (count=0; count<mp->ndep; ++count, ++dep) {
dp=searchdriver(strcpy(name,(char *)POINTER(dep->name,mp)));
/* <pdriver->name>: dependent driver <name> not available */
if (dp==(struct driver *)NULL) {
error(ER22, pdriver->mname, name);
continue;
}
if (dp->flag & LOAD)
/*
* already marked to be loaded
*/
continue;
/* <pdriver->name>: dependent driver <name> is EXCLUDED */
if (dp->flag & EXCLUDE) {
error(ER23, pdriver->mname, name);
continue;
}
m = dp->opthdr;
if (!((m->flag & (SOFT|NOTADRV)) ||
((m->flag & (CHAR | BLOCK | FUNMOD | FUNDRV)) == FUNMOD)) &&
!(dp->flag & INEDT)) {
/*
* driver is not a software driver (ie. it is a
* hardware driver) but the hardware does not exist
*
* <pdriver->name>: device not equipped for dependent driver <name>
*/
error(ER24, pdriver->mname, name);
continue;
}
/* Check if object format matches kernel */
if (!driver_matches_kernel(dp))
continue;
dp->flag |= LOAD;
if (m->ndep > 0)
/*
* follow the dependency chain
*/
dependency(dp);
if ((m->flag & (SOFT|NOTADRV) ||
((m->flag & (CHAR | BLOCK | FUNMOD | FUNDRV)) == FUNMOD)) &&
! (dp->flag & INEDT) && dp->nctl == 0)
/*
* make sure that #C is set if not done already
*/
dp->nctl = 1;
}
}
/*
* dependld(pdriver)
*
* Driver *pdriver has dependencies. Find them and if they are .a's
* add them to the passed in list..
*/
static char *
dependld(register struct driver *pdriver, char *ldopt)
{
struct driver *dp;
struct master *mp = pdriver->opthdr;
struct depend *dep;
int count;
char name[MAXNAMLEN+3];
dep = (struct depend*) POINTER(mp->o_depend, mp);
for (count=0; count<mp->ndep; ++count, ++dep) {
dp=searchdriver(strcpy(name,(char *)POINTER(dep->name,mp)));
/* <pdriver->name>: dependent driver <name> not available */
if (dp==(struct driver *)NULL) {
error(ER22, pdriver->mname, name);
continue;
}
/* only interested if these are marked to be loaded */
if (!(dp->flag & LOAD))
continue;
if (dp->dname != 0 && suffix(dp->dname, "a")) {
ldopt = concat_free(ldopt, dp->dname);
ldopt = concat_free(ldopt, " ");
}
/*
* XXX don't follow dependencies since there are lots
* of loops in the dependency tree...
*/
#ifdef NEVER
if (dp->opthdr->ndep > 0)
/*
* follow the dependency chain
*/
ldopt = dependld(dp, ldopt);
#endif
}
return ldopt;
}
/*
* Given a filename, determine if its a loadable module or not.
*
* NOTE: this routine assumes that the driver list has already been
* created.
*/
static int
isloadable (char *fname)
{
struct driver *dp;
char tmpname[MAXNAMELEN];
if (strlen(fname) < 3) /* the file better have a .o extension */
return 0;
strncpy (tmpname, fname, (strlen(fname) - 2));
tmpname[strlen(fname) - 2] = '\0';
dp = driver;
while (dp) {
if (strcmp (dp->mname, tmpname) == 0)
if (dp->opthdr->flag & DYNAMIC)
return 1;
dp = dp->next;
}
return 0;
}
/*
* This routine links the objects specified by the system list
*/
void
loadunix(void)
{
register struct driver *dp, *dpp = NULL;
register struct master *mp;
int i, j;
register int fd;
register FILE *stream;
int b_major, c_major, bc_major;
union commonhdr {
FILHDR fhdr;
Elf32_Ehdr elfhdr;
char armag[SARMAG];
} commonhdr;
struct stat statbuf;
register FILE *nfdot;
char master_dot_c[MAXPATHLEN+14];
char master_dot_o[MAXPATHLEN+14];
char new_edt_dot[MAXPATHLEN+14];
char old_edt_dot[MAXPATHLEN+14];
char reason[MAXPATHLEN+14+MAXPATHLEN+14+10];
char *cc_cmd, *ld_cmd, *tmpdir;
register int c1, c2;
register FILE *olds;
register DIR *dirp;
register struct dirent *dep;
struct stat nsb, osb;
int relink;
time_t lmtime; /* largest mtime */
lmtime = 0;
cdevcnt = bdevcnt = fmodcnt = nfstype = 0;
openlog("lboot", LOG_ODELAY, LOG_AUTH);
/*
* Parse the system file. Quit if it is bad.
*
* If we fail and need to exit somewhere w/i the path
* through parse_system(), enable switch to print some
* warnings to user about possible incomplete autoregistration.
*/
do_mreg_diags = 1;
if (0 != parse_system()) {
myexit(1);
}
do_mreg_diags = 0;
for (i=0; i< NMAJORS; ++i)
Major[i] = DONTCARE;
/*
* Register all loadable modules requested for pre-registration.
*/
if (Smart & !Noautoreg)
do_mregister ();
if (Autoreg) {
printf ("Warning: lboot using -a - performing auto-register only\n");
do_mregister ();
exit(0);
}
/*
* save EDT structures
*/
(void) sprintf(old_edt_dot, "%s/edt.list", slash_runtime);
(void) sprintf(new_edt_dot, "%s/edt.list.new", slash_runtime);
stream = fopen(new_edt_dot, "w");
if (stream != 0) {
edt_gen(stream);
(void)fclose(stream);
}
if (Smart) {
if (Nogo && Verbose)
printf ("\nPerforming dry run to determine if a new kernel should be built...\n");
relink = 0;
if (0 == stream) {
sprintf (reason, "fopen %s failed", new_edt_dot);
relink = 1;
}
if (!relink && 0 != stat(unix_name, &statbuf)) {
sprintf (reason, "stat %s failed", unix_name);
relink = 1;
}
}
/* we go through the files in var/sysgen even if we're
* not Smart in case any is timestamped in the future.
* if that's the case, we'll timestamp unix in the future
* too
*/
/* if master.d/x is newer than unix, reconfig */
if (0 != (dirp = opendir(master_dot_d))) {
(void)chdir(master_dot_d);
while (0 != (dep = readdir(dirp))) {
if (dep->d_ino != 0
&& stat(dep->d_name, &nsb) == 0
&& (nsb.st_mode & S_IFMT) == S_IFREG
&& statbuf.st_mtime < nsb.st_mtime) {
if (nsb.st_mtime > lmtime)
lmtime = nsb.st_mtime;
if (!Smart || relink) /* already have reason */
continue;
relink = 1;
sprintf (reason, "%s/%s newer than %s",
master_dot_d, dep->d_name,
unix_name);
}
}
(void)chdir(slash_boot);
(void)closedir(dirp);
}
/* if boot/x is newer than unix, reconfig */
if (0 != (dirp = opendir("."))) {
while (0 != (dep = readdir(dirp))) {
if (dep->d_ino != 0
&& 0 != strcmp(dep->d_name, "edt.list.new")
&& stat(dep->d_name, &nsb) == 0
&& (nsb.st_mode & S_IFMT) == S_IFREG
&& statbuf.st_mtime < nsb.st_mtime) {
/*
* If its a loadable module, don't
* reconfig for it.
*/
if (isloadable(dep->d_name))
continue;
if (nsb.st_mtime > lmtime)
lmtime = nsb.st_mtime;
if (!Smart || relink)
continue;
relink = 1;
sprintf (reason, "%s/%s newer than %s",
slash_boot, dep->d_name,
unix_name);
}
}
(void)closedir(dirp);
}
/* if /var/sysgen/stune is missing or newer than unix, reconfig */
if (stat(stune_file, &nsb) < 0){
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s is missing", stune_file);
}
} else if (statbuf.st_mtime < nsb.st_mtime) {
if (nsb.st_mtime > lmtime)
lmtime = nsb.st_mtime;
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s is newer than %s", stune_file,
unix_name);
}
}
/* if /var/sysgen/boot is missing or newer than unix, reconfig */
if (stat(slash_boot, &nsb) < 0){
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s is missing", slash_boot);
}
} else if (statbuf.st_mtime < nsb.st_mtime) {
if (nsb.st_mtime > lmtime)
lmtime = nsb.st_mtime;
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s is newer than %s", slash_boot, unix_name);
}
}
/* if /var/sysgen/system/x is newer than unix, reconfig */
if (stat(etcsystem, &nsb) < 0) {
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s stat failed", etcsystem);
}
}
else if (S_ISDIR(nsb.st_mode)) {
int i, nentries;
char system_path[PATH_MAX];
struct dirent **systems;
if ((nentries = scandir(etcsystem, &systems, sys_select, alphasort)) < 0) {
if (Smart && !relink) {
relink = 1;
sprintf (reason, "scandir %d failed", etcsystem);
}
}
else {
for (i = 0; i < nentries; i++) {
strcpy(system_path, etcsystem);
strcat(system_path, "/");
strcat(system_path, systems[i]->d_name);
if ((stat(system_path, &nsb) < 0) ||
statbuf.st_mtime < nsb.st_mtime) {
if (nsb.st_mtime > lmtime)
lmtime = nsb.st_mtime;
if (!Smart || relink)
continue;
relink = 1;
sprintf (reason, "%s is newer than %s",
system_path, unix_name);
}
free(systems[i]);
}
free(systems);
}
} else {
if (Smart && !relink) {
relink = 1;
sprintf (reason, "%s is not a directory",
etcsystem);
}
}
if (Smart) {
/* if the edt files seem similar, do a slow but easy comparison */
olds = stream = NULL;
if (!relink
&& (olds = fopen(old_edt_dot, "r")) != 0
&& fstat(fileno(olds), &osb) >= 0
&& (stream = fopen(new_edt_dot, "r")) != 0
&& fstat(fileno(stream), &nsb) >= 0
&& osb.st_size == nsb.st_size) {
for (;;) {
i = getc(olds);
if (i != getc(stream)) {
relink = 1;
sprintf (reason, "%s and %s differ",
old_edt_dot, new_edt_dot);
break;
}
if (i == EOF) {
if (statbuf.st_mtime > time(0)) {
syslog(LOG_WARNING, "WARNING: kernel seems current but has a modification time in the future");
fprintf(stderr, "lboot: WARNING: kernel seems current but has a modification time in the future\n");
}
if (Verbose)
printf("kernel already current\n");
(void)unlink(new_edt_dot);
exit(0);
}
}
} else {
if (!relink) {
relink = 1;
sprintf (reason, "%s and %s differ",
old_edt_dot, new_edt_dot);
}
}
if (stream)
(void)fclose(stream);
if (olds)
(void)fclose(olds);
if (Nogo) {
printf ("New kernel would have been built: %s.\n",
reason);
(void)unlink(new_edt_dot);
exit(1);
}
/*
* Autoconfig is 1 by default, which means just go ahead and
* do the autoconfig. This can be overridden by the
* autoconfig.options file, in which case the Auto question
* will be asked.
*/
if (!Autoconfig) {
if (Verbose)
printf ("\n%s...\n", reason);
printf("Automatically reconfigure the operating system (y or n)? ");
c1 = c2 = getchar();
while (c2 != EOF && c2 != '\n')
c2 = getchar();
if (c1 != 'y' && c1 != 'Y') {
(void)unlink(new_edt_dot);
exit(1);
}
} else {
if (Verbose)
printf ("\n%s...\n", reason);
printf ("Automatically reconfiguring the operating system.\n");
syslog (LOG_NOTICE,
"Automatically reconfiguring the operating system");
}
}
/*
* open the kernel object file, and do sanity checks
*/
if (!kernel_master)
error(ER101, etcsystem);
strcat(strcpy(kernel_object,kernel_master),".o");
if (stat(kernel_object,&statbuf) < 0
|| (fd=open(kernel_object,O_RDONLY)) < 0)
error(ER2, kernel_object);
/*
* Read file header and verify it.
*/
read_and_check(fd, kernel_object, (char*)&commonhdr, sizeof(commonhdr));
(void)close(fd);
if (!IS_ELF(commonhdr.elfhdr) &&
!IS_MIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_MIPSELMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSELMAGIC(commonhdr.fhdr.f_magic)) {
/* <kernel_object>: not an object file */
error(ER32, kernel_object);
}
if (IS_ELF(commonhdr.elfhdr)) {
/* Determine ABI of kernel.o */
if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS64)
kernel.magic = ELF64_FMT;
else if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS32) {
if (commonhdr.elfhdr.e_flags & EF_MIPS_ABI2)
kernel.magic = ELFN32_FMT;
else
kernel.magic = ELFO32_FMT;
}
}
else
kernel.magic = COFF_FMT;
kernel.mname = kernel_master;
kernel.dname = kernel_object;
kernel.next = driver;
if ((driver == NULL) || (driver->next == driver))
error(ER1, "no driver linked-list was built");
/*
* make sure we have everything we need
*/
if (bootrootfile == NULL)
error(ER1, "no ROOTDEV specified in system file");
/*
* Determine all drivers to be loaded. We compare object
* file types here with the base kernel module to make sure
* that everything is in sync. If for some reason we have
* an entry in this list that is bogus, then we remove and
* free up the memory.
*/
for (dp = driver; dp; dpp = dp, dp = dp->next) {
/* Skip driver if we've already decided it is the wrong format */
if (dp->magic !=0 && !dp->dname)
continue;
/*
* If dp->magic is 0, we need to assign it now. This
* is rather expensive, but we have no choice.
*/
if (dp->magic == 0 && dp->dname) {
if ((fd = open(dp->dname, O_RDONLY)) == -1) {
/* <name>: perror() message */
error(ER7, dp->dname);
if (dp == driver)
driver = dp->next;
else
dpp->next = dp->next;
if (dp->opthdr)
free((char*)dp->opthdr);
if (dp->mname)
free(dp->mname);
if (dp->dname)
free(dp->dname);
if (dp)
free((char*)dp);
if (fd == -1)
(void) close(fd);
continue;
}
read_and_check(fd, dp->dname, (char *)&commonhdr,
sizeof (commonhdr));
if (!IS_ELF(commonhdr.elfhdr) &&
!IS_MIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_MIPSELMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSELMAGIC(commonhdr.fhdr.f_magic) &&
(memcmp(&commonhdr.armag, ARMAG, SARMAG))) {
/* Driver <name>: not a valid object file */
error(ER15, dp->dname);
if (dp == driver)
driver = dp->next;
else
dpp->next = dp->next;
if (dp->opthdr)
free((char*)dp->opthdr);
if (dp->mname)
free(dp->mname);
if (dp->dname)
free(dp->dname);
if (dp)
free((char*)dp);
close(fd);
continue;
}
if (IS_ELF(commonhdr.elfhdr)) {
if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS64)
dp->magic = ELF64_FMT;
else if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS32) {
if (commonhdr.elfhdr.e_flags & EF_MIPS_ABI2)
dp->magic = ELFN32_FMT;
else
dp->magic = ELFO32_FMT;
}
}
else if (memcmp(&commonhdr.armag, ARMAG, SARMAG) == 0)
dp->magic = get_ar_fmt(fd);
else
dp->magic = COFF_FMT;
close(fd);
/*
* Magic number test. The object format of dp must
* match that of kernel.
*/
if (dp->magic != kernel.magic) {
/* Driver <name>: <driver_format> object is incompatible with <kernel_format> kernel; object ignored */
error(ER16, dp->dname, FORMAT_NAME(dp->magic), FORMAT_NAME(kernel.magic));
syslog (LOG_WARNING,
"WARNING %s: object file not in ELF format; object ignored\n",
dp->dname);
free(dp->dname);
dp->dname = NULL;
dp->flag &= ~LOAD;
continue;
}
}
if ((mp=dp->opthdr)->flag & REQ) {
if (dp->flag & EXCLUDE) {
/* <dp->mname>: required driver is EXCLUDED */
error(ER36, dp->mname);
continue;
}
dp->flag |= LOAD;
dp->nctl = 1;
}
if (dp->flag & EXCLUDE)
continue;
if (dp->flag & INEDT)
dp->flag |= LOAD;
if (dp->flag & INCLUDE)
dp->flag |= LOAD;
if ((dp->flag & LOAD) && mp->ndep > 0)
dependency(dp);
if ((mp->flag & DYNAMIC) && !Dolink) {
dp->flag |= DYNLOAD;
dp->flag &= ~LOAD;
}
}
/*
* If a loadable driver specifies its major number, we need to
* temporarily set that slot aside in the MAJOR table.
*/
dp = driver;
while (dp) {
if ((dp->dname) && (dp->opthdr->flag & DYNAMIC) &&
(dp->opthdr->flag & DYNREG) &&
(dp->opthdr->soft[0] != DONTCARE))
for (i=0; i<dp->opthdr->nsoft; i++)
Major[dp->opthdr->soft[i]] = LOAD_RESERVE;
dp = dp->next;
}
/*
* Assign the internal major numbers. This is a two pass approach,
* first the drivers which are both BLOCK and CHAR are assigned numbers
* then the remaining drivers are assigned. This will minimize the size
* of the character and block device switch tables. Also count the
* number of cdevs and bdevs here.
*/
bc_major = 0;
for (i=0; i<2; ++i) {
b_major = c_major = bc_major;
dp = driver;
do {
if (! (dp->flag & LOAD))
continue;
mp = dp->opthdr;
if (!(mp->flag & (BLOCK|CHAR|FUNDRV))) /* SOFT? */
continue;
if (i == 0) {
if ((mp->flag & (BLOCK|CHAR)) == (BLOCK|CHAR)) {
dp->int_major = bc_major++;
cdevcnt++;
bdevcnt++;
} else {
continue;
}
} else {
if ((mp->flag & (BLOCK|CHAR)) == BLOCK) {
dp->int_major = b_major++;
bdevcnt++;
} else {
if ((mp->flag & (BLOCK|CHAR)) == CHAR
|| mp->flag & FUNDRV) {
dp->int_major = c_major++;
cdevcnt++;
} else
continue;
}
}
/*
* Assign internal major number to external major
* numbers. There can be multiple external major
* numbers, but they all map to one internal number.
* This is the case where there are multiple major
* numbers specified in one master file.
*/
for (j=0; j<mp->nsoft; j++) {
if (mp->soft[j] != DONTCARE) {
if (Major[mp->soft[j]] != DONTCARE &&
Major[mp->soft[j]] != LOAD_RESERVE)
fprintf(stderr,
"Warning: major number collision -- %d\n", mp->soft[j]);
Major[mp->soft[j]] = dp->int_major;
}
}
} while (dp = dp->next);
}
dp = driver;
for (i=0; i< NMAJORS; ++i)
if (Major[i] == LOAD_RESERVE)
Major[i] = DONTCARE;
/*
* Compute fmodcnt; also count the total number of drivers
* to be loaded, and interrupt routines that will be needed.
*/
dp = driver;
do {
if (!(dp->flag & LOAD))
continue;
++number_drivers;
if ((mp=dp->opthdr)->flag & ONCE && dp->nctl != 1) {
/* <dp->mname>: flagged as ONCE only; #C set to 1 */
error(ER37, dp->mname);
dp->nctl = 1;
}
if (mp->flag & FSTYP) {
++nfstype;
}
if (mp->flag & NOTADRV)
continue;
if (mp->flag & FUNMOD) {
++fmodcnt;
if (!(mp->flag & (CHAR | BLOCK | FUNDRV)))
continue;
}
} while (dp = dp->next);
++nfstype;
/*
* Print configuration table
*/
if (Debug)
print_configuration();
/*
* build the "master.c" file -- this defines all constants
* and will instantiate all extern structures.
*/
(void) sprintf(master_dot_c, "%s/master.c", slash_runtime);
if (tmpdir = getenv("TMPDIR"))
(void) sprintf(master_dot_o, "%s/master%d.o", tmpdir,
getpid());
else
(void) sprintf(master_dot_o, "/tmp/master%d.o", getpid());
(void)unlink(master_dot_c);
if ((nfdot=fopen(master_dot_c,"w")) == (FILE *)NULL)
error(ER2, master_dot_c);
/* if -Iroot/usr/include, doesn't come last, then people working
* with their own trees (like many developers) can get mucked up
* because their changed .h files haven't yet (if they ever will
* be) copied to the root/usr/include tree (and they won't be
* able to override the /usr/include tree without resorting to
* full pathnames). Olson, 4/89 */
if (0 == cc)
cc = concat(toolpath, "cc");
if (noprobe)
ccopts = concat_free(ccopts, "-DNOPROBE ");
if (!ccopts) {
error(ER122, "CCOPTS");
ccopts = "";
}
cc_cmd = mymalloc(64+strlen(cc)+strlen(root)+strlen(ccopts)
+strlen(slash_boot)+strlen(master_dot_c)+strlen(master_dot_o));
sprintf(cc_cmd, "%s -c -I %s -I%s/usr/include -I%s %s -o %s",
cc, ccopts, root, slash_boot,master_dot_c, master_dot_o);
fprintf(nfdot,"\n\n/*** DO NOT EDIT THIS FILE - THIS FILE IS GENERATED BY LBOOT ***/\n\n");
dump_source((struct driver *)&kernel, nfdot);
gen_tune((struct driver *)&kernel, mtune_kernel);
for (dp = driver; dp != 0; dp = dp->next) {
if (dp->flag & (LOAD|DYNLOAD)) {
dump_source(dp, nfdot);
gen_tune(dp, (char *)0);
}
}
rdstune();
if (0 == ld)
ld = concat(toolpath, "ld");
if (0 == ldopts)
error(ER122, "LDOPTS");
ld_cmd = concat(ld, " ");
ld_cmd = concat_free(ld_cmd, ldopts);
ld_cmd = concat_free(ld_cmd, " ");
ld_cmd = concat_free(ld_cmd, kernel.dname);
ld_cmd = concat_free(ld_cmd, " ");
ld_cmd = concat_free(ld_cmd, master_dot_o);
ld_cmd = concat_free(ld_cmd, " -o ");
ld_cmd = concat_free(ld_cmd, unix_name);
if (Smart)
ld_cmd = concat_free(ld_cmd, ".install");
ld_cmd = concat_free(ld_cmd, " ");
/*
* Put .o's before .a's ("except after ``c''...")
*/
for (dp = driver; dp != 0; dp = dp->next) {
if (((dp->flag & (LOAD|LOADLAST)) == LOAD)
&& dp->dname != 0
&& suffix(dp->dname, "o")) {
ld_cmd = concat_free(ld_cmd, dp->dname);
ld_cmd = concat_free(ld_cmd, " ");
}
}
for (dp = driver; dp != 0; dp = dp->next) {
if (((dp->flag & (LOAD|LOADLAST)) == LOAD)
&& dp->dname != 0
&& suffix(dp->dname, "a")) {
ld_cmd = concat_free(ld_cmd, dp->dname);
ld_cmd = concat_free(ld_cmd, " ");
/*
* if this .a has any dependencies that are .a's
* add them AFTER this .a - this does no harm
* but fixes archive dependency problems...
*/
ld_cmd = dependld(dp, ld_cmd);
}
}
/* load stub modules last */
for (dp = driver; dp != 0; dp = dp->next) {
if (((dp->flag & (LOAD|LOADLAST)) == (LOAD|LOADLAST))
&& dp->dname != 0) {
ld_cmd = concat_free(ld_cmd, dp->dname);
ld_cmd = concat_free(ld_cmd, " ");
}
}
/*
* Build all interrupt routines, pcb's,
* kernel data structures for I/O, etc.
*/
build_io_subsys(nfdot);
symbol_scan(((struct driver *)&kernel)->dname, find_kernel_sanity,
(void *)&kernel,
(void *)gfind(kernel.mname),
(void *)NULL);
/* small backward compat - since kernel used to have all of os & ml
* in it, look in os.a as well as kernel for sanity functions
*/
dp = searchdriver("os");
if (dp)
symbol_scan(dp->dname, find_kernel_sanity,
(void *)dp,
(void *)gfind(kernel.mname),
(void *)NULL);
print_tune(nfdot);
fprintf(nfdot,"\n\n/* cc %s */\n", cc_cmd);
fprintf(nfdot,"/* ld %s */\n", ld_cmd);
(void)fclose(nfdot);
/* print the device / driver administration support info table
* in the master.c file
*/
print_dev_admin();
fflush(stderr);
/*
* Compile new master_dot_c...
*/
if (Verbose) {
printf("%s\n", cc_cmd);
fflush(stdout);
}
/*
* Quit if we could not parse any of the master.d files
*/
if (any_error)
exit(1);
/*
* Now compile it.
*/
if ((i=system(cc_cmd)) != 0) {
fprintf(stderr,"lboot: cc returned %d--failed\n", i);
(void)unlink(master_dot_o);
exit(1);
}
/*
* link master_dot_o, kernel_object, all ``loaded'' drivers
*/
if (Verbose) {
printf("%s\n", ld_cmd);
fflush(stdout);
}
if ((i=system(ld_cmd)) != 0) {
printf("lboot: ld returned %d--failed\n", i);
(void)unlink(master_dot_o);
exit(1);
}
if (lmtime) {
/* lmtime is the largest modification time (mtime)
* of any file in /var/sysgen. we just wrote unix
* so if mtime(unix) < lmtime then lmtime must be
* in the future and we set the unix mtime in the
* future as well. this way, autoconfig won't fire
* at every reboot.
*/
struct utimbuf utb;
char *kernel_touch;
kernel_touch = concat(unix_name, (Smart) ? ".install" : "");
if (stat(kernel_touch, &statbuf) == 0) {
if (lmtime > statbuf.st_mtime) {
syslog (LOG_WARNING, "WARNING: there are files in /var/sysgen with mtime in the future");
fprintf (stderr, "lboot: WARNING: there are files in /var/sysgen with mtime in the future\n");
utb.actime = statbuf.st_atime;
utb.modtime = lmtime;
if (utime(kernel_touch, &utb) == 0) {
syslog (LOG_WARNING, "WARNING: setting %s mtime to %s", kernel_touch, ctime(&lmtime));
fprintf (stderr, "lboot: WARNING: setting %s mtime to %s", kernel_touch, ctime(&lmtime));
}
}
}
}
if (Smart) {
printf("\nReboot to start using the reconfigured kernel.\n");
syslog (LOG_NOTICE,
"Reboot to start using the reconfigured kernel");
}
(void)rename(new_edt_dot, old_edt_dot);
(void)unlink(master_dot_o);
exit(0);
}
extern char master_file[]; /* current master file entity */
/*
* dump "parameters" sections of master.d file
*/
static void
dump_source(struct driver *dp, FILE *file)
{
FILE *master;
register c;
char *p;
char sCDM[12];
char line[LSIZE];
int nCDM;
strcpy( master_file, master_dot_d );
strcat( master_file, "/" );
strcat( master_file, dp->mname );
p=strrchr(master_file,'/');
if ( (p=strchr(p,'.')) != NULL )
*p = '\0';
if ((master = fopen(master_file,"r")) == NULL)
error(ER2, master_file);
while ((fgets(line, LSIZE, master)) != NULL) {
if (line[0] == '*')
continue;
if (line[0] == '$')
break;
}
while ((c=getc(master)) != EOF) {
if (c == '#') {
if ((c=getc(master)) == '#') {
switch(c=getc(master)) {
case 'C':
case 'c':
nCDM = dp->nctl;
break;
case 'D':
case 'd':
nCDM = dp->opthdr->ndev;
break;
case 'M':
case 'm':
nCDM = dp->int_major;
break;
case 'E':
case 'e':
nCDM = (int) dp->opthdr->soft[0];
break;
default:
fprintf(stderr,"data initializer ##%c unknown -- using zero\n", c);
nCDM = 0;
break;
}
sprintf(sCDM,"%d",nCDM);
p = sCDM;
while (*p)
(void)putc(*p++,file);
} else {
(void)putc('#',file);
(void)putc(c,file);
}
} else (void)putc(c,file);
}
(void) fclose(master);
}
static void
build_io_subsys(FILE *f)
{
struct driver *dp;
/*
* generate structures and set up default values
*/
initialize_subsys();
dp = driver;
do {
if (! (dp->flag & LOAD))
continue;
/*
* Fill in tables with symbol table values.
* We call load_values even though the object
* might not exist because we have to set up
* driver semaphoring structures.
*/
load_values(dp);
} while (dp = dp->next);
/* sanity check on the cpu intr locking option */
intrlock_sanity_check();
/*
* copy the generated data into the temp file
*/
generate(f);
}
/*
* initialize structures for the i/o subsystem
*/
static void
initialize_subsys(void)
{
register i;
struct Bdevsw *bp;
struct Cdevsw *cp;
struct Fmodsw *fp;
struct Vfssw *vfsp;
bdevswp = (struct Bdevsw *)mymalloc(bdevcnt*sizeof(struct Bdevsw));
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++) {
bp->d_prefix = NULL;
bp->d_open = bp->d_close =
bp->d_strategy = bp->d_print =
bp->d_map = bp->d_unmap =
bp->d_dump = rtname[RNODEV].name;
bp->d_size = bp->d_size64 = rtname[RNULL].name;
bp->d_flags = rtname[RNODEVFLAG].name;
bp->d_bdevsw = NULL;
}
cdevswp = (struct Cdevsw *)mymalloc(cdevcnt*sizeof(struct Cdevsw));
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
cp->d_prefix = NULL;
cp->d_open = cp->d_close = cp->d_map
= cp->d_mmap
= cp->d_unmap = cp->d_read = cp->d_write
= cp->d_ioctl = rtname[RNODEV].name;
cp->d_flags = rtname[RNODEVFLAG].name;
cp->d_poll = cp->d_attach =
cp->d_detach = cp->d_enable =
cp->d_disable = rtname[RNULL].name;
cp->d_ttys = cp->d_str = Nzero;
cp->d_cdevsw = NULL;
}
fmodswp = (struct Fmodsw *)mymalloc(fmodcnt*sizeof(struct Fmodsw));
for (i=0, fp=fmodswp; i<fmodcnt; i++, fp++) {
fp->f_name = Nnofile;
fp->f_strmtab = Nzero;
fp->f_flags = rtname[RNODEVFLAG].name;
}
vfsswp = (struct Vfssw *) mycalloc(nfstype*sizeof(struct Vfssw),1);
vfsp=vfsswp;
vfsp->vfs_name = "BADFS";
vfsp->vfs_vfsops = "vfs_strayops";
vfsp->vfs_vnodeops = "dead_vnodeops";
io_init = next_init = (char **) mycalloc((number_drivers+1)
*(sizeof(io_init)
+sizeof(io_start)
+sizeof(io_reg)
+sizeof(io_unreg)
+sizeof(io_halt)), 1);
io_start = next_start = io_init + (number_drivers+1) ;
io_reg = next_reg = io_start + (number_drivers+1);
io_unreg = next_unreg = io_reg + (number_drivers+1);
io_halt=next_halt=io_unreg + (number_drivers+1);
}
/*
* load_values
*
* Fill in correct values for generated structures
*/
static void
load_values(struct driver *dp)
{
struct master *mp;
register struct Bdevsw *b;
register struct Cdevsw *c;
register struct Vfssw *vfsp;
register struct Fmodsw *fp;
int cpulock;
got_init = got_halt = got_start = got_reg = got_unreg = 0;
mp = dp->opthdr;
b = bdevswp+dp->int_major;
c = cdevswp+dp->int_major;
/*
** for drivers that has edt list, lets go thru. ea edt entry
** and set the flag v_cpuintr based on the set value of IPL.
** If the driver is of processor locking type, then check to make sure
** that the ipl level of all edt entries are locked on the same cpu,
** also set the d_cpulock flag in bdevsw/cdevsw
** The return value of lock_on_cpu() is only useful for
** processor locked drivers
*/
if ((dp->flag & INEDT) || (mp->sema == S_PROC))
/* fig out which cpu to lock to, and error checking */
cpulock = lock_on_cpu(mp, dp);
/*
* We need to know what type of locking the
* driver requires (locking on major number,
* processor locking, or none).
* If a driver has both raw (char) and block
* routines, the char device switch table
* must point to the same semaphore structure
* as the block device.
*
*/
if (mp->flag & BLOCK) {
b->d_cpulock = -1;
/* set d_cpulock for proc locked driver */
if (mp->sema == S_PROC)
b->d_cpulock = cpulock;
/*
** if this is also a char then lock to same cpu as the
** block device
*/
if (mp->flag & (FUNDRV|CHAR))
c->d_cpulock = b->d_cpulock;
} else if (mp->flag & (FUNDRV|CHAR)) {
if (dp->edtp && dp->edtp->v_setcpusyscall)
c->d_cpulock = dp->edtp->v_cpusyscall;
else
c->d_cpulock = -1;
if (mp->sema == S_PROC)
c->d_cpulock = cpulock;
}
if (!dp->dname) {
fprintf(stderr,"Warning: no object file for %s\n", dp->mname);
return;
}
if (mp->flag & FSTYP) {
for (vfsp=vfsswp; vfsp->vfs_name != (char *)0; vfsp++)
continue;
vfsp->vfs_name = concat(dp->mname, (char *)0);
vfsp->vfs_init = concat(mp->prefix, "init");
vfsp->vfs_vfsops = concat(mp->prefix, "vfsops");
vfsp->vfs_vnodeops = concat(mp->prefix, "vnodeops");
}
/*
* inviolate names
*/
if (mp->flag & TTYS) {
c->d_ttys = concat(mp->prefix, "_tty");
}
if (mp->flag & FUNMOD) {
for (fp=fmodswp; strcmp(fp->f_name,Nnofile); fp++)
continue;
fp->f_name = mp->name;
fp->f_strmtab = concat(mp->prefix, "info");
}
if (mp->flag & BLOCK) {
b->d_prefix = mp->prefix;
b->d_bdevsw = concat(mp->prefix, "bdevsw");
}
if (mp->flag & FUNDRV)
c->d_str = concat(mp->prefix, "info");
if (mp->flag & (CHAR | FUNDRV)) {
c->d_prefix = mp->prefix;
c->d_cdevsw = concat(mp->prefix, "cdevsw");
}
symbol_scan(dp->dname, load_value_for_object, dp, gfind(dp->mname), fp);
}
/*
* load_value_for_object
*
* Does much of the dirty work for load_values() above.
* Called for each global procedure symbol.
*/
static void
load_value_for_object(char *procname, void *arg0, void *arg1, void *arg2)
{
struct master *mp, *mmp;
struct driver *dp = (struct driver *)arg0;
struct tunemodule *gp = (struct tunemodule*)arg1;
register struct Fmodsw *fp = (struct Fmodsw *)arg2;
register struct Bdevsw *b;
register struct Cdevsw *c;
struct lboot_edt *ep;
struct driver *ddp;
struct tunemodule *tmpgp;
char mgname[80];
register int i;
mp = dp->opthdr;
/*
* stub out unnecessary stubs
*/
ddp = driver;
do {
mmp = driver->opthdr;
if (mmp->flag & LOAD)
continue;
if (mmp->nrtn) {
register struct routine *rp;
register char *sp;
rp = (struct routine *) POINTER(mmp->o_routine, mmp);
for (i=0; i<mmp->nrtn; ++i, ++rp)
if ((sp=POINTER(rp->name,mmp)) && ! (strcmp(sp, procname)))
rp->name = 0;
}
} while (ddp = ddp->next);
/* build up tune_sanity functions */
tmpgp = gp;
got_sanity = 0;
while ((!got_sanity) &&(tmpgp != NULL) &&
EQUAL(tmpgp->t_mname, dp->mname)) {
strcpy(mgname, "_");
if (tmpgp->t_gname)
strcat(mgname, tmpgp->t_gname);
else
strcat(mgname, tmpgp->t_mname);
if (function(mgname, "_sanity", procname)) {
tmpgp->t_sanity =
strcpy(mymalloc(strlen(procname)+1),procname);
got_sanity++;
}
tmpgp = tmpgp->t_next;
}
if (!(mp->flag & FSTYP))
if ((!got_init) && function(mp->prefix, "init", procname)) {
*next_init++ =
strcpy(mymalloc(strlen(procname)+1), procname);
got_init++;
}
if ((!got_start) && function(mp->prefix, "start", procname)) {
*next_start++ = strcpy(mymalloc(strlen(procname)+1), procname);
got_start++;
}
if ((!got_reg) && function(mp->prefix, "reg", procname)) {
*next_reg++ = strcpy(mymalloc(strlen(procname)+1), procname);
got_reg++;
}
if ((!got_unreg) && function(mp->prefix, "unreg", procname)) {
*next_unreg++ = strcpy(mymalloc(strlen(procname)+1), procname);
got_unreg++;
}
if ((!got_halt) && function(mp->prefix, "halt", procname)) {
*next_halt++ = strcpy(mymalloc(strlen(procname)+1), procname);
got_halt++;
}
if (mp->flag & FUNMOD) {
if (function(mp->prefix, "devflag", procname))
fp->f_flags = strcpy(mymalloc(strlen(procname)+1),
procname);
}
b = bdevswp+dp->int_major;
c = cdevswp+dp->int_major;
/*
* no more special names if not a driver
*/
if ((mp->flag & NOTADRV) ||
((mp->flag & (CHAR | BLOCK | FUNMOD | FUNDRV)) == FUNMOD))
return;
if (function(mp->prefix, "devflag", procname)) {
if (mp->flag & BLOCK)
b->d_flags = strcpy(mymalloc(strlen(procname)+1),
procname);
if (mp->flag & (CHAR | FUNDRV))
c->d_flags = strcpy(mymalloc(strlen(procname)+1),
procname);
}
if (function(mp->prefix, "open", procname)) {
if (mp->flag & BLOCK)
b->d_open =
strcpy(mymalloc(strlen(procname)+1), procname);
if (mp->flag & CHAR)
c->d_open =
strcpy(mymalloc(strlen(procname)+1), procname);
}
if (function(mp->prefix, "close", procname)) {
if (mp->flag & BLOCK)
b->d_close = strcpy(mymalloc(strlen(procname)+1),
procname);
if (mp->flag & CHAR)
c->d_close = strcpy(mymalloc(strlen(procname)+1),
procname);
}
if (mp->flag & BLOCK) {
if (function(mp->prefix,"strategy",procname))
b->d_strategy = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"print",procname))
b->d_print = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"dump",procname))
b->d_dump = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"size",procname))
b->d_size = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"size64",procname))
b->d_size64 = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"map",procname))
b->d_map = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix,"unmap",procname))
b->d_unmap = strcpy(mymalloc(strlen(procname)+1),
procname);
}
if (mp->flag & CHAR) {
if (function(mp->prefix, "read", procname))
c->d_read = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "write", procname))
c->d_write = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "ioctl", procname))
c->d_ioctl = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "mmap", procname))
c->d_mmap = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "map", procname))
c->d_map = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "unmap", procname))
c->d_unmap = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "poll", procname) ||
function(mp->prefix, "chpoll", procname))
c->d_poll = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "attach", procname))
c->d_attach = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "detach", procname))
c->d_detach = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "enable", procname))
c->d_enable = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "disable", procname))
c->d_disable = strcpy(mymalloc(strlen(procname)+1),
procname);
}
if (mp->flag & FUNDRV) {
if (function(mp->prefix, "attach", procname))
c->d_attach = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "detach", procname))
c->d_detach = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "enable", procname))
c->d_enable = strcpy(mymalloc(strlen(procname)+1),
procname);
if (function(mp->prefix, "disable", procname))
c->d_disable = strcpy(mymalloc(strlen(procname)+1),
procname);
}
if (dp->flag & INEDT) {
if (function(mp->prefix, "edtinit", procname)) {
for (ep=dp->edtp; ep; ep=ep->e_next)
ep->e_init = strcpy(mymalloc(strlen(procname)+1),procname);
}
}
}
/*
* generate EDT structures
*/
static void
edt_gen(register FILE *f)
{
register struct driver *dp;
register struct lboot_edt *ep;
register struct lboot_vme_intrs *vp;
int i, vec, sub;
register int flag;
# define NUM_VECTS (MAX_VME_INTRS+1)
struct {
int sub;
struct driver *driver;
struct lboot_vme_intrs *intr;
} vme_intrs[NUM_VECTS];
for (dp = driver, flag=0; dp != 0; dp = dp->next) {
if ((!(dp->flag & INEDT)) || (dp->flag & DYNLOAD))
continue;
for (ep=dp->edtp; ep; ep=ep->e_next)
for (vp=ep->v_next; vp; vp=vp->v_next)
fprintf(f, !(flag++)
? "\nextern int %s()"
: ", %s()",
vp->v_vname);
}
if (flag)
fprintf(f, ";\n" );
bzero((char*)&vme_intrs[0], sizeof(vme_intrs));
sub = -1;
fprintf(f, "struct vme_intrs vme_intrs[] = {");
for (dp = driver; dp != 0; dp = dp->next) {
if ((!(dp->flag & INEDT)) || (dp->flag & DYNLOAD))
continue;
for (ep=dp->edtp,i=0; ep; ep=ep->e_next,++i) {
if (!(vp=ep->v_next))
continue;
if (++sub >= MAX_VME_INTRS)
error(ER108);
do {
fprintf(f, "\n\t{ %-10s, %#4x, %d, %d, ",
vp->v_vname,
vp->v_vec, vp->v_brl, vp->v_unit);
fprintf(f, "}," );
/* notice if an interrupt vector is assigned
* more than once
*/
vec = vp->v_vec;
if (vec) {
if (0 != vme_intrs[vec].driver) {
error(ER107,
vme_intrs[vec].driver->mname,
vme_intrs[vec].intr->v_unit,
dp->mname,
vp->v_unit,
vec);
}
vme_intrs[vec].driver = dp;
vme_intrs[vec].intr = vp;
vme_intrs[vec].sub = sub;
}
} while (vp=vp->v_next);
}
}
if (sub <= 0)
fprintf(f, "\n\t{ 0 }");
fprintf(f, "\n};\n");
for (dp = driver, flag = 0; dp != 0; dp = dp->next) {
if ((!(dp->flag & INEDT)) || (dp->flag & DYNLOAD))
continue;
for (ep=dp->edtp; ep; ep=ep->e_next) {
if (ep->e_init)
fprintf(f, (!(flag++)
? "\nextern int %s()"
: ", %s()"),
ep->e_init);
}
}
if (flag)
fprintf(f, ";\n" );
fprintf(f, "\nstruct edt edt[] = {\n" );
sub = -1;
for (dp = driver; dp != 0; dp = dp->next) {
if ((!(dp->flag & INEDT)) || (dp->flag & DYNLOAD))
continue;
for (ep=dp->edtp,i=0; ep; ep=ep->e_next,++i) {
fprintf(f, "\t{ %2d, %3d, %d, %2d, %2d, ",
ep->e_bus_type, ep->v_cpuintr,
ep->v_setcpuintr,
ep->e_adap, ep->e_ctlr);
if (ep->v_next) {
fprintf(f, "&vme_intrs[%2d], ",++sub);
} else {
fprintf( f, "0, " );
}
fprintf(f, "%s",
(ep->e_init!=0 ? ep->e_init : "0"));
for (i=0; i < NBASE; i++)
fprintf(f, ",%2d, %#10x, %#10x, (caddr_t)%#10llxl",
ep->e_space[i].ios_type,
ep->e_space[i].ios_iopaddr,
ep->e_space[i].ios_size,
ep->e_space[i].ios_vaddr);
fprintf(f, "},\n");
}
}
fprintf(f, "};\n\nint nedt = sizeof (edt)/ sizeof (struct edt);\n" );
}
/*
* mindlessly spew out generated structures
*/
static void
generate(register FILE *f)
{
register struct driver *dp;
register struct master *mp;
register struct Bdevsw *bp;
register struct Cdevsw *cp;
register struct Fmodsw *fp;
register struct Vfssw *vfsp;
int i, j, devtotal, bextra, cextra;
struct tune *t;
next_init = io_init;
if ((NULL != next_init) && (*next_init != NULL)) {
fprintf( f, "\nextern void %s()", *next_init);
while (*++next_init)
fprintf( f, ", %s()", *next_init);
fprintf( f, ";\n" );
}
fprintf( f, "void (*io_init[])() = {\n" );
for (next_init = io_init; *next_init; next_init++)
fprintf( f, " %s,\n", *next_init);
fprintf( f, " 0\n};\n" );
next_start = io_start;
if ((NULL != next_start) && (*next_start != NULL)) {
fprintf( f, "\nextern void %s()", *next_start);
while (*++next_start)
fprintf( f, ", %s()", *next_start);
fprintf( f, ";\n" );
}
fprintf( f, "void (*io_start[])() = {\n" );
for (next_start = io_start; *next_start; next_start++)
fprintf( f, " %s,\n", *next_start);
fprintf( f, " 0\n};\n" );
next_reg = io_reg;
if ((NULL != next_reg) && (*next_reg != NULL)) {
fprintf( f, "\nextern void %s()", *next_reg);
while (*++next_reg)
fprintf( f, ", %s()", *next_reg);
fprintf( f, ";\n" );
}
fprintf( f, "void (*io_reg[])() = {\n" );
for (next_reg = io_reg; *next_reg; next_reg++)
fprintf( f, " %s,\n", *next_reg);
fprintf( f, " 0\n};\n" );
next_unreg = io_unreg;
if ((NULL != next_unreg) && (*next_unreg != NULL)) {
fprintf( f, "\nextern void %s()", *next_unreg);
while (*++next_unreg)
fprintf( f, ", %s()", *next_unreg);
fprintf( f, ";\n" );
}
fprintf( f, "void (*io_unreg[])() = {\n" );
for (next_unreg = io_unreg; *next_unreg; next_unreg++)
fprintf( f, " %s,\n", *next_unreg);
fprintf( f, " 0\n};\n" );
next_halt = io_halt;
if ((NULL != next_halt) && (*next_halt != NULL)) {
fprintf( f, "\nextern void %s()", *next_halt);
while (*++next_halt)
fprintf( f, ", %s()", *next_halt);
fprintf( f, ";\n" );
}
fprintf( f, "void (*io_halt[])() = {\n" );
for (next_halt = io_halt; *next_halt; next_halt++)
fprintf( f, " %s,\n", *next_halt);
fprintf( f, " 0\n};\n" );
fprintf( f, "\nshort MAJOR[%d] = { ", NMAJORS);
for (i=0; i< NMAJORS; i++) {
if (!(i % 16))
fprintf( f, "\n\t");
fprintf( f, "%3d," , Major[i]);
}
/* { */ fprintf( f, " };\n\n");
/*
* Output block devices
*/
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++)
if (strcmp(bp->d_flags, rtname[RNODEVFLAG].name) == 0) {
error(ER121, bp->d_prefix);
/* NOTREACHED */
}
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++)
fprintf(f, "extern int %s;\n", bp->d_flags);
fprintf( f, "\nextern nodev()" );
j = 16;
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++) {
j = dcl_fnc(f,j, bp->d_open);
j = dcl_fnc(f,j, bp->d_close);
j = dcl_fnc(f,j, bp->d_strategy);
j = dcl_fnc(f,j, bp->d_print);
j = dcl_fnc(f,j, bp->d_map);
j = dcl_fnc(f,j, bp->d_unmap);
j = dcl_fnc(f,j, bp->d_dump);
j = dcl_fnc(f,j, bp->d_size);
j = dcl_fnc(f,j, bp->d_size64);
}
fprintf( f, ", nulldev();\n" );
bextra = (t = tunefind("bdevsw_extra")) ? t->svalue : 0;
cextra = (t = tunefind("cdevsw_extra")) ? t->svalue : 0;
/* if adding entries to both switches, then be sure bdevsw is long
* enough for devices to have the same index into both switches
*/
if (bextra && cextra) {
devtotal = max(bextra+bdevcnt, cextra+cdevcnt);
bextra = devtotal - bdevcnt;
cextra = devtotal - cdevcnt;
}
fprintf( f, "\nstruct bdevsw bdevsw[] = {\n");
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++) {
fprintf(f, "\t{ ");
fprintf(f, "&%s," , bp->d_flags);
fprintf( f, "%d, ", bp->d_cpulock);
fprintf(f, "%s, %s, %s, %s,\n" ,
bp->d_open, bp->d_close, bp->d_strategy, bp->d_print);
fprintf(f, "\t %s, %s, %s, %s, %s, 0, 0},\n",
bp->d_map, bp->d_unmap, bp->d_dump, bp->d_size,
bp->d_size64);
}
if (bextra)
for (i = 0; i < bextra; i++)
fprintf(f, "\t{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},\n");
/* { */ fprintf(f, "};\n" );
fprintf(f, "\nint bdevcnt = %d;\n", bdevcnt);
fprintf(f, "int bdevmax = %d;\n\n", bextra + bdevcnt);
/*
* Make a second pass to create prefixbdevsw entries for
* hardware graph-aware drivers.
*/
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++) {
if (bp->d_bdevsw == NULL)
continue;
fprintf(f, "struct bdevsw %s_s = \n\t{", bp->d_bdevsw);
fprintf(f, "&%s," , bp->d_flags);
fprintf( f, "%d, ", bp->d_cpulock);
fprintf(f, "%s, %s, %s, %s,\n" ,
bp->d_open, bp->d_close, bp->d_strategy, bp->d_print);
fprintf(f, "\t %s, %s, %s, %s, %s, 0, 0};\n",
bp->d_map, bp->d_unmap, bp->d_dump, bp->d_size,
bp->d_size64);
fprintf(f, "struct bdevsw *%s = &%s_s;\n\n",
bp->d_bdevsw, bp->d_bdevsw);
}
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++)
if (strcmp(cp->d_flags, rtname[RNODEVFLAG].name) == 0) {
error(ER121, cp->d_prefix);
/* NOTREACHED */
}
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++)
fprintf( f, "extern int %s;\n", cp->d_flags);
fprintf( f, "\nextern nodev()" );
j = 16;
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
j = dcl_fnc(f,j, cp->d_open);
j = dcl_fnc(f,j, cp->d_close);
j = dcl_fnc(f,j, cp->d_read);
j = dcl_fnc(f,j, cp->d_write);
j = dcl_fnc(f,j, cp->d_ioctl);
j = dcl_fnc(f,j, cp->d_mmap);
j = dcl_fnc(f,j, cp->d_map);
j = dcl_fnc(f,j, cp->d_unmap);
j = dcl_fnc(f,j, cp->d_poll);
j = dcl_fnc(f,j, cp->d_attach);
j = dcl_fnc(f,j, cp->d_detach);
j = dcl_fnc(f,j, cp->d_enable);
j = dcl_fnc(f,j, cp->d_disable);
}
fprintf( f, ", nulldev();\n" );
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
if (strcmp("0", cp->d_ttys))
fprintf( f, "extern struct tty %s;\n", cp->d_ttys);
if (strcmp("0", cp->d_str))
fprintf( f, "extern struct streamtab %s;\n", cp->d_str);
}
fprintf( f, "\n" );
fprintf( f, "\nstruct cdevsw cdevsw[] = {\n"); /* } */
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
fprintf(f, "\t{ ");
fprintf( f, "&%s,", cp->d_flags);
fprintf( f, "%d, ", cp->d_cpulock);
fprintf( f, "%s, %s, %s, %s,\n" ,
cp->d_open, cp->d_close, cp->d_read, cp->d_write);
fprintf( f, "\t %s, %s, %s, %s, %s,\n",
cp->d_ioctl, cp->d_mmap, cp->d_map, cp->d_unmap, cp->d_poll);
fprintf( f, "\t %s, %s, %s, %s, ",
cp->d_attach, cp->d_detach, cp->d_enable, cp->d_disable);
if (strcmp(cp->d_ttys, "0"))
fprintf( f, "&%s, ", cp->d_ttys);
else
fprintf( f, "0, ");
if (strcmp(cp->d_str, "0"))
fprintf( f, "&%s, 0, 0},\n", cp->d_str);
else
fprintf( f, "0, 0, 0 },\n");
}
if (cextra)
for (i = 0; i < cextra; i++)
fprintf(f, "\t{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},\n");
/* { */ fprintf( f, "};\n" );
fprintf( f, "\nint cdevcnt = %d;\n", cdevcnt);
fprintf( f, "int cdevmax = %d;\n\n", cextra + cdevcnt);
/*
* Make a second pass to create prefixcdevsw entries for
* hardware graph-aware drivers.
*/
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
if (cp->d_cdevsw == NULL)
continue;
fprintf(f, "struct cdevsw %s_s = \n\t{", cp->d_cdevsw);
fprintf( f, "&%s,", cp->d_flags);
fprintf( f, "%d, ", cp->d_cpulock);
fprintf( f, "%s, %s, %s, %s,\n" ,
cp->d_open, cp->d_close, cp->d_read, cp->d_write);
fprintf( f, "\t %s, %s, %s, %s, %s,\n",
cp->d_ioctl, cp->d_mmap, cp->d_map, cp->d_unmap, cp->d_poll);
fprintf( f, "\t %s, %s, %s, %s, ",
cp->d_attach, cp->d_detach, cp->d_enable, cp->d_disable);
if (strcmp(cp->d_ttys, "0"))
fprintf( f, "&%s, ", cp->d_ttys);
else
fprintf( f, "0, ");
if (strcmp(cp->d_str, "0"))
fprintf( f, "&%s, 0, 0};\n", cp->d_str);
else
fprintf( f, "0, 0, 0 };\n");
fprintf( f, "struct cdevsw *%s = &%s_s;\n\n",
cp->d_cdevsw, cp->d_cdevsw);
}
/*
* Create a table that associates prefix names for each driver with
* the appropriate cdevsw/bdevsw descriptors.
*/
fprintf(f, "struct static_device_driver_desc_s static_device_driver_table[] = {");
for (i=0, bp=bdevswp; i<bdevcnt; i++, bp++) {
if (bp->d_bdevsw == NULL)
continue;
if (bp->d_prefix == NULL)
continue;
fprintf(f, "\n\t{\"%s\", &%s_s, NULL},",
bp->d_prefix, bp->d_bdevsw);
}
for (i=0, cp=cdevswp; i<cdevcnt; i++, cp++) {
if (cp->d_cdevsw == NULL)
continue;
if (cp->d_prefix == NULL)
continue;
fprintf(f, "\n\t{\"%s\", NULL, &%s_s},",
cp->d_prefix, cp->d_cdevsw);
}
fprintf(f, "\n};\n");
fprintf(f, "int static_devsw_count = sizeof(static_device_driver_table)/sizeof(struct static_device_driver_desc_s);\n\n");
for (i=0, fp=fmodswp; i<fmodcnt; i++, fp++)
if (strcmp(fp->f_flags, rtname[RNODEVFLAG].name) == 0) {
error(ER121, fp->f_name);
/* NOTREACHED */
}
for (i=0, fp=fmodswp; i<fmodcnt; i++, fp++) {
if (strcmp("0", fp->f_strmtab))
fprintf(f, "extern struct streamtab %s;\n",
fp->f_strmtab);
}
for (i=0, fp=fmodswp; i<fmodcnt; i++, fp++)
fprintf( f, "extern int %s;\n", fp->f_flags);
fprintf( f, "\nstruct fmodsw fmodsw[] = {\n"); /* } */
for (i=0, fp=fmodswp; i<fmodcnt; i++, fp++) {
char tmpstr[FMNAMESZ+1];
if (strlen(fp->f_name) > FMNAMESZ) {
strncpy (tmpstr, fp->f_name, FMNAMESZ);
tmpstr[FMNAMESZ] = 0;
fprintf( f, "\t{ \"%s\", &%s, ",
tmpstr, fp->f_strmtab ); /* } */
} else
fprintf( f, "\t{ \"%s\", &%s, ",
fp->f_name, fp->f_strmtab ); /* } */
fprintf( f, "&%s,", fp->f_flags);
/* { */ fprintf( f, "},\n");
}
devtotal = (t = tunefind("fmodsw_extra")) ? t->svalue : 0;
for (; i<fmodcnt + devtotal; i++)
fprintf(f, "\t{ \"\", 0, 0},\n");
/* { */ fprintf( f, "};\n" );
fprintf( f, "\nint fmodcnt = %d;\n" , fmodcnt);
fprintf( f, "int fmodmax = %d;\n\n" , fmodcnt + devtotal);
/* vfssw table */
for (i=0, vfsp=vfsswp; i<nfstype; i++, vfsp++) {
if (vfsp->vfs_init && strlen(vfsp->vfs_init))
fprintf(f, "extern int %s();\n", vfsp->vfs_init);
if (vfsp->vfs_vfsops && strlen(vfsp->vfs_vfsops))
fprintf(f, "extern struct vfsops %s;\n",
vfsp->vfs_vfsops);
if (vfsp->vfs_vnodeops && strlen(vfsp->vfs_vnodeops))
fprintf(f, "extern struct vnodeops %s;\n",
vfsp->vfs_vnodeops);
}
fprintf( f, "\nstruct vfssw vfssw[] = {\n" ); /* } */
for (i=0, vfsp=vfsswp; i<nfstype; i++, vfsp++) {
if (vfsp->vfs_name && strlen(vfsp->vfs_name))
fprintf(f, "\t{ \"%s\", ", vfsp->vfs_name);
else
fprintf(f, "\t{ \"BADFS\", ");
if (vfsp->vfs_init && strlen(vfsp->vfs_init))
fprintf(f, "%s, ", vfsp->vfs_init);
else
fprintf(f, "0, ");
if (vfsp->vfs_vfsops && strlen(vfsp->vfs_vfsops))
fprintf(f, "&%s, ", vfsp->vfs_vfsops);
else
fprintf(f, "0, ");
if (vfsp->vfs_vnodeops && strlen(vfsp->vfs_vnodeops))
fprintf(f, "&%s, ", vfsp->vfs_vnodeops);
else
fprintf(f, "0, ");
fprintf(f, "&%s, 0 },\n", vfsswp[0].vfs_vnodeops);
}
devtotal = (t = tunefind("vfssw_extra")) ? t->svalue : 0;
for (; i<nfstype + devtotal; i++)
fprintf(f, "\t{ \"\", 0, 0, 0, 0, 0},\n");
fprintf( f, "};\n" );
fprintf(f, "int nfstype = %d;\n" , nfstype);
fprintf( f, "int vfsmax = %d;\n\n" , nfstype + devtotal);
fprintf( f, "int noprobe = %d;\n",noprobe);
fprintf( f, "cpuid_t nointr_list[] = {\n");
for (i=0; i<nointr_count;) {
for (j=0; (j<16) && (i<nointr_count); i++, j++)
fprintf( f, "%d, ", nointr_list[i]);
fprintf( f, "\n");
}
fprintf( f, "CPU_NONE };\n\n");
fprintf( f, "/* system file version %d */\n\n", system_version);
fprintf( f, "\ndev_t rootdev = 0x%x;\n", rootdev);
if (bootrootfile)
fprintf(f, "char *bootrootfile = \"%s\";\n\n", bootrootfile);
else
fprintf(f, "char *bootrootfile = NULL;\n\n");
fprintf( f, "\ndev_t dumpdev = 0x%x;\n", dumpdev);
if (bootdumpfile)
fprintf(f, "char *bootdumpfile = \"%s\";\n\n", bootdumpfile);
else
fprintf(f, "char *bootdumpfile = NULL;\n\n");
fprintf( f, "dev_t swapdev = 0x%x;\n", swapdev);
if (bootswapfile)
fprintf(f, "char *bootswapfile = \"%s\";\n", bootswapfile);
else
fprintf(f, "char *bootswapfile = NULL;\n");
fprintf( f, "daddr_t swplo = %ld;\n", swplo);
fprintf( f, "int nswap = %d;\n\n", nswap);
/* Dump ibus adapter table */
if (ibus_numadaps > 0) {
fprintf(f, "\nint ibus_numadaps = %d;\n", ibus_numadaps);
fprintf(f, "ibus_t ibus_adapters[] = {\n");
for (i = 0; i < ibus_numadaps; i++) {
ibus_t *ib = &ibus_adapters[i];
fprintf(f, "\t{ %d, %d, %d, %d, %d },\n",
ib->ibus_module, ib->ibus_unit,
ib->ibus_adap, ib->ibus_ctlr, ib->ibus_proc);
}
fprintf(f, "\t{ 0, 0, 0, 0, 0}\n};\n\n");
}
/* map interrupt req. level to cpu */
fprintf( f, "char cpuipl[] = {");
for (i=0; i<MAXIPL-1; i++)
fprintf( f, "%d, ",cpuipl[i]);
fprintf( f, "%d };\n",cpuipl[i]);
edt_gen(f); /* generate EDT structures */
fprintf( f, "\n/* stubs */\n" );
dp = driver;
do {
if (dp->flag & LOAD)
continue;
mp = dp->opthdr;
if (mp->nrtn) {
struct routine *rp;
rp = (struct routine *) POINTER(mp->o_routine, mp);
for (i=0; i<mp->nrtn; ++i, ++rp)
if (rp->name) {
if (rp->id == RNOTHING ||
rp->id == RNOREACH)
fprintf( f, "void %s() %s\n",
POINTER(rp->name,mp),
rtname[rp->id].routine);
else
fprintf( f, "%s() %s\n",
POINTER(rp->name,mp),
rtname[rp->id].routine);
}
}
} while (dp=dp->next);
}
#ifdef NEVER
static void
devflags_print(FILE *f, uint flags)
{
register int i;
register int gotone;
gotone = 0;
if (!(flags & DLOCK_MASK)) {
/* default to processor locked */
fprintf(f, "D_PROCESSOR");
gotone++;
}
for (i = 0; i < sizeof(flags) * 8; i++) {
if (flags & (1 << i)) {
if (gotone++)
fprintf(f, "|");
switch (1 << i) {
case D_MP:
fprintf(f, "D_MP");
break;
case D_PROCESSOR:
fprintf(f, "D_PROCESSOR");
break;
#ifdef DLOCK_NETWORK
case DLOCK_NETWORK:
fprintf(f, "DLOCK_NETWORK");
break;
#endif /* DLOCK_NETWORK */
#ifdef D_WBACK
case D_WBACK:
fprintf(f, "D_WBACK");
break;
#endif /* D_WBACK */
default:
/* Unknown flag. Not good, but don't
* break anything.
*/
fprintf(f, "0");
break;
}
}
}
fprintf(f, ", ");
}
#endif
/*
* get_ar_fmt()
*
* This routine attempts to determine the underlying
* object file format of an archive library by checking
* the magic # of the first .o member in the archive.
*/
static int
get_ar_fmt(int fd)
{
__int64_t offset = SARMAG;
struct ar_hdr arhdr;
int rc = UNKNOWN_FMT;
Elf32_Ehdr elfhdr;
/* seek to start of first arhdr */
(void) lseek(fd, offset, 0);
/* scan member entries until we get an object file */
for ( ; ; ) {
/* read next arhdr -- truncate indicates ??? */
if (read(fd, (void *)&arhdr, sizeof (arhdr)) != sizeof (arhdr))
break;
(void) sscanf(arhdr.ar_size, "%lld", &offset);
/* skip optional symtab/strtab member */
if (IS_ELF_AR_SYMTAB(arhdr.ar_name) ||
IS_ELF_AR64_SYMTAB(arhdr.ar_name) ||
IS_ELF_AR_STRTAB(arhdr.ar_name)) {
(void) lseek(fd, offset, 1);
continue;
}
/* we've got what should be our first real object file */
if (read(fd, (void *)&elfhdr, sizeof (elfhdr)) != sizeof (elfhdr))
break;
/* ELF or COFF? */
if (IS_ELF(elfhdr)) {
/* Determine ABI of kernel.o */
if (elfhdr.e_ident[EI_CLASS] == ELFCLASS64)
rc = ELF64_FMT;
else if (elfhdr.e_ident[EI_CLASS] == ELFCLASS32) {
if (elfhdr.e_flags & EF_MIPS_ABI2)
rc = ELFN32_FMT;
else
rc = ELFO32_FMT;
}
break;
} else {
rc = COFF_FMT;
break;
}
}
return (rc);
}
/*
* driver_matches_kernel()
*
* Determines object format/ABI of driver and checks it against kernel.
* If incompatible, generates an error and returns FALSE.
* Otherwise, returns TRUE.
*/
static int
driver_matches_kernel(struct driver *dp)
{
int fd;
union commonhdr {
FILHDR fhdr;
Elf32_Ehdr elfhdr;
char armag[SARMAG];
} commonhdr;
if (!dp->dname)
return FALSE;
if ((fd = open(dp->dname, O_RDONLY)) == -1) {
/* <name>: perror() message */
error(ER7, dp->dname);
return FALSE;
}
read_and_check(fd, dp->dname, (char *)&commonhdr,
sizeof (commonhdr));
if (!IS_ELF(commonhdr.elfhdr) &&
!IS_MIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_MIPSELMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSEBMAGIC(commonhdr.fhdr.f_magic) &&
!IS_SMIPSELMAGIC(commonhdr.fhdr.f_magic) &&
(memcmp(&commonhdr.armag, ARMAG, SARMAG))) {
/* Driver <name>: not a valid object file */
error(ER15, dp->dname);
close (fd);
free(dp->dname);
dp->dname = NULL;
dp->magic = UNKNOWN_FMT;
dp->flag &= ~LOAD;
return FALSE;
}
if (IS_ELF(commonhdr.elfhdr)) {
if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS64)
dp->magic = ELF64_FMT;
else if (commonhdr.elfhdr.e_ident[EI_CLASS] == ELFCLASS32) {
if (commonhdr.elfhdr.e_flags & EF_MIPS_ABI2)
dp->magic = ELFN32_FMT;
else
dp->magic = ELFO32_FMT;
}
}
else if (memcmp(&commonhdr.armag, ARMAG, SARMAG) == 0)
dp->magic = get_ar_fmt(fd);
else
dp->magic = COFF_FMT;
close(fd);
/*
* Magic number test. The object format of dp must
* match that of kernel.
*/
if (dp->magic != kernel.magic) {
/* Driver <name>: <driver_format> object format is incompatible with <kernel_format> kernel; object ignored */
error(ER16, dp->dname, FORMAT_NAME(dp->magic), FORMAT_NAME(kernel.magic));
syslog (LOG_WARNING,
"WARNING %s: %s object format is incompatible with %s kernel; object ignored\n",
dp->dname, FORMAT_NAME(dp->magic), FORMAT_NAME(kernel.magic));
free(dp->dname);
dp->dname = NULL;
dp->flag &= ~LOAD;
return FALSE;
}
return TRUE;
}