Xinu7/src/cmd/download/OLD/upload.c.RAW

/*----------------------------------------------------------------------*/
/*									*/
/*	upload        +++ copy LSI-11 memory to ./core11 +++		*/
/*									*/
/* This program takes LSI-11 memory and places it into a file named	*/
/* core11 on the host system						*/
/*									*/
/* Configuration -							*/
/*	VAX tty line connected to LSI 11 ODT (console) port		*/
/*									*/
/* Usage:								*/
/*	upload [filename] [-lx] [-o filename]				*/
/*									*/
/* Authors:								*/
/*	R. Brown & C. Kent						*/
/*	Purdue University/CS Deptartment				*/
/*	September, 1981							*/
/*	mods by Comer, 11/81-11/83					*/
/*									*/
/*----------------------------------------------------------------------*/

#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <errno.h>
#include "{Xinu-directory}/include/core11.h"
#include "{Xinu-directory}/include/a.out.h"
#include "{Xinu-directory}/include/baud.h"
#include "getdev.h"

#define	MAXADDR		0157777
#define	CSRBASE		0177560
#define	LOADSTART	0
typedef	unsigned short	lsiword;

#ifndef	TRUE
#define	TRUE		1
#define	FALSE		0
typedef	int		Bool;
#endif
#define	EOS		((char)0)
#define	SOH		'/'
#define	ESC		'\033'

#define	LOADER		"{Xinu-directory}/lib/ul"
#define	MAXPACKSIZE	526
#define	STACKLEN	20

#define settimer(t,m)	msgval = m; alarm(t)
#define canceltimer()	alarm(0)
#define	unctrl(ch)	(_unctrl[ch])

char	*_unctrl[] = {			/* unctrl codes	for ttys	*/
	"^@","^A","^B","^C","^D","^E","^F","^G","^H","^I","^J","^K",
	"^L","^M","^N","^O","^P","^Q","^R","^S","^T","^U","^V","^W",
	"^X","^Y","^Z","^[","^\\","^]","^~","^_",
	" ","!","\"","#","$", "%","&","'","(",")","*","+",",","-",
	".","/","0", "1","2", "3","4","5","6","7","8","9",":",";",
	"<","=",">", "?","@", "A","B","C","D","E","F","G","H","I",
	"J","K","L", "M","N", "O","P","Q","R","S","T","U","V","W",
	"X","Y","Z", "[","\\","]","^","_","`","a","b","c","d","e",
	"f","g","h", "i","j", "k","l","m","n","o","p","q","r","s",
	"t","u","v", "w","x", "y","z","{","|","}","~","^?"
};

struct	packet	{
	lsiword	len, base;
	lsiword	buf[MAXPACKSIZE];
	lsiword	sum;
};

struct {
	char	*odtline;
	int	baudrate;
	char	*corefile;
	char	*loader;
	int	lowaddr;
	int	highaddr;
	Bool	verbose;
	Bool	silent;
	Bool	noload;
	char	*outfile;
} A;

char 	*msgval;
char	*Openfiles[20];
struct	core11	Corehead;
int	Devfd,	Corefd;
int	Haltedat;
struct	sgttyb	VAXttyb;
lsiword *Memory;
char	*index();
char	class[MAXNAMELEN];
int	useclass;
int	machnum;
char	dev[MAXNAMELEN], devname[MAXNAMELEN];
char	lockfile[40];
int	touch(), getdev();
extern	int	errno;
int	use;

/*----------------------------------------------------------------------
 *  upload  -- upload an LSI 11 memory image
 *----------------------------------------------------------------------
 */
main(argc,argv)
int	argc;
char	*argv[];
{
	int alarmhandler(), inthandler();
	int ldrfd, bytes;
	int base,length,i;
	char buf[32];
	struct exec bhdr;
	short entry;

	/*
	 * set up terminal modes...prepare to reset on interrupt
	 */
	procargs(argc, argv);
	if ((machnum = getdev(useclass,class,machnum,&Devfd,lockfile)) < 0)
		exit(1);
	if (machnum == 0) {
		strcpy(devname, class);
		if (! A.silent)
			printf("Using %s\n", class);
	}
	else {
		sprintf(devname, DEVNAME, DEVDIR, class);
		if (! A.silent)
			printf("Using %s #%d\n", class, machnum);
	}
	Openfiles[Devfd] = sprintf(dev, devname, machnum);
	Corefd = creat(A.corefile,0666);
	ldrfd =	openfile(A.loader,0);
	gtty(Devfd,&VAXttyb);
	/*
	 * trap	software signals so that lines can be restored to their
	 * original state and the core file can	be written
	 */
	if ( signal(SIGINT,SIG_IGN) != SIG_IGN )
		signal(SIGINT,inthandler);
	if ( signal(SIGTERM,SIG_IGN) !=	SIG_IGN	)
		signal(SIGTERM,inthandler);
	if ( signal(SIGQUIT,SIG_IGN) !=	SIG_IGN	)
		signal(SIGQUIT,inthandler);
	linemode(Devfd,A.baudrate,RAW); /*|TANDEM*/

	signal(SIGALRM,	alarmhandler);
	/*
	 * allocate memory array - this	written	to the core file when the
	 * program terminates
	 */
	if (A.verbose)
		printf("Alocating %d (0%o) bytes for image\n",MAXADDR+1,
			MAXADDR+1);
	Memory = (lsiword *)malloc(MAXADDR+1);
	for ( i=0 ; i<(MAXADDR+1)/2 ; i++ )
		Memory[i] = 0;
	Corehead.c_zero1 = 0;
	Corehead.c_zero2 = 0;
	Corehead.c_zero3 = 0;
	Corehead.c_zero4 = 0;
	Corehead.c_zero5 = 0;
	Corehead.c_magic = COREMAGIC;

        message("Getting ODT...",0,0);
	getodt(Devfd);
	/*
	 * Get the contents of the registers
	 */
	message("Getting registers...",0,0);
	getregs(Devfd,Corehead.c_regs);
	getpsw(Devfd,&Corehead.c_psw);
	if (A.verbose)
		message("Getting a.out header",0,0);
	gethdr(ldrfd,&bhdr);
	bytes =	bhdr.a_text+bhdr.a_data+STACKLEN;
	if (A.verbose)
		message("Number of bytes = %d",bytes,0);
	if ( !A.noload ) {
		message("Deposit boot loader...",0,0);
		entry =	odtload(ldrfd,&bhdr,0,Memory);
	} else {
		message("Not loading boot loader...",0,0);
		read ( ldrfd, Memory, bytes*sizeof(lsiword) );
	}
	/*
	 * Set up arguments to upl and start it	running...
	 */
	if (A.verbose)
		message("Getting ODT again...",0,0);
	getodt(Devfd);
	message("Starting load of 0%o-0%o...",A.lowaddr,A.highaddr);
	base = (A.lowaddr < bytes ? bytes :	A.lowaddr);
	length = (A.highaddr-base + 1)/2;
	if (A.verbose)
		message("Setting argument registers",0,0);
	setreg(Devfd,0,base);
	setreg(Devfd,1,length);
	setreg(Devfd,4,CSRBASE);
	setreg(Devfd,6,base);
	if (A.verbose)
		message("Starting LSI 11 execution",0,0);
	sendodt(Devfd,"P",TRUE);
	fastread(Devfd,Memory);
	message("Writing core file...",0,0);
	write(Corefd,&Corehead,sizeof Corehead);
	write(Corefd,Memory,A.highaddr+1);
	touch(lockfile);
	message("Done",0,0);

}
/*
 *===================================================
 * procargs - process argument in global structure
 *===================================================
 *
 * This	procedure continas the logic for converting the	UNIX argument
 * list	into global variables
 */
procargs(argc, argv)
int argc;
char *argv[];
{
	int arg, i, unswitched, more;
	int  afd;
	struct exec ahdr;
	char *swptr;
	/*
	 * assign default values
	 */
	A.lowaddr = 0;
	A.highaddr = MAXADDR;
	A.corefile = "core11";
	A.odtline = NULL;
	A.baudrate = B9600;
	strcpy(class, "LSI");
	useclass = FALSE;
	machnum = MYDEV;
	A.loader = LOADER;
	A.verbose = FALSE;
	A.silent = FALSE;
	A.noload = FALSE;
	unswitched = 0;
	for ( arg=1 ; arg<argc ; arg++ ) {
		if ( argv[arg][0] == '-' ) {
			more = TRUE;
			swptr =	&argv[arg][1];
			while (	more &&	*swptr!='\0' ) {
				switch ( *swptr	) {
				case 'o':
					if ( arg+1 >= argc )
						usagexit(argv[0]);
					A.corefile = argv[arg++];
					more = FALSE;
					break;
				case 'v':
					A.verbose = TRUE;
					break;
				case 's':
					A.silent = TRUE;
					break;
				case 'n':
					A.noload = TRUE;
					break;
				case 'a':
					afd = openfile(argv[arg++],0);
					if ( arg+1 >= argc )
						usagexit(argv[0]);
					gethdr(afd,&ahdr);
					A.lowaddr = ahdr.a_text;
					A.highaddr = ahdr.a_text+ahdr.a_data+
							ahdr.a_bss;
					more = FALSE;
					break;
				case 'c':
					argv[arg] += 2;
					strcpy(class, argv[arg]);
					useclass = TRUE;
					more = FALSE;
					break;
				case 'l':
					argv[arg] += 2;
					if ( (machnum = atoi(argv[arg])) < 0)
						usagexit(argv[0]);
					more = FALSE;
					break;
				case 't':
					argv[arg] += 2;
					strcpy(class, argv[arg]);
					machnum = TTYNAME;
					more = FALSE;
					break;
				case 'B':
					if (*(argv[arg]+=2) == '\0') {
						A.baudrate = NOBAUD;
						break;
					}
					for (i = 0; i < NBAUD; ++i)
						if (strcmp(baudlist[i].name,
							argv[arg]) == 0)
								break;
					if (i < NBAUD) {
					printf("baud = %s (%d)\n", baudlist[i].name, baudlist[i].rate);
						A.baudrate = baudlist[i].rate;
					}
					else {
						fprintf(stderr,
						    "Unknown baud rate: %s\n",
							argv[arg]);
						exit(1);
					}
					more = FALSE;
					break;
				default:
					usagexit(argv[0]);
				}
				swptr++;
			}
		} else { /* there's no dash in front */
			switch ( unswitched++ )	{
			case 0:
				A.highaddr = atoi(argv[arg]);
				message("highaddr=%o",A.highaddr,0);
				break;
			case 1:
				A.lowaddr = A.highaddr;
				A.highaddr = atoi(argv[arg]);
				message("lowaddr=%o",A.lowaddr,0);
				message("highaddr=%o",A.highaddr,0);
				break;
			default:
				usagexit(argv[0]);
			}
		}
	}
}
usagexit(pgm)
char *pgm;
{
	fprintf(stderr,"usage: %s [-options] [[lowaddr] highaddr]\n",pgm);
	exit(1);
}
/*
 *==========================================================
 * openfile - try to open file,	exit with message if error
 *==========================================================
 */
openfile(name,mode)
char *name;
int mode;
{
	int fd;
	settimer(10, "open timed out");
	if ((fd=open(name,mode)) < 0 ) {
		perror(name);
		exit(1);
	}
	canceltimer();
	Openfiles[fd] =	name;
	return(fd);
}
/*
 *=========================================
 * alarmhandler	- return from alarm calls
 *=========================================
 */
alarmhandler()
{
	signal(SIGALRM,	alarmhandler);
	fprintf(stdout, "%s\n", msgval);
	exit(1);
}

/*
 *=====================================
 * inthandler -- interrupt processing
 *=====================================
 */
inthandler()
{
	write(Corefd,&Corehead,sizeof Corehead);
	write(Corefd,Memory,A.highaddr+1);
	touch(lockfile);
	callexit(2);
}
/*
 *=======================================
 * callexit - restore ttymodes and exit
 *=======================================
 */
callexit(ret)
int ret;
{
	/* stty(Devfd,&VAXttyb); */
	exit(ret);
}

/*
 *==========================================
 * odtload - load bootstrap loader via ODT
 *==========================================
 * input state:	after ODT prompt
 * output state: same
 *
 * fdin	- a.out	file to	download
 * hdr - a.out header for file to load
 * loc - location to begin loading (overrides default 0)
 * outaddr - ptr to int	array to hold current contents,	or NULL
 */
odtload(fdin, hdr, loc,	outaddr)
int fdin;
int loc;
lsiword	*outaddr;
struct exec *hdr;
{
	int addr, lsival;
	int i, length;
	lsiword	word;
	char buf[32], filebuf[BUFSIZ],c,*val;
	FILE *infile;

	infile = fdopen(dup(fdin),"r");
	fseek(infile,sizeof *hdr,0);
	setbuf(stdout,NULL);
	setbuf(infile,filebuf);
	length = hdr->a_text+hdr->a_data+STACKLEN;
	addr = LOADSTART;
	do {
		fread(&word, sizeof word, 1, infile);
		if ( addr == LOADSTART ) {
			sprintf(buf,"%o/",addr+loc);
			sendodt(Devfd,buf,TRUE);
			readuntil(Devfd, " ?", buf, 7);
			val = buf;
		} else {
			sendodt(Devfd, "\n",TRUE);
			readuntil(Devfd, " ?", buf, 7);
			val = index(buf,'/')+1;
		}
		if ( outaddr !=	NULL ) {
			sscanf(val,"%o ",&lsival);
			outaddr[(addr+loc)/2] =	lsival & 0xffff;
		}
		sprintf(buf, "%o", word	& 0xffff);
		sendodt(Devfd, buf,TRUE);
		if ( !A.silent && !A.verbose )
			displayval(addr);
		addr +=	sizeof (lsiword);
	} while	( word != 0177777 );
	if ( !A.silent && !A.verbose )
		printf("\r");
	sendodt(Devfd,"\r",TRUE);
	readuntil(Devfd, "@", buf, 5);
	/*
	 * now,	run this half to load the other half faster
	 */
	fseek(infile,sizeof(struct exec),0);
	setreg(Devfd,1,length);
	setreg(Devfd,-1,0340);
	setreg(Devfd,7,LOADSTART);
	sendodt(Devfd,"P",FALSE);
        sleep(1);
	for ( i=0 ; i<length ; i++ ){
		c = getc(infile);
		if (A.verbose){
			fprintf(stdout,"AT: %06o ", i&0xffff);
			fprintf(stdout,"OUT: %03o ",c&0xff);
		}
		write(Devfd,&c,1);
		read(Devfd,&c,1);
		if (A.verbose) fprintf(stdout,"IN: %03o\n",c&0xff);
		if ( i>=addr && outaddr != NULL )
			*(((char *)outaddr)+i) = c;
	}
	readuntil(Devfd,"@", buf, 8);
	return(addr);
}
/*
 *===============================================
 * getpsw - get	the current contents of	the PSW
 *===============================================
 */
getpsw(fd,psw)
int fd;
short *psw;
{
	char buf[60];
	char	*reply;

	sendodt(Devfd,"$S/",TRUE);
	readuntil(Devfd," ?", buf, 5);
	reply = index(buf,'/');
	sscanf( ((0==(int)reply) ? buf : reply+1),"%o ",psw);
	sendodt(Devfd,"\r",TRUE);
	readuntil(Devfd,"@",buf,5);
}
/*
 *==========================================
 * getregs - get contents of the registers
 *==========================================
 */
getregs(fd,regs)
int fd;
short *regs;
{
	int r;
	int lsival;
	char buf[32], *val;
	for ( r=0 ; r<REGISTERS	; r++ )	{
		if ( r==0 ) {
			sprintf(buf,"R%d/",r);
			sendodt(Devfd,buf,TRUE);
			readuntil(Devfd, " ?", buf, 7);
			val = buf;
		} else {
			sendodt(Devfd, "\n",TRUE);
			readuntil(Devfd, " ?", buf, 7);
			val = index(buf,'/')+1;
		}
		sscanf(val,"%o ",&lsival);
		regs[r]	= lsival & 0xffff;
		if ( !A.silent && !A.verbose )
			displayval(r);
	}
	if ( !A.silent && !A.verbose )
		printf("\r");
	sendodt(Devfd,"\r",TRUE);
	readuntil(Devfd, "@", buf, 5);
}

/*
 *===============================
 * getodt - get	ODT's attention
 *===============================
 * Input state - undefined
 * Output state	- immediately after ODT	prompt
 */
getodt(fd)
int fd;
{
	char buf[BUFSIZ];

	ioctl(fd, TIOCSBRK, NULL);
	sleep(2);
	ioctl(fd, TIOCCBRK, NULL);
	readuntil(fd,"@",buf,5);
	sscanf(buf,"%o",&Haltedat);
}
/*
 *==================================================
 * readuntil - read from line until some character
 *==================================================
 */
readuntil ( fd,	ch, buf, time )
int fd,	time;
char *ch, *buf;
{
	settimer(time, "read timed out");
	if ( A.verbose )
		printf("IN: ");
	do {
		if ( read(fd, buf, 1) != 1 ) {
			perror(Openfiles[fd]);
			callexit(1);
		}
		if (A.verbose )
			printf("%s",unctrl(*buf));
	} while	( *buf == '\0' || index(ch,*buf++) == NULL );
	*buf = EOS;
	canceltimer();
	if ( A.verbose )
		printf("\n");
}
/*
 *==============================================
 * sendodt - send a message to ODT half duplex
 *==============================================
 */
sendodt(fd, msg, wait)
int fd;
char *msg;
Bool wait;
{

	char buf[32], *ptr, tmpstr[2];
	if ( A.verbose ) {
		printf("OUT: ");
		for ( ptr=msg ; *ptr!=EOS ; ptr++ ) {
			printf("%s",unctrl(*ptr));
		}
		printf("\n");
	}
	while (*msg!=EOS) {
		write(fd,msg,1);
                if ( wait ) {
                        tmpstr[0] = *msg;
                        tmpstr[1] = EOS;
                        readuntil(fd, tmpstr, buf, 5);
                }
		msg++;
	}
}

/*
 *==========================================
 * setreg - preload a register through ODT
 *==========================================
 */
setreg(fd, reg,	value)
int fd,	reg, value;
{
	char buf[32];
	if (A.verbose)
		message("Setting register %d to 0%o",reg,value&0xffff);
	if ( reg >= 0 )
		sprintf(buf,"R%d/",reg);
	else
		sprintf(buf,"$S/");
	sendodt(fd,buf,TRUE);
	readuntil(fd," ",buf,5);
	sprintf(buf,"%o\r",value&0xffff);
	sendodt(fd,buf,TRUE);
	readuntil(fd,"@",buf,5);
}
/*
 *=================================================
 * message - conditionally display status message
 *=================================================
 */
message(str,arg,arg2)
char *str;
{
	if ( !A.silent ) {
		printf(str,arg,arg2);
		printf("\n");
	}
}
/*
 *=======================================
 * linemode - set up linemode and speed
 *=======================================
 */
linemode(fd,speed,mode)
int fd,	speed, mode;
{
	struct sgttyb tcb;
	if ( gtty(fd,&tcb) < 0 ) {
		perror(Openfiles[fd]);
		callexit(1);
	}
	if (speed != NOBAUD)
		tcb.sg_ispeed =	tcb.sg_ospeed =	speed;
	tcb.sg_flags = mode;
	stty(fd,&tcb);
}

/*
 *================================
 * gethdr - read an a.out header
 *================================
 */
gethdr(fd,hdr)
int fd;
struct exec *hdr;
{
	if ( read(fd, hdr, sizeof *hdr)	!= sizeof *hdr)	{
		fprintf(stderr,"%s: EOF	reading	a.out header\n",Openfiles[fd]);
		callexit(1);
	}
	if ( hdr->a_magic != A_MAGIC1 )	{
		fprintf(stderr,"%s: wrong magic	number\n",Openfiles[fd]);
		callexit(1);
	}
}

/*
 *============================================
 * displayval -	display	a number on one	line
 *============================================
 */
displayval(val)
int val;
{
	char buf[32];
        sprintf(buf,"%o ",val);
	printf("\r%s",buf);
	fflush(stdout);
}


/*
 *==================================================
 * fastread - receive packets from high	speed line
 *==================================================
 */
fastread(fd,ptr)
int fd;
lsiword	*ptr;
{
	struct packet packet;
	FILE *in;
	lsiword	sum;
	int i;
	in = fdopen(fd,"r");
	message("Reading LSI 11 memory...",0,0);
	do {
		do {
			getpack(in,&packet);
			if ( packet.len	<= MAXPACKSIZE ) {
				sum = packet.len + packet.base;
				for ( i=0 ; i<packet.len ; i++ )
					sum += packet.buf[i];
				if ( A.verbose )
					message("exp./actual sum=0%o/0%o",
						sum, packet.sum);
				if ( sum == packet.sum )
					break;
			}
			if ( !A.silent )
				fprintf(stdout,"NAK\n");
			write(fd,"n",1);
		} while	( TRUE ) ;
		write(fd,"y",1);
		for ( i=0 ; i<packet.len ; i++ )
			Memory[i+(packet.base/sizeof(lsiword))]	= packet.buf[i];
		if ( !A.silent )
			displayval((int)(packet.base&0xffff));
	} while	( packet.len !=	0 );
	if ( !A.silent ) {
		displayval(0);
		printf("\r");
	}
}
/*
 *=======================================
 * getpack - read next packet from line
 *=======================================
 */
getpack(fd,pptr)
FILE *fd;
struct packet *pptr;
{
	char c;
	Bool success;
	int i;
	/*
	 * wait	for start of heading character
	 */
	success	= FALSE;
	do {
		while (	(c=getc(fd)) !=	SOH ) ;	/* nil */
		if (A.verbose)
			fprintf(stdout,"SOH\n");
		pptr->len = getword(fd);
		pptr->base = getword(fd);
		if ( A.verbose )
			fprintf(stdout,"len, base = %o %o\n",pptr->len,
			pptr->base);
		if ( pptr->len > MAXPACKSIZE ) {
			return;
		}
		for ( i=0 ; i<pptr->len	; i++ )	{
			pptr->buf[i] = getword(fd);
		}
		pptr->sum = getword(fd);
		success	= TRUE;
	} while	( !success );
}
getword(fd)
FILE *fd;
{
	lsiword	word;
	word = getbyte(fd);
	word = word | (getbyte(fd)<<8);
	return(word);
}
getbyte(fd)
FILE *fd;
{
	char c;
	c = getc(fd);
if (A.verbose) fprintf(stdout,"%03o ",c&0xff);
	if ( c==ESC ) {
		c = getc(fd);
if (A.verbose) fprintf(stdout,"(%03o) ",c&0xff);
	}
	return(c&0xff);
}