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

Compare this file to the similar file:
Show the results in this format:

/*----------------------------------------------------------------------*/
/*									*/
/*	download	+++ load programs into LSI 11 +++		*/
/*									*/
/* This program takes PDP-11 a.out format files and downloads them	*/
/* into a PDP-11/02.							*/
/*									*/
/* Usage:								*/
/*	download [filename] [-lLSI#] [-b filename] [-v] [-s]		*/
/*									*/
/* Authors:								*/
/*	R. Brown, Doug Comer						*/
/*	Purdue University/CS Deptartment				*/
/*	September, 1981 - Nov. 1983					*/
/*									*/
/* (c) Copyright, 1982, All rights reserved.				*/
/*									*/
/*									*/
/*----------------------------------------------------------------------*/

#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <errno.h>
#include "/usr/Xinu/include/a.out.h"
#include "/usr/Xinu/include/baud.h"
#include "getdev.h"

#define DEFFILE	"a.out"
#define LOADER	"/usr/Xinu/lib/dl"

#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", "{", "|", "}", "~", "^?"
};
#ifndef TRUE
#define TRUE	1
#define FALSE	0
typedef int	Bool;
#endif
typedef unsigned short lsiword;

#define SOH		'/'
#define ACK		'y'
#define NAK		'n'
#define ESC		'\033'
#define PACKSIZE	0200
#define LSIPORT		0177560
#define	LSISPEED	B9600		/* speed of LSI line for stty	*/
#define INTDISABLE	0340
#define EOS		((char)0)
#define MAXADDR		0160000

#define LOADSTART	0
#define SP		6

/*
 * Argument defaults then global structure
 */


struct {
	char *lsiline;
	int  baudrate;
	char *filename;
	char *loader;
	int  startdelay;
	Bool verbose;
	Bool silent;
	Bool autostart;
} A;

int Haltedat;
int Devfd;
char class[MAXNAMELEN];
int useclass;			/* TRUE iff class requested explicitly	*/
int machnum;			/* device number requested/received	*/
char dev[MAXNAMELEN], devname[MAXNAMELEN];
char *msgval;
char	lockfile[20];
char *Openfiles[20];
extern int errno;

/*
 * MAIN PROGRAM...
 */
main ( argc, argv )
int argc;
char *argv[];
{
	int aoutfd, ldrfd;
	int alarmhandler(), inthandler();
        int bsize, asize;
	char buf[32];
	struct exec ahdr, bhdr;

	/*
	 * set up terminal modes...prepare to reset on interrupt
	 */
	procargs(argc, argv);
	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);

	signal(SIGALRM, alarmhandler);
	/*
	 * open lines and files - set line mode
	 */
	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] = A.lsiline = sprintf(dev, devname, machnum);
	aoutfd = openfile(A.filename,0);
	ldrfd = openfile(A.loader,0);
	linemode(Devfd,A.baudrate,RAW);
	/*
	 * download sequence -
	 *    get ODT's attention
	 * load bootstrap, enter
	 * load program
	 */
	gethdr(aoutfd, &ahdr);
	gethdr(ldrfd,&bhdr);
	message("getting ODT...");
	getodt(Devfd);
	bsize = bhdr.a_text+bhdr.a_data;
	asize = ahdr.a_text+ahdr.a_data;
	message("loading boot program...");
	bootload(ldrfd,&bhdr,0);
	setreg(Devfd,1,ahdr.a_bss);
	setreg(Devfd,2,(A.autostart ? A.startdelay : -1));
	setreg(Devfd,3,ahdr.a_entry & (~1));
	setreg(Devfd,4,LSIPORT);
        message("\rstarting boot loader...");
	sendodt(Devfd,"P",FALSE);
        fastload(aoutfd, &ahdr);
	autostart(Devfd,&ahdr);
        message("done");
	touch(lockfile);
	callexit(0);
}
/*
 *====================================================================
 * procargs - parse and check command line, setup global A structure
 *====================================================================
 */
procargs(argc, argv)
int argc;
char *argv[];
{
	int arg, i;
	int unswitched;

	A.filename  = DEFFILE;
	A.baudrate = B9600;
	strcpy(class, "LSI");
	useclass = FALSE;
	machnum = ANYDEV;
	A.loader    = LOADER;
	A.verbose = FALSE;
	A.silent = FALSE;
	A.autostart = FALSE;
	A.startdelay = 0;
	unswitched = 0;
	for ( arg=1 ; arg<argc ; arg++ ) {
		if ( argv[arg][0] == '-' ) {
			switch ( argv[arg][1] ) {
			case 'c':
				argv[arg] += 2;
				strcpy(class, argv[arg]);
				useclass = TRUE;
				break;
			case 'l':
				argv[arg] += 2;
				if ( (machnum=atoi(argv[arg])) < 0)
					usagexit(argv[0]);
				break;
			case 't':
				argv[arg] += 2;
				strcpy(class, argv[arg]);
				machnum = TTYNAME;
				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)
					A.baudrate = baudlist[i].rate;
				else {
					fprintf(stderr,
						"Unknown baud rate: %s\n",
						argv[arg]);
					exit(1);
				}
				break;
			case 'b':
				if ( ++arg >= argc )
					usagexit(argv[0]);
				A.loader = argv[arg];
				break;
			case 'v':
				A.verbose = TRUE;
				break;
			case 's':
				A.silent = TRUE;
				break;
			case 'a':
				A.autostart = TRUE;
				A.startdelay = atoi(&argv[arg][2]);
				break;
			default:
				usagexit(argv[0]);
			}
		} else /* ( argv[arv][1] != '-' ) */ {
			switch ( unswitched++ ) {
			case 0:
				A.filename = argv[arg];
				break;
			default:
				usagexit(argv[0]);
			}
		}
	}
}

/*
 *================================
 * 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);
	}
}

/*
 *==========================================
 * usagexit - print usage message and exit
 *==========================================
 */
usagexit(pgm)
char *pgm;
{
	fprintf(stderr,
	"usage: %s [filename] [-l lsi#] [-b filename] [-v] [-s] [-a [delay]]",
		pgm);
	callexit(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);
		callexit(1);
	}
	canceltimer();
	Openfiles[fd] = name;
	return(fd);
}
/*
 *=======================================
 * 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);
}

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

	ioctl(fd, TIOCSBRK, NULL);
	sleep(2);
	ioctl(fd, TIOCCBRK, NULL);
        readuntil(fd,"@",buf,10);
        atptr = rindex(buf,'@');
        if ( atptr != buf && *(atptr-1) == '^' )
                readuntil(fd,"@",buf,10);
}
/*
 *==================================================
 * 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 == EOS || index(ch,*buf++) == NULL );
	*buf = EOS;
	canceltimer();
	if ( A.verbose )
		printf("\n");
}

/*
 *=========================================
 * alarmhandler - return from alarm calls
 *=========================================
 */
alarmhandler()
{
	signal(SIGALRM, alarmhandler);
	fprintf(stdout, "%s\n", msgval);
	exit(1);
}

/*
 *=====================================
 * inthandler -- interrupt processing
 *=====================================
 */
inthandler()
{
	callexit(2);
}
/*
 *=======================================
 * callexit - restore ttymodes and exit
 *=======================================
 */
callexit(ret)
int ret;
{
	exit(ret);
}
/*
 *===========================================
 * bootload - load bootstrap loader via ODT
 *===========================================
 * input state: after ODT prompt
 * output state: same
 */
bootload(fdin, hdr, loc)
int fdin;
int loc;
struct exec *hdr;
{
	FILE *infile;
	int length, stklen, i, addr;
	lsiword word;
	char buf[32], *stack;

	infile = fdopen(dup(fdin),"r");
	fseek(infile,sizeof(struct exec),0);
	length = hdr->a_text + hdr->a_data;
	addr = LOADSTART;
	/*
	 * load first part of the boot loader at location LOADSTART
	 */
	do {
		fread ( &word, sizeof word, 1, infile);
		if ( addr == LOADSTART ) {
			sprintf(buf,"%o/",addr+loc);
			sendodt(Devfd,buf,TRUE);
		} else
			sendodt(Devfd,"\n",TRUE);
		readuntil(Devfd," ?", buf, 7);
		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);
	/*
	 * send the boot loader in reverse order
	 */
	stack = (char *)malloc(length);
	stklen = 0;
	while ( addr+stklen < length )
		stack[stklen++] = getc(infile);
	setreg(Devfd,0,MAXADDR);
	setreg(Devfd,1,stklen);
        setreg(Devfd,7,LOADSTART);
        setreg(Devfd,-1,INTDISABLE);
        sendodt(Devfd,"P", FALSE);
        sleep(1);
	for ( i=stklen-1 ; i>=0 ; i-- ) {
		write(Devfd, &stack[i], 1);
		if ( A.verbose )
			printf("%03o ",stack[i]&0xff);
	}
        if ( A.verbose )
                printf("\n");
	readuntil(Devfd,"@",buf,5);
}

/*
 *==============================================
 * 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 ( reg >= 0 )
                sprintf(buf,"R%d/",reg);
        else
                sprintf(buf,"$S/");
	sendodt(fd,buf,TRUE);
        if ( !A.silent && !A.verbose )
                displayreg(reg);
	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)
char *str;
{
	if ( !A.silent )
		puts(str);
}

/*
 *================================
 * fastload - load user program
 *================================
 */

FILE *Fastline;
char Fastbuf[BUFSIZ];

fastload(fd,ahdr)
int fd;
struct exec *ahdr;
{
        int words, addr, length, total;
	FILE *infile;
	lsiword buf[PACKSIZE];
	char resp;

	words = (ahdr->a_text+ahdr->a_data) / sizeof (lsiword);
	Fastline = fdopen(Devfd,"w");
	setbuf(Fastline,Fastbuf);
	infile = fdopen(fd,"r");
	fseek(infile, (long) sizeof (struct exec), 0);
	addr = LOADSTART;
	while ( words > 0 ) {
		length = (words>PACKSIZE ? PACKSIZE : words);
		fread(buf,sizeof(lsiword),length,infile);
		do {
			sendpack(addr,length,buf);
                        settimer(6, "fastload read timed out");
                        if ( read ( Devfd, &resp, 1) != 1 ) {
				perror(Openfiles[Devfd]);
				exit(1);
                        }
                        canceltimer();
                        if ( A.verbose )
                                printf("response is %s\n",unctrl(resp));
                        else if ( resp == NAK )
                                fprintf(stderr,"NAK\n");
		} while ( resp != ACK );

		addr += length * sizeof (lsiword);
		words -= length;
                if ( !A.silent && !A.verbose )
                        displayval(words);
	}
        if ( !A.silent && !A.verbose ) {
                displayval(0);
                printf("\r");
        }
        sendpack ( addr, 0, buf );
}

/*
 *=========================================
 * sendpack - send a packet to the LSI-11
 *=========================================
 */

#define putwsum(w) putw(w), sum += w
#define rawputc(c) putc(c,Fastline)

sendpack(addr, length, buf)
int addr, length;
lsiword *buf;
{
	int sum, i;
        if ( A.verbose ) {
                printf("Sending packet addr=%6o len=%d\n",addr,length);
                for ( i=0 ; i<length ; i++ )
                        printf("%03o ",buf[i]&0xff);
                printf("\n");
        }
	rawputc(SOH);
	sum = 0;
	putwsum(addr);
	putwsum(length);
	for ( i=0 ; i<length ; i++ )
		putwsum(buf[i]);
        if ( A.verbose )
                printf("sum is %d\n",(-sum)&0xffff);
        putwsum((-(lsiword)sum));
	fflush(Fastline);
}
/*
 *=============================================
 * putw - write a word to the high speed line
 *=============================================
 */
putw(word)
lsiword word;
{
	putch((char)(word&0xff));
	putch((char)((word>>8)&0xff));
}
/*
 *=================================================
 * putch - put a character on the high speed line
 *=================================================
 */
putch(ch)
char ch;
{
	if ( ch == ESC || ch == SOH )
		rawputc(ESC);
	rawputc(ch);
}

/*
 *========================================
 * autostart - implement startup options
 *========================================
 */
autostart(fd,hdr)
int fd;
struct exec *hdr;
{
	int i;
	char buf[32];

	if ( !A.autostart ) {
		readuntil(fd, "@", buf, 2);
		setreg(fd, 7, (i=hdr->a_entry & (~1)) );
		setreg(fd, 6, hdr->a_text + hdr->a_data + hdr->a_bss + 6);
		setreg(fd, -1, INTDISABLE);
		if ( !A.silent )
			printf("\rStart at 0%o\n",i);
	}
}
/*
 *============================================
 * displayval - display a number on one line
 *============================================
 */
displayval(val)
int val;
{
	char buf[32];
	sprintf(buf,"%d",val);
	strncat(buf,"        ",8-strlen(buf));
	printf("\r%s",buf);
	fflush(stdout);
}
/*
 *==============================================
 * displayreg - display a register on one line
 *==============================================
 */
displayreg(val)
int val;
{
	char buf[32];
        if ( val < 0 )
                strcpy(buf,"PS");
        else
                sprintf(buf,"R%d",val);
        strncat(buf,"        ",8-strlen(buf));
	printf("\r%s",buf);
	fflush(stdout);
}