/*	boot.c	6.1	83/07/29	*/

#include	"../s32/setjmp.h"
#include	"../h/param.h"
#include	"../h/inode.h"
#include	"../h/fs.h"
#include	"../h/vm.h"
#include	<a.out.h>
#include	"../salib/saio.h"
#include	"../h/reboot.h"
#include	"../s32/cpu.h"

#define		TAPE_BSIZE  (16*1024)
#define		PROMNAMELEN  4
extern int *nofault;

/*
 * Boot program... arguments passed in determine
 * whether boot stops to ask for system name and which device
 * boot comes from.
 */

char	devname[][2] = {
	'r','d',	/* 0 = rd */
	'i','d',	/* 1 = is */
};

char line[100] = "xx(0,0)vmunix";
char def_boot[] = "d(0,6)vmunix";
char def_tape[] = "xx(0,x)";

extern short autoboot_area;
extern char bootline_area[];
extern u_long chipType;
char sys_debug = 1;	/* Enable system-wide debugging statements. */

int	retry = 0;
unsigned	sum = 0;		/* kernel checksum */
char	defaultstring[PROMNAMELEN+1];	/* store the "boot-from" string here */
jmp_buf	restart;			/* Handy rabbithole to pop out of */

main(romval, defaultfile)
	char *defaultfile;
{
	register howto, devtype;	/* this is very important.
		do not procede unless you fully understand this comment:
		howto=r11, devtype=r10 */
	register i;
	register char *ptr1, *ptr2;
	int io;
	extern char version[];

	romval &= 0xff; /* not sure about crm yet */

#ifdef lint
	howto = 0; devtype = 0;
#endif
	/*
	 * Check that the format of the string the monitor 
	 * passed us is legit.  VRM, GRM and SRM may waffle; CRM
	 * may screw up, too, in various circumstances.
	 */
	if (checkformat(defaultfile) < 0)
		/* 
		 * "defaultstring" is where the string is stored 
		 * after validity checking.
		 */
		defaultstring[0] = '\0';
	else
		defaultstring[PROMNAMELEN] = '\0'; /* null-terminate */

#ifndef	USE_ERM
	if (setjmp(restart))
	{
		/*
		 * We will wind up here in case of unexpected exceptions...
		 *
		 * We don't want to autoboot after 
		 * weirdness dumps us here.
		 */
		romval = 0;
		printf("\n(boot code restarting)\n");
	}
#endif	USE_ERM

	printf("\n%sboot from %s\n",
		romval == 2?"auto":"", 
		(*defaultstring) ? defaultstring : "");
#ifdef	LATER
#ifdef JUSTASK
	howto = RB_ASKNAME|RB_SINGLE;
#else
	devtype = 0;		/* For now only boot from Rimfire */
	if (romval == 2)	/* Autoboot */
		howto = 0;
	else			/* Boot to single user */
		howto = RB_ASKNAME;
	if ((howto&RB_ASKNAME)==0) {	/* Autoboot */
		if (devtype>=0 && devtype<sizeof(devname)/2	/* Check */
		    && devname[devtype][0]) {			/* devtype */
		/* 
		 * Convert prom syntax to unix syntax .
		 *
		 * If the machine is stupid enough to have grody old VRM
		 * and it passes us a garbage defaultfile, force the 
		 * defaultfile to be DEFBOOT.
		 */
		convert(line, defaultstring);
		} else
			howto = RB_SINGLE|RB_ASKNAME;	/* Force manual boot */
	}
#endif
#endif	LATER
	for (;;) {
		static char *progname[] = {"mkfs","bootload","cpio",0};

		printf("\nM%x StandAlone Tape Boot Version:%s",
			chipType, version);
		printf ("Options:\n\t\t1) Run 'mkfs'\n");
		printf ("\t\t2) Load 'boot code' onto disk\n");
		printf ("\t\t3) Run 'cpio'\n");
		printf ("\t\t4) Return to CRM\n");
		printf ("TAPE BOOT> ");
		gets(line);			/* Get response */
		i = atoi (line);
		if (i <= 0 || i > 4)
			printf ("Illegal value %d, type a number between 1 and 3\n", i);
		else {
			/*
			 * Jump to CRM
			 */
			if (i == 4)
				asm ("jmp	0x10000");
			strcpy (line, def_tape);
			convert(line, defaultstring);
			line [5] = i + '0';
			printf ("Loading %s\n", progname[i-1]);
			io = open(line, 0);/* Open and initialize the device */
			if (io >= 0)	/* Open succeeded, device ready */
				copyunix(io);	/* Load vmunix */
			else printf ("Open error on %s\n", line);
		}
	}
}

long
convert(uname, pname) /* convert prom syntax to unix syntax */
	char *uname, *pname;
{
	register long pnameval = (long)pname;
	register char *un = uname;
	register char *pn = pname;
	long ctlr, minornumber, tempnumber, diskspercont, unit;

	/*
	 * Because of validity check "checkformat", we no longer need to 
	 * check the origin of the string we are converting.  So, the check:
	 *	(pnameval < 0x18000) || (pnameval > 0x18800)
	 * is no longer necessary.  It's ugly anyways.
	 * 
	 * Earlier, we truncated the string if checkformat didn't like it.
	 */
	if (! *pname)  
	{
		/* 
		 * Address of string is out of range,
		 * or string is otherwise bogus (like not composed of 
		 * printing characters). "Checkformat" said so when we 
		 * first started the boot code.
		 */
		printf("OLD STYLE BOOT PROMS\n", pnameval);
		strcpy(uname, "rd(0,6)vmunix"); /* ICCH */
		return 1;
	}

	*un++ = *pn++ + 'a' - 'A'; /* convert to lower case */
	*un++ = *pn++ + 'a' - 'A'; /* convert to lower case */
	*un++ = '(';
	ctlr = *pn++ - '0';
	unit = *pn++ - '0';

	tempnumber = minornumber = 16 * ctlr + unit;
	if (minornumber > 99) {
		*un++ = '0' + (tempnumber / 100);
		tempnumber %= 100;
	}
	if (minornumber > 9) {
		*un++ = '0' + (tempnumber / 10);
		tempnumber %= 10;
	}
	*un++ = '0' + tempnumber;
	strcpy(un, ",0)");

	return 0;
}

/*
 * Check that the given string is made up of real live ASCII characters.
 */
checkformat(promstring)
char *promstring;
{
	register int i;
	register char c;
	int *save;

	save = nofault;
	nofault = restart;

	if (!setjmp(restart))
	{
		for (i=0; i<PROMNAMELEN; promstring++, i++)
		{
			c = *promstring;
			/*
			 * 32 is ascii for ' ';
			 * 126 is ascii for highest printable character ('~').
			 */
			if ((c < 32) || (c > 126))
				return (-1);
			else
				defaultstring[i] = c;
		}
	} 
	else
	{
#ifdef DEBUG
		printf("Bus error examining boot string.\n");
#endif DEBUG
		return(0);
	}
	nofault = save;
}

unsigned
checksum(prevsum, addr, len)
	unsigned register prevsum;
	register char *addr;
	register int len;
{

	while (len--) {
		if (prevsum&01)
			prevsum = (prevsum>>1) + 0x8000;
		else
			prevsum >>= 1;
		prevsum += *addr++;
		prevsum &= 0xFFFF;
	}

	return(prevsum);
}



/*ARGSUSED*/
copyunix(io)
register io;
{
	register int i;
	char *addr;
	
	addr = (char *)0x20000;		/* Load starting at 128K */

	/*
	 * Do magic; count == 0 ==> read til next filemark
	 */
	while (read(io, addr, TAPE_BSIZE) == TAPE_BSIZE)
		addr += TAPE_BSIZE;

	close (io);
	/* Jump start: */
	(*((int (*)()) 0x20000))();
	return;
}
