#ifndef lint static char sccsid[] = "@(#)main.c 1.1 94/10/31 SMI"; #endif /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #ifdef OPENPROMS #include #include #include 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