587 lines
13 KiB
C
587 lines
13 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)main.c 1.1 94/10/31 SMI";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/reboot.h>
|
|
#include <machine/reg.h>
|
|
#include <debug/debugger.h>
|
|
#include <a.out.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#ifdef OPENPROMS
|
|
#include <sun/openprom.h>
|
|
#include <sun/autoconf.h>
|
|
#include <machine/pte.h>
|
|
|
|
extern char *prom_bootpath(), *prom_bootargs();
|
|
#endif
|
|
|
|
char vmunix[50] = "vmunix"; /* and room to patch to whatever */
|
|
char myname[50]; /* name of the debugger */
|
|
char aline[LINEBUFSZ]; /* generic buffer used for console input */
|
|
extern int debugcmd();
|
|
extern char *malloc();
|
|
extern char estack[];
|
|
char *malreturn;
|
|
|
|
#ifdef MULTIPROCESSOR
|
|
unsigned nodeid;
|
|
unsigned who;
|
|
extern int cpus_enabled[];
|
|
#ifdef PROM_IDLECPUS_WORKS
|
|
extern unsigned cpus_nodeid[];
|
|
#endif /* PROM_IDLECPUS_WORKS */
|
|
#endif MULTIPROCESSOR
|
|
|
|
#define MALLOC_PAD 0x1000 /* malloc pad */
|
|
|
|
static interactive = 0; /* true if -d flag passed in */
|
|
|
|
#ifndef sun2
|
|
u_int memory_avail;
|
|
#endif
|
|
|
|
main()
|
|
{
|
|
func_t go2, load_it();
|
|
char *arg;
|
|
#ifdef mc68000
|
|
struct regs fakeregs;
|
|
struct stkfmt fakestkfmt;
|
|
int fakedfc, fakesfc;
|
|
#endif
|
|
#ifdef OPENPROMS
|
|
register struct memlist *pmem;
|
|
extern struct memlist *getmemlist();
|
|
#endif
|
|
|
|
ttysync();
|
|
#ifdef OPENPROMS
|
|
if (romp->op_romvec_version > 0) {
|
|
pmem = getmemlist("memory", "available");
|
|
if (pmem == (struct memlist *)0)
|
|
return;
|
|
} else
|
|
pmem = *romp->v_availmemory;
|
|
for (memory_avail = 0; pmem->next != (struct memlist *)NULL;
|
|
pmem = pmem->next) {
|
|
memory_avail += pmem->size;
|
|
}
|
|
memory_avail += pmem->size;
|
|
#elif !defined(sun2)
|
|
/*
|
|
* Initialize so that the standalone code doesn't
|
|
* use the same pages the debugger is in.
|
|
*/
|
|
memory_avail = *romp->v_memoryavail;
|
|
#endif OPENPROMS || !sun2
|
|
spawn((int *)estack, debugcmd);
|
|
while ((go2 = load_it(&arg)) == (func_t)-1)
|
|
continue;
|
|
if (go2 == (func_t)-2)
|
|
return;
|
|
free(malloc(MALLOC_PAD));
|
|
|
|
printf("%s loaded - 0x%x bytes used\n",
|
|
arg, mmu_ptob(pagesused));
|
|
|
|
#ifdef MULTIPROCESSOR
|
|
nodeid = prom_nextnode(0); /* root node */
|
|
for (nodeid = prom_childnode(nodeid);
|
|
(nodeid != 0) && (nodeid != -1);
|
|
nodeid = prom_nextnode(nodeid)) {
|
|
if ((prom_getproplen(nodeid, "mid") == sizeof who) &&
|
|
(prom_getprop(nodeid, "mid", &who) != -1)) {
|
|
if (who == 15)
|
|
who = 0; /* level-1 mbus module */
|
|
else
|
|
who &= 3;
|
|
#ifdef PROM_IDLECPUS_WORKS
|
|
cpus_nodeid[who] = nodeid;
|
|
#endif /* PROM_IDLECPUS_WORKS */
|
|
cpus_enabled[who] = 1;
|
|
}
|
|
}
|
|
#endif MULTIPROCESSOR
|
|
if (interactive) {
|
|
#ifdef mc68000
|
|
bzero((caddr_t)&fakeregs, sizeof (fakeregs));
|
|
bzero((caddr_t)&fakestkfmt, sizeof (fakestkfmt));
|
|
(void) cmd(fakedfc, fakesfc, fakeregs, fakestkfmt);
|
|
#else
|
|
(void) cmd();
|
|
#endif
|
|
if (dotrace) {
|
|
scbstop = 1;
|
|
dotrace = 0;
|
|
}
|
|
}
|
|
nobrk = 1; /* no more sbrk's allowed */
|
|
exitto(go2);
|
|
}
|
|
|
|
#define LOAD 0x4000
|
|
|
|
/*
|
|
* Read in a Unix executable file and return its entry point.
|
|
* Handle the various a.out formats correctly.
|
|
* "Io" is the standalone file descriptor to read from.
|
|
* Print informative little messages if "print" is on.
|
|
* Returns -1 for errors.
|
|
*/
|
|
func_t
|
|
readfile(io, print, name)
|
|
register int io;
|
|
int print;
|
|
char *name;
|
|
{
|
|
struct exec x;
|
|
register int i;
|
|
register char *addr;
|
|
register int shared = 0;
|
|
register int loadaddr;
|
|
register int segsiz;
|
|
register int datasize;
|
|
|
|
i = read(io, (char *)&x, sizeof x);
|
|
if (i != sizeof (x)) {
|
|
printf("Bad read: expected 0x%x got 0x%x\n", sizeof(x), i);
|
|
return ((func_t)-1);
|
|
}
|
|
if (N_BADMAG(x)) {
|
|
printf("Not executable\n");
|
|
return ((func_t)-1);
|
|
}
|
|
shared = (x.a_magic == OMAGIC? 0: 1);
|
|
if (print)
|
|
printf("Size: %d", x.a_text);
|
|
datasize = x.a_data;
|
|
if (!shared) {
|
|
x.a_text = x.a_text + x.a_data;
|
|
x.a_data = 0;
|
|
}
|
|
if (lseek(io, N_TXTOFF(x), 0) == -1)
|
|
goto shread;
|
|
if (read(io, (char *)LOAD, (int)x.a_text) < x.a_text)
|
|
goto shread;
|
|
addr = (char *)(x.a_text + LOAD);
|
|
if (x.a_machtype == M_OLDSUN2)
|
|
segsiz = OLD_SEGSIZ;
|
|
else
|
|
segsiz = SEGSIZ;
|
|
if (shared)
|
|
while ((int)addr & (segsiz-1))
|
|
*addr++ = 0;
|
|
if (print)
|
|
printf("+%d", datasize);
|
|
if (read(io, addr, (int)x.a_data) < x.a_data)
|
|
goto shread;
|
|
if (print)
|
|
printf("+%d", x.a_bss);
|
|
addr += x.a_data;
|
|
for (i = 0; i < x.a_bss; i++)
|
|
*addr++ = 0;
|
|
if (print)
|
|
printf(" bytes\n");
|
|
if (x.a_machtype != M_OLDSUN2 && x.a_magic == ZMAGIC)
|
|
loadaddr = LOAD + sizeof (struct exec);
|
|
else
|
|
loadaddr = LOAD;
|
|
debuginit(io, &x, name);
|
|
return ((func_t)loadaddr);
|
|
|
|
shread:
|
|
printf("Truncated file\n");
|
|
return ((func_t)-1);
|
|
}
|
|
|
|
/*
|
|
* Prompt for name of file to be read into memory for debugging.
|
|
*/
|
|
#ifdef OPENPROMS
|
|
func_t
|
|
obp_load_it(arg)
|
|
register char **arg;
|
|
{
|
|
register int howto;
|
|
register int io;
|
|
func_t go2;
|
|
extern char myname_default[];
|
|
static char filename[LINEBUFSZ];
|
|
register char *bargs;
|
|
register char *bpath;
|
|
char *args[8];
|
|
register char abuf[128];
|
|
|
|
bpath = prom_bootpath();
|
|
bargs = prom_bootargs();
|
|
(void)strcpy(abuf, bargs);
|
|
setparam(abuf, args);
|
|
|
|
if (myname[0] == '\0') {
|
|
register char *s, *p;
|
|
|
|
for (s = bargs; isspace(*s); s++)
|
|
;
|
|
if (*s == '-')
|
|
s = myname_default;
|
|
for (p = myname; *s && !isspace(*s); )
|
|
*p++ = *s++;
|
|
} else if (interactive == 0) {
|
|
/*
|
|
* 2nd time thru and we are not interactive,
|
|
* return fatal error code back to caller.
|
|
*/
|
|
return ((func_t)-2);
|
|
}
|
|
|
|
if (*args[0] == '-')
|
|
howto = bootflags(args[0]);
|
|
else
|
|
howto = bootflags(args[1]);
|
|
if (howto & RB_DEBUG)
|
|
interactive = 1;
|
|
|
|
/*
|
|
* Now we have to ask for the name of the program to load
|
|
* if we are interactive.
|
|
*/
|
|
*filename = '\0';
|
|
if (interactive) {
|
|
printf("%s: ", myname);
|
|
gets(filename);
|
|
}
|
|
|
|
/*
|
|
* If no file name given (or we are non-interactive),
|
|
* default to patchable string in vmunix[]
|
|
*/
|
|
if (*filename == '\0') {
|
|
(void)strcpy(filename, vmunix);
|
|
printf("%s: %s\n", myname, filename);
|
|
}
|
|
parseargs(filename, howto, args, bargs);
|
|
|
|
(void) reopen(0); /* Restart the I/O. */
|
|
io = open(filename, 0);
|
|
if (io >= 0) {
|
|
go2 = readfile(io, 1, filename);
|
|
} else {
|
|
printf("boot failed\n");
|
|
interactive = 1;
|
|
go2 = (func_t)-1;
|
|
}
|
|
close(io); /* Done with it. */
|
|
*arg = filename;
|
|
return (go2);
|
|
}
|
|
|
|
/*
|
|
* Parse the boot line to set bootparam structure
|
|
*/
|
|
setparam(cp, bp)
|
|
register char *cp;
|
|
register char *bp[];
|
|
{
|
|
register int i = 0;
|
|
|
|
while (*cp && isspace(*cp))
|
|
cp++;
|
|
while ((i < 8) && *cp) {
|
|
bp[i++] = cp;
|
|
while (*cp && (!isspace(*cp)))
|
|
cp++;
|
|
if (isspace(*cp))
|
|
*cp++ = '\0';
|
|
while (*cp && isspace(*cp))
|
|
cp++;
|
|
}
|
|
/*
|
|
* Null out remaining args.
|
|
*/
|
|
for (; i < 8; ++i)
|
|
bp[i] = '\0';
|
|
}
|
|
#endif OPENPROMS
|
|
|
|
func_t
|
|
load_it(arg)
|
|
register char **arg;
|
|
{
|
|
register struct bootparam *bp;
|
|
register int howto;
|
|
register int io;
|
|
func_t go2;
|
|
extern char myname_default[];
|
|
register char *ap;
|
|
static char filename[LINEBUFSZ];
|
|
|
|
#ifdef OPENPROMS
|
|
if (romp->op_romvec_version > 0)
|
|
return (obp_load_it(arg));
|
|
#endif
|
|
|
|
#if defined(sun2) || defined(sun3)
|
|
if (romp->v_bootparam == 0)
|
|
bp = (struct bootparam *)0x2000; /* Old Sun-1 address */
|
|
else
|
|
#endif sun2 || sun3
|
|
bp = *romp->v_bootparam; /* S-2: via romvec */
|
|
|
|
*arg = bp->bp_argv[0];
|
|
if (*arg == NULL)
|
|
*arg = "";
|
|
if (myname[0] == '\0') {
|
|
register char *s, *p;
|
|
|
|
for (s = *arg, ap = aline; *s && *s != ')';)
|
|
*ap++ = *s++;
|
|
*ap++ = *s++;
|
|
if (*s == '\0')
|
|
s = myname_default;
|
|
for (p = myname; *s;)
|
|
*p++ = *s++;
|
|
} else if (interactive == 0) {
|
|
/*
|
|
* 2nd time thru and we are not interactive,
|
|
* return fatal error code back to caller.
|
|
*/
|
|
return ((func_t)-2);
|
|
}
|
|
|
|
howto = bootflags(bp->bp_argv[1]);
|
|
if (howto & RB_DEBUG)
|
|
interactive = 1;
|
|
|
|
/*
|
|
* Now we have to ask for the name of the program to load
|
|
* if we are interactive.
|
|
*/
|
|
*filename = '\0';
|
|
if (interactive) {
|
|
printf("%s: ", myname);
|
|
gets(filename);
|
|
}
|
|
|
|
/*
|
|
* If no file name given (or we are non-interactive),
|
|
* default to patchable string in vmunix[]
|
|
*/
|
|
if (*filename == '\0') {
|
|
register char *s, *p;
|
|
|
|
for (s = filename, p = vmunix; *p;)
|
|
*s++ = *p++;
|
|
*s = '\0';
|
|
printf("%s: %s\n", myname, filename);
|
|
for (s = filename; *s; )
|
|
*ap++ = *s++;
|
|
*ap = '\0';
|
|
}
|
|
parseparam(filename, howto, bp);
|
|
|
|
(void) reopen(aline); /* Restart the I/O. */
|
|
io = open(filename, 0);
|
|
if (io >= 0) {
|
|
go2 = readfile(io, 1, filename);
|
|
} else {
|
|
printf("boot failed\n");
|
|
go2 = (func_t)-1;
|
|
}
|
|
close(io); /* Done with it. */
|
|
*arg = filename;
|
|
return (go2);
|
|
}
|
|
|
|
struct bootf {
|
|
char let;
|
|
short bit;
|
|
} bootf[] = {
|
|
'a', RB_ASKNAME,
|
|
's', RB_SINGLE,
|
|
'i', RB_INITNAME,
|
|
'h', RB_HALT,
|
|
'b', RB_NOBOOTRC,
|
|
'd', RB_DEBUG,
|
|
'w', RB_WRITABLE,
|
|
0, 0,
|
|
|
|
};
|
|
|
|
/*
|
|
* Parse the boot line to determine boot flags
|
|
*/
|
|
bootflags(cp)
|
|
register char *cp;
|
|
{
|
|
register int i, boothowto = 0;
|
|
|
|
if ((cp) && (*cp++ == '-'))
|
|
while (*cp) {
|
|
for (i = 0; bootf[i].let; i++) {
|
|
if (*cp == bootf[i].let) {
|
|
boothowto |= bootf[i].bit;
|
|
break;
|
|
}
|
|
}
|
|
cp++;
|
|
}
|
|
return (boothowto);
|
|
}
|
|
|
|
/*
|
|
* Parse the boot line and put it in bootparam. Preserve the flags
|
|
* unless redefined. Always preserve the remaining arguments.
|
|
*
|
|
* The boot line comes in in one of two forms:
|
|
* xx(c,u,p)file[whitespace]\0
|
|
* xx(c,u,p)file[whitespace]-[flags]\0
|
|
* If the former is present, we take the bootflags and arguments from the
|
|
* bootparam structure. If the latter is present, the user has overridden
|
|
* the original boot flags with his/her own specification.
|
|
*/
|
|
parseparam(line, defaults, bp)
|
|
char *line;
|
|
int defaults;
|
|
register struct bootparam *bp;
|
|
{
|
|
register int i;
|
|
register char *cp, *lp = line;
|
|
|
|
while (*lp && isgraph(*lp))
|
|
lp++;
|
|
if (*lp) {
|
|
*lp = '\0';
|
|
}
|
|
cp = lp++;
|
|
while (*lp && isspace(*lp))
|
|
lp++;
|
|
if (*lp) {
|
|
/*
|
|
* There's something here. Is it new flags?
|
|
*/
|
|
if (*lp == '-') {
|
|
defaults = bootflags(lp);
|
|
}
|
|
}
|
|
/*
|
|
* Now backtrack, write the flags, and fill in the arguments.
|
|
*/
|
|
lp = cp + 1;
|
|
defaults |= RB_DEBUG; /* or in debug flag */
|
|
*lp++ = '-';
|
|
for (i = 0; bootf[i].let; i++) {
|
|
if (defaults & bootf[i].bit)
|
|
*lp++ = bootf[i].let;
|
|
}
|
|
*lp++ = 0;
|
|
for (i = 1; i < 8; ++i) {
|
|
cp = bp->bp_argv[i];
|
|
if (cp && *cp && (*cp != '-')) {
|
|
while (*lp++ = *cp++)
|
|
;
|
|
}
|
|
}
|
|
/*
|
|
* Copy the fully qualified boot line to the string table.
|
|
*/
|
|
bcopy(line, bp->bp_strings, 95);
|
|
bp->bp_strings[95] = '\0';
|
|
/*
|
|
* Scan the string table, setting the argv pointers.
|
|
*/
|
|
for (i = 0, cp = bp->bp_strings; i < 8; ++i) {
|
|
if (cp && *cp) {
|
|
bp->bp_argv[i] = cp;
|
|
while (*cp++)
|
|
;
|
|
} else {
|
|
bp->bp_argv[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef OPENPROMS
|
|
/*
|
|
* Parse the line argument and put it in the bootargs in OBP.
|
|
* Preserve the flags unless redefined. Always preserve the remaining
|
|
* arguments. Leave just a filename in line.
|
|
*
|
|
* The line looks like:
|
|
* file[whitespace]-[flags]\0
|
|
*
|
|
* We take the bootflags and arguments from the bargs structure.
|
|
*/
|
|
parseargs(line, defaults, bp, dp)
|
|
char *line;
|
|
int defaults;
|
|
register char *bp[];
|
|
register char *dp;
|
|
{
|
|
register int i;
|
|
register char *cp, *lp = line;
|
|
char buf[128];
|
|
|
|
/*
|
|
* Find the end of the file argument.
|
|
*/
|
|
while (*lp && isgraph(*lp))
|
|
lp++;
|
|
cp = lp++;
|
|
|
|
/*
|
|
* Scan ahead, looking for flags.
|
|
*/
|
|
while (*lp && isspace(*lp))
|
|
lp++;
|
|
if (*lp) {
|
|
/*
|
|
* There's something here. Is it new flags?
|
|
*/
|
|
if (*lp == '-') {
|
|
defaults = bootflags(lp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now backtrack, write the flags, and fill in the arguments.
|
|
*/
|
|
lp = cp;
|
|
defaults |= RB_DEBUG;
|
|
if (defaults) {
|
|
*lp++ = ' ';
|
|
*lp++ = '-';
|
|
for (i = 0; bootf[i].let; i++) {
|
|
if (defaults & bootf[i].bit)
|
|
*lp++ = bootf[i].let;
|
|
}
|
|
*lp = '\0';
|
|
}
|
|
if (bp[1] && *(bp[1]) == '-')
|
|
i = 2;
|
|
else
|
|
i = 1;
|
|
for (; i < 8; ++i) {
|
|
cp = bp[i];
|
|
if (cp && *cp && (*cp != '-')) {
|
|
*lp++ = ' ';
|
|
while (*lp++ = *cp++)
|
|
;
|
|
*lp = '\0';
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copy the fully qualified boot line to the bootargs.
|
|
* Reset the bootparam arguments.
|
|
*/
|
|
bcopy(line, dp, 100);
|
|
setparam(line, bp);
|
|
}
|
|
#endif OPENPROMS
|