Xinu7/src/cmd/download/vax/src/sdl.c
/*----------------------------------------------------------------------*/
/* */
/* sdl -- Download to VAX over Serial Line */
/* */
/* This program takes VAX a.out format files and downloads them */
/* into a VAX. */
/* */
/* Usage: */
/* (This program is exec'd by download; the following arguments are */
/* accepted by download:) */
/* download [file] [-cCLASS] [-lLSI#] [-a[delay]] */
/* [-Bbaudrate] [-a[# of Secs]] [-h] [-v] [-s] */
/* */
/* Author: */
/* Tom Stonecypher */
/* based on the PDP-11 downloader, written by: */
/* R. Brown, Doug Comer, D. Hachigian */
/* Purdue University CS Deptartment */
/* */
/* (c) Copyright, 1986, All rights reserved. */
/* */
/*----------------------------------------------------------------------*/
/* Include files - Unix domain */
#include "/usr/include/errno.h"
#include "/usr/include/setjmp.h"
#include "/usr/include/signal.h"
#include "/usr/include/sgtty.h"
#include "/usr/include/stdio.h"
#include "/usr/include/sys/file.h"
#include "/usr/include/sys/types.h"
#include "/usr/include/ctype.h"
#include "/usr/include/a.out.h"
/* Include files - XINU domain */
#include <getdev.h>
#include <download.h>
#include <vaxdl.h>
#include <ethdown.h>
struct arglist A;
jmp_buf env; /* used to return from read time-outs */
static char *alarm_msg; /* message printed when alarm signalled */
char *Openfiles[MAXFILES]; /* open file names for error reporting */
char *locknm; /* name of lock file */
extern int errno;
/*
* MAIN -- download user's program from host into VAX's memory
*/
main ( argc, argv )
int argc;
char *argv[];
{
char *machine, *cputype;
struct exec aouthdr;
locknm = argv[--argc];
machine = argv[--argc];
/* cputype = get_cputype(machine); */
procargs(argc, argv); /* process arguments into struct A */
initsigs();
Openfiles[DEVFD] = get_name(machine);
Openfiles[AOUTFD] = A.filename;
gethdr(AOUTFD, &aouthdr, TRUE);
serial_load(AOUTFD, LOADSTART, &aouthdr, A.startdelay);
touch(locknm);
message("done ");
printstart(&aouthdr);
callexit(0);
}
/*
*====================================================================
* procargs - parse and check command line, setup global A structure
*====================================================================
*/
procargs(argc, argv)
int argc;
char *argv[];
{
int arg, i;
A.filename = DEFFILE;
A.baudrate = B9600;
A.class = NULL;
A.machnum = GD_ANYDEV;
A.devflags = FALSE;
A.reloadether = FALSE;
A.verbose = FALSE;
A.silent = FALSE;
A.autostart = FALSE;
A.startdelay = NOAUTOSTART;
for ( arg=1 ; arg<argc ; arg++ ) {
if ( argv[arg][0] == '-' ) {
switch ( argv[arg][1] ) {
case 'l':
A.machnum=atoi(argv[arg]+2);
break;
case 'h':
A.devflags |= GD_HLDDEVS;
break;
case 'e':
A.reloadether = TRUE;
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:
break; /* ignore other args */
}
} else
A.filename = argv[arg];
}
}
/*
*=================================================================
* initsigs - prepare to reset on an interrupt & setup for alarms
*=================================================================
*/
initsigs()
{
int alarmhandler(), inthandler();
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);
}
/*=======================================================================
* serial_load - download an a.out image over serial line
*=======================================================================
* input state: <undefined>
* output state: a.out in memory, executing autostart else cpu halted
*/
serial_load(aout_fd, load_addr, aout_hdr, delay)
int aout_fd;
char *load_addr;
struct exec *aout_hdr;
int delay;
{
int ldrfd;
struct exec ldr_hdr;
ldrfd = openfile(VAXLOADER, O_RDONLY);
gethdr(ldrfd, &ldr_hdr, FALSE);
initcpu();
message("loading boot program...");
bootload(aout_hdr, ldrfd, &ldr_hdr, delay);
slowload(aout_fd, aout_hdr, load_addr);
close(ldrfd);
}
/*
*=============================================
* bootload - load bootstrap loader via console
*=============================================
* input state: after console prompt, cpu initialized (interrupts disabled)
* output state: same, bootstrap loader in memory and running
*/
bootload(aout_hdr, fdin, ldr_hdr, delay)
int fdin, delay;
struct exec *aout_hdr, *ldr_hdr;
{
FILE *infile;
int length, stklen, i, ph0len;
unsigned long val;
char buf[32], *stack, ch, resp;
infile = fdopen(dup(fdin),"r");
fseek(infile, N_TXTOFF(*ldr_hdr),0);
length = ldr_hdr->a_text + ldr_hdr->a_data;
/*
* load phase1 of the boot loader at location P0BSTRT.
*/
fread (&val, sizeof val, 1, infile);
sprintf(buf, "D/L/P %x %x\r",P0BSTRT, val); /* initialize console */
sendcons(buf, TRUE);
getprompt(6);
fread ( &val, sizeof val, 1, infile);
ph0len = sizeof (unsigned long) * 2;
while ( val != (unsigned)0xffffffff ) {
sprintf(buf, "D + %x\r", val);
sendcons(buf, TRUE);
getprompt(6);
if ( !A.silent && ! A.verbose )
displayval(ph0len);
fread ( &val, sizeof val, 1, infile);
ph0len += sizeof (unsigned long);
}
if ( !A.silent && !A.verbose )
fprintf(stderr,"\r");
sendcons("\r",TRUE);
getprompt(5);
/*
* send the boot loader in reverse order, remove trailing zeros
*/
stack = (char *)malloc(length);
for (stklen = 0; ph0len+stklen < length; stklen++)
stack[stklen] = getc(infile);
setreg(0, stklen);
setreg(1, HIADDR);
setreg(2, delay);
setreg(3, aout_hdr->a_entry);
sprintf(buf, "S %x\r", P0BSTRT);
sendcons(buf, TRUE);
usleep(1000000);
buf[0] = ESC;
/* escape bytes for big VAXen */
for ( i=stklen-1 ; i>=0 ; i-- ) {
if( (ch = stack[i])==CNSINTRC || ch==CNSINTRC2 || ch==ESC ) {
buf[1] = ch|STUFFBIT;
write(DEVFD, buf, 2);
} else
write(DEVFD, &ch, 1);
if ( A.verbose )
fprintf(stderr,"%03x ",stack[i]&0xff);
}
if ( A.verbose )
fprintf(stderr,"\n");
}
/*
*============================================
* getserack - get an ack from destination VAX
*============================================
*/
getserack()
{
char ch;
settimer(6, "getack read timed out");
if (setjmp(env) == EINTR)
callexit(1);
else if (read(DEVFD, &ch, 1) < 0) {
perror(Openfiles[DEVFD]);
message("getserack: no ack");
ch = EOS;
} else
canceltimer();
if (A.verbose)
fprintf(stderr,"IN(getack): %s\n", unctrl(ch));
return(ch);
}
FILE *Slowline;
char Slowbuf[BUFSIZ];
/*============================================================
* slowload - load user program via packets over serial line
*============================================================
* input state: serial downloader running, ready to receive packets
* output state: a.out file loaded into memory; a.out running if auto-
* start, before console prompt if no autostart
*/
slowload(aoutfd, ahdr, load_addr)
int aoutfd;
struct exec *ahdr;
int load_addr;
{
int words, addr, length;
FILE *infile;
unsigned short buf[PACKSIZE];
char resp;
words = (ahdr->a_text+ahdr->a_data) / sizeof (unsigned short);
Slowline = fdopen(DEVFD,"w");
setbuf(Slowline,Slowbuf);
infile = fdopen(aoutfd,"r");
fseek(infile, N_TXTOFF(*ahdr), 0);
addr = load_addr;
while ( words > 0 ) {
length = (words>PACKSIZE ? PACKSIZE : words);
fread(buf,sizeof(unsigned short),length,infile);
do {
sendserpack(addr,length,buf);
settimer(6, "slowload read timed out");
if (setjmp(env) == EINTR)
callexit(1);
if ( read ( DEVFD, &resp, 1) != 1 ) {
perror(Openfiles[DEVFD]);
exit(1);
}
canceltimer();
if ( A.verbose )
fprintf(stderr,"response is %s\n",unctrl(resp));
else if (resp == NAK )
fprintf(stderr,"NAK\n");
} while ( resp != ACK );
addr += length * sizeof (unsigned short);
words -= length;
if ( !A.silent && !A.verbose )
displayval(words);
}
if ( !A.silent && !A.verbose ) {
displayval(0);
fprintf(stderr,"\r");
}
do {
sendserpack ( addr, 0, buf );
} while (getserack() != ACK);
}
/*
*====================================
* sendserpack - send a packet to the VAX
*====================================
*/
#define putwsum(w) putw(w), sum += w
#define rawputc(c) putc(c, Slowline)
sendserpack(addr, length, buf)
unsigned int addr, length;
unsigned short *buf;
{
short sum;
int i;
if ( A.verbose ) {
fprintf(stderr,"Sending packet addr=%8x len=%d\n",addr,length);
for ( i=0 ; i<length ; i++ )
fprintf(stderr,"%02x ",buf[i]&0xff);
fprintf(stderr,"\n");
}
rawputc(SOH);
sum = 0;
putwsum(addr & LOW16); /* put low word of address */
putwsum(addr>>16); /* put high word of address */
putwsum(length);
for ( i=0 ; i<length ; i++ )
putwsum(buf[i]);
if ( A.verbose )
fprintf(stderr, "sum is %d\n", -sum);
putwsum(-sum);
fflush(Slowline);
}
/*
*==================================================
* putw - write a word to the slow-speed serial line
*==================================================
*/
putw(word)
unsigned short word;
{
putch((char)(word&LOWBYTE));
putch((char)((word>>8)&LOWBYTE));
}
/*
*==============================================================
* putch - put a character on the high speed line, with escaping
*==============================================================
*/
putch(ch)
char ch;
{
if ( ch == ESC || ch == SOH || ch == CNSINTRC || ch == CNSINTRC2 ) {
rawputc(ESC);
rawputc(ch|STUFFBIT);
} else
rawputc(ch);
}
/*
*===================================================
* printstart - print start location for serial loads
*===================================================
*/
printstart(hdr)
struct exec *hdr;
{
if ( !A.autostart && !A.silent )
fprintf(stderr,"\rHalt the cpu, then start at 0x%x\n",
hdr->a_entry+sizeof(short));
}
/*
*================================
* gethdr - read an a.out header
*================================
*/
gethdr(fd, hdr, cfile)
int fd;
struct exec *hdr;
Bool cfile;
{
if ( read(fd, hdr, sizeof *hdr) != sizeof *hdr) {
fprintf(stderr,"%s: EOF reading a.out header\n",Openfiles[fd]);
callexit(1);
}
if (cfile && hdr->a_magic != NMAGIC && hdr->a_magic != ZMAGIC ) {
fprintf(stderr,"%s: wrong magic number\n",Openfiles[fd]);
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 (setjmp(env) == EINTR)
callexit(1);
if ((fd=open(name,mode)) < 0 ) {
perror(name);
callexit(1);
}
canceltimer();
Openfiles[fd] = name;
return(fd);
}
/*
*==================================================
* readuntil - read from line until some character
*==================================================
*/
readuntil ( ch, time )
char ch;
int time;
{
char input;
settimer(time, "\rread timed out");
if (setjmp(env) == EINTR) {
fprintf(stderr, "readuntil did not find %s\n", unctrl(ch));
callexit(1);
}
if ( A.verbose ) {
fprintf(stderr,"IN: "); fflush(stderr);
}
do {
if ( read(DEVFD, &input, 1) != 1 ) {
perror(Openfiles[DEVFD]);
callexit(1);
}
if (A.verbose ) {
fprintf(stderr,"%s",unctrl(input)); fflush(stderr);
}
} while ( input == EOS || input != ch);
canceltimer();
if ( A.verbose )
fprintf(stderr,"\n");
}
/*
*=========================================
* alarmhandler - return from alarm calls
*=========================================
*/
alarmhandler()
{
signal(SIGALRM, alarmhandler);
if (alarm_msg != NULL)
fprintf(stderr, "%s\n", alarm_msg);
longjmp(env, EINTR);
/* not reached */
}
/*
*=====================================
* inthandler -- interrupt processing
*=====================================
*/
inthandler()
{
touch(locknm);
callexit(2);
}
/*
*=======================================
* callexit - restore ttymodes and exit
*=======================================
*/
callexit(ret)
int ret;
{
exit(ret);
}
/*
*==================================================
* sendcons - send a message to console half duplex
*==================================================
*/
sendcons(msg, wait)
char *msg;
Bool wait;
{
char *ptr;
ptr = msg;
while (*msg!=EOS) {
if (islower(*msg))
*msg = *msg - 32;
write(DEVFD,msg,1);
if ( wait )
readuntil(*msg, 6);
msg++;
}
if ( A.verbose ) {
fprintf(stderr,"OUT: ");
while (*ptr!=EOS) {
fprintf(stderr,"%s",unctrl(*ptr));
ptr++;
}
fprintf(stderr,"\n");
}
}
/*
*================================================
* setreg - preload a register through VAX console
*================================================
*/
setreg(reg, value)
int reg, value;
{
char buf[32];
/* there's no machine-independent way to load PSL, so let */
/* console Initialize command take care of that */
if (reg == KSPREG)
sprintf (buf, "D/I 0 %x\r", value);
else if ( reg >= 0 ) /* general register */
sprintf(buf,"D/G %x %x\r", reg, value);
else /* internal privileged register -reg */
sprintf(buf, "D/I %x %x\r", -reg, value);
sendcons(buf, TRUE);
if ( !A.silent && !A.verbose )
displayreg(reg);
getprompt (6);
}
/*
*===================================
* getprompt - get VAX console prompt
*===================================
*/
getprompt (time)
int time;
{
int i;
for (i=0; i<3; i++)
readuntil ('>', time);
}
/*
*======================================================
* initcpu - get VAX console's attention, initialize cpu
*======================================================
* Input state - undefined
* Output state - immediately after VAX console prompt
*/
initcpu()
{
message("getting console");
/* get console, if it's a big VAX */
write(DEVFD, CONSKILL, 1); /* ^U erases current cmd. line */
write(DEVFD, CONSABRT, 1); /* ^C enables console input */
write(DEVFD, CONSINTR, 1); /* ^P breaks to console mode */
usleep(100000);
/* get console, if it's a UVAX */
ioctl(DEVFD, TIOCSBRK, NULL);
usleep(300000);
ioctl(DEVFD, TIOCCBRK, NULL);
/* now have console, initialize cpu */
getprompt(15);
sendcons(CPUHALT, TRUE); /* halt the processor */
sendcons("\r", TRUE);
getprompt(6);
sendcons(CPUNJAM, TRUE); /* unjam bus */
getprompt(15); /* high waits for big VAXen */
sendcons(CPUINIT, TRUE); /* init: interrupts disab, etc. */
getprompt(15); /* takes a while on big VAXen */
}
/*
*============================================================
* setmem - load a 32-bit memory location through VAX console
*============================================================
*/
setmem(loc, value)
int loc, value;
{
char buf[128];
sprintf(buf,"D/L/P %x %x\r",loc,value);
sendcons(buf, TRUE);
getprompt(6);
}
/*
*=================================================
* message - conditionally display status message
*=================================================
*/
message(str)
char *str;
{
if ( !A.silent ) {
fprintf(stderr,"\r%s\n",str);
}
}
/*
*============================================
* displayval - display a number on one line
*============================================
*/
displayval(val)
int val;
{
fprintf(stderr,"\r%d ",val);
fflush(stderr);
}
/*
*==============================================
* displayreg - display a register on one line
*==============================================
*/
displayreg(val)
int val;
{
if ( val < 0 )
fprintf(stderr,"\rPS ");
else
fprintf(stderr,"\rR%d ",val);
fflush(stderr);
}