Xinu7/src/cmd/download/lsi11/src/edl.c
/*----------------------------------------------------------------------*/
/* */
/* edl -- Download to PDP-11 over Ethernet */
/* */
/* This program takes PDP-11 a.out format files and downloads them */
/* into a PDP-11. */
/* */
/* 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] */
/* */
/* Authors: */
/* Version One: R. Brown, Doug Comer */
/* Purdue University/CS Deptartment */
/* September, 1981 - Nov. 1983 */
/* */
/* Version Two: Dan Hachigian */
/* Doug Comer, eload (LSI side) */
/* Modified to handle ethernet downloading, February, 1986 */
/* Modified to use new device database alloc. scheme, Spring 86 */
/* Significant structure reorganization, Spring 86 */
/* */
/* Version Three: Tom Stonecypher 10/86 */
/* Implemented stateless memory server protocol */
/* Longjmp botches fixed, output format fixed, power-up */
/* Initialization of memory-map unit fixed */
/* Modified to allow download to exec this program */
/* Structure reorganized: serial downloader modularized */
/* */
/* (c) Copyright, 1982, All rights reserved. */
/* (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"
/* 4.2 Network include files */
#include "/usr/include/netinet/in.h"
#include "/usr/include/sys/socket.h"
#include "/usr/include/netdb.h"
/*----------------------------------------------------------*/
/* Include files - XINU domain */
/*----------------------------------------------------------*/
#include <a.out.h>
#include <getdev.h>
#include <download.h>
#include <dlpack.h>
#include <lsidl.h>
#include <ethdown.h>
#include "../eload/src/.version"
#include "../eload/src/.entry"
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;
extern int errno;
int Sfd; /* socket descriptor for upd write/reads*/
/*
* MAIN -- download user's program from host into LSI's memory
*/
main ( argc, argv )
int argc;
char *argv[];
{
char *machine, *cputype;
int eloadfd, fMap, retry;
u_long lsi_ip;
struct exec ehdr, 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;
getudp_port(&lsi_ip, machine);
if (lsi_ip != 0) { /* do an ethernet download */
retry = 0;
fMap = MAPMEM;
gethdr(AOUTFD, &aouthdr);
do {
if ( A.reloadether || retry == 1 ) {
if (!A.verbose && !A.silent)
fprintf(stderr,"%sloading eload...\n",
(A.reloadether?NULL:"re"));
eloadfd = openfile(ELOAD, O_RDONLY);
gethdr(eloadfd, &ehdr);
serial_load(eloadfd, &ehdr, NOAUTOSTART);
readuntil('@', 10);
fMap = NOMAP;
}
if (ethload(&aouthdr, lsi_ip, fMap) == ETH_OK)
break;
lseek(AOUTFD, sizeof(aouthdr), 0);
} while (++retry == 1 && !A.reloadether);
}
if (lsi_ip == 0 || retry == 2 || (retry == 1 && A.reloadether)) {
message("performing serial download...");
serial_load(AOUTFD, &aouthdr, A.startdelay);
initstart(&aouthdr);
}
touch(locknm);
message("\rdone ");
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 if autostart else cpu halted
*/
serial_load(aout_fd, aout_hdr, delay)
int aout_fd;
struct exec *aout_hdr;
int delay;
{
int ldrfd;
struct exec ldr_hdr;
/* place bootloader in memory */
ldrfd = openfile(LSILOADER, O_RDONLY);
gethdr(ldrfd, &ldr_hdr);
getodt();
setmem(SR0_ADDR, DISABLE_MMU);
message("\rloading boot program...");
bootload(ldrfd, &ldr_hdr, 0);
close(ldrfd);
start_ldr(aout_hdr, delay);
slowload(aout_fd, aout_hdr);
}
/*
*===========================================
* 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, j, 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(buf,TRUE);
} else
sendodt("\n",TRUE);
readuntil(' ', 7);
sprintf(buf,"%o",word&0xffff);
sendodt(buf,TRUE);
if ( !A.silent && ! A.verbose )
displayval(addr);
addr += sizeof (lsiword);
} while ( word != 0177777 );
if ( !A.silent && ! A.verbose )
fprintf(stderr,"\r");
sendodt("\r",TRUE);
readuntil('@',5);
/*
* send the boot loader in reverse order
*/
stack = (char *)malloc(length);
stklen = 0;
while ( addr+stklen < length )
stack[stklen++] = getc(infile);
setreg(0,MAXADDR);
setreg(1,stklen);
setreg(7,LOADSTART);
setreg(-1,INTDISABLE);
sendodt("P", FALSE);
usleep(200000);
for ( i=stklen-1 ; i>=0 ; i-- ) {
write(DEVFD, &stack[i], 1);
if ( A.verbose )
fprintf(stderr,"%03o ",stack[i]&0xff);
}
if ( A.verbose )
fprintf(stderr,"\r");
readuntil('@',5);
}
/*==================================================================
* start_ldr - load arguments to serial downloader and start it up
*==================================================================
* input state: after odt prompt, serial loader in memory
* output state: downloader running, ready to receive packets
*/
start_ldr(hdr, delay)
struct exec *hdr;
int delay;
{
setreg(1, hdr->a_bss);
setreg(2, delay);
setreg(3, hdr->a_entry & (~1));
setreg(4, LSIPORT);
message("\rstarting boot loader...");
sendodt("P", TRUE);
}
/*===============================================================
* getserack - get an ack from serial downloader over serial line
*===============================================================
*/
char getserack()
{
char resp;
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 (resp == NAK)
fprintf(stderr,"NAK\n");
else if (A.verbose && resp == ACK)
fprintf(stderr, "ACK\n");
else if (A.verbose)
fprintf(stderr,"response is %s\n",unctrl(resp));
return(resp);
}
/*============================================================
* 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 odt prompt if no autostart
*/
FILE *Fastline;
char Fastbuf[BUFSIZ];
slowload(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
sendserpack(addr,length,buf);
while ( getserack() != ACK );
addr += length * sizeof (lsiword);
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);
}
/*
*=================================================================
* initstart - initialize startup register value for serial loads
*=================================================================
* input state: before odt prompt
* output state: after odt, a.out setup to run
*/
initstart(hdr)
struct exec *hdr;
{
int i;
if ( !A.autostart ) {
readuntil('@', 2);
setreg(7, (i=hdr->a_entry & (~1)) );
setreg(6, hdr->a_text + hdr->a_data + hdr->a_bss + 6);
setreg(-1, INTDISABLE);
if ( !A.silent )
fprintf(stderr,"\nStart at 0%o\n",i);
}
}
/*
*============================================================================
* getudp_port - get a udp port connected to the lsi port for packet transfer
*============================================================================
*/
getudp_port(lsi_ip, machine)
u_long *lsi_ip;
char *machine;
{
struct sockaddr_in sin, sout;
struct hostent *phost;
char *hostname;
hostname = get_hname(machine);
if (isdigit(*hostname)) /* IP dot notation instead of name */
*lsi_ip = inet_addr(hostname);
else { /* hostname format */
phost = gethostbyname(hostname);
if ((char *)phost != NULL && phost->h_addrtype == AF_INET)
bcopy(phost->h_addr, lsi_ip, sizeof lsi_ip);
else
*lsi_ip = 0;
}
if ((Sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("creating socket");
callexit(1);
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
if (bind(Sfd, (caddr_t) &sin, sizeof(sin)) < 0) {
perror("bind");
callexit(1);
}
sout.sin_family = AF_INET;
sout.sin_addr.s_addr = *lsi_ip;
sout.sin_port = htons((u_short) DLUDP);
if (connect(Sfd, &sout, sizeof(sout)) < 0) {
perror("connect");
callexit(1);
}
}
/*============================================================================
* start_eload - init lsi and start up eload (have memory mapped if requested)
*============================================================================
* input state: after the odt prompt
* output state: undefined (waiting for an ack from eload)
*/
start_eload(ip_addr, fMapMem)
u_long ip_addr;
int fMapMem;
{
getodt();
message("\rstarting resident loader...");
setreg(PSW, INTDISABLE);
if (fMapMem == MAPMEM)
map_mem();/* phys 7 to virt 0, I/O to virt 7 */
else
load_args(ip_addr);
setreg(SP, ETH_INITSP);
setreg(PC, ETH_INITPC & (~1));
sendodt("P", TRUE);
}
/*
*===============================================================
* load_args - put arguments to ELOAD into the appropriate locs
*===============================================================
*/
load_args(lsi_ip)
u_long lsi_ip;
{
setmem(0, lsi_ip & 0xffff);
setmem(2, lsi_ip >> 16 & 0xffff);
}
/*
*========================================================
* map_mem - set up virtual memory before starting eload
*========================================================
*/
map_mem()
{
setmem(PAR0_ADDR, PAR0_VAL); /* par0 -> physical 7 */
setmem(PAR7_ADDR, PAR7_VAL); /* par7 -> I/O space */
setmem(PDR0_ADDR, PDR_VAL); /* page len=8K, RW access */
setmem(PDR7_ADDR, PDR_VAL);
setmem(SR3_ADDR, 0); /* 18-bit bus addresses */
setmem(SR0_ADDR, ENABLE_MMU);
}
/*
*================================
* 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);
}
}
/*
*==========================================================
* 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);
}
/*
*===============================
* getodt - get ODT's attention
*===============================
* Input state - undefined -- nothing valid in memory
* Output state - immediately after ODT prompt
*/
getodt()
{
message("\rgetting odt...");
ioctl(DEVFD, TIOCSBRK, NULL);
usleep(300000);
ioctl(DEVFD, TIOCCBRK, NULL);
/* reset machine state -- necessary after power-up */
readuntil('@',10);
setmem(SR0_ADDR, DISABLE_MMU);
setmem(0, 5); /* place a reset instruction at 0 */
setmem(2, 0); /* place a halt after it */
setreg(PSW, INTDISABLE);/* (reset disables MMU) */
setreg(PC, 0);
sendodt("P", FALSE); /* reset machine state */
readuntil('@',10);
}
/*
*==================================================
* readuntil - read from line until some character
*==================================================
*/
readuntil ( ch, time )
char ch;
int time;
{
char lastch, input;
settimer(time, "read 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);
}
input = ' ';
do {
lastch = input;
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");
if (ch == '@' && lastch == '^')
readuntil(ch, time);
}
/*
*=========================================
* 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);
}
/*
*==============================================
* sendodt - send a message to ODT half duplex
*==============================================
*/
sendodt(msg, wait)
char *msg;
Bool wait;
{
char *ptr;
if ( A.verbose ) {
fprintf(stderr,"OUT: ");
for ( ptr=msg ; *ptr!=EOS ; ptr++ ) {
fprintf(stderr,"%s",unctrl(*ptr));
}
fprintf(stderr,"\n");
}
while (*msg!=EOS) {
write(DEVFD,msg,1);
if ( wait )
readuntil(*msg, 10);
msg++;
}
}
/*
*==========================================
* setreg - preload a register through ODT
*==========================================
*/
setreg(reg, value)
int reg, value;
{
char buf[32];
if ( reg >= 0 )
sprintf(buf,"R%d/",reg);
else
sprintf(buf,"$S/");
sendodt(buf,TRUE);
readuntil(' ',5);
sprintf(buf,"%o\r",value&0xffff);
sendodt(buf,TRUE);
readuntil('@',5);
}
/*
*==============================================
* setmem - preload a mem location through ODT
*==============================================
*/
setmem(loc, value)
int loc, value;
{
char buf[32];
sprintf(buf,"%o/",loc);
sendodt(buf,TRUE);
readuntil(' ',5);
sprintf(buf,"%o\r",value&0xffff);
sendodt(buf,TRUE);
readuntil('@',5);
}
/*
*=================================================
* message - conditionally display status message
*=================================================
*/
message(str)
char *str;
{
if ( !A.silent ) {
fprintf(stderr,"%s\n",str);
}
}
/*
*===========================================================
* sendserpack - send a packet to the LSI-11 over serial line
*===========================================================
*/
#define putwsum(w) putw(w), sum += w
#define rawputc(c) putc(c,Fastline)
sendserpack(addr, length, buf)
int addr, length;
lsiword *buf;
{
int sum, i;
if ( A.verbose ) {
fprintf(stderr,"Sending packet addr=%6o len=%d\n",addr,length);
for ( i=0 ; i<length ; i++ )
fprintf(stderr,"%03o ",buf[i]&0xff);
fprintf(stderr,"\n");
}
rawputc(SOH);
sum = 0;
putwsum(addr);
putwsum(length);
for ( i=0 ; i<length ; i++ )
putwsum(buf[i]);
if ( A.verbose )
fprintf(stderr,"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);
}
/*
*============================================
* 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);
}
struct dl_pack ackdl;
/*
*=============================================
* getack - get an ack from ELOAD over ethernet
*=============================================
*/
struct dl_pack *getack()
{
char *ackmsg;
settimer(ACKTIME, NULL);
if (setjmp(env) == EINTR) /* timed out */
return(NULL);
if (read(Sfd, &ackdl, sizeof ackdl) < 0) {
perror("udp packet read");
callexit(1);
}
canceltimer();
if (A.verbose) {
switch (ackdl.dl_hdr.dl_op) {
case DLACK:
ackmsg = "ACK";
break;
case DLNAK:
ackmsg = "NAK";
break;
case DLRAK:
ackmsg = "ready-ack";
break;
case DLQAK:
ackmsg = "quit-ack";
break;
default:
ackmsg = "invalid ack command";
break;
}
fprintf(stderr,"IN(getack): %s, addr = 0%o\n", ackmsg,
ntohl(ackdl.dl_hdr.dl_addr));
}
return(&ackdl);
}
/*
*===========================================
* ethload - download program over ethernet
*===========================================
*/
ethload(aouthdr, lsi_ip, fMapMem)
int lsi_ip, fMapMem;
struct exec *aouthdr;
{
u_short addr, len, i;
int aoutsize, iNak, version, bsslen;
struct dl_pack packet, *pDlAck;
start_eload(lsi_ip, fMapMem);
build_dlpack(DLID, 0, 0, &packet);
usleep(400000);
for (iNak = 0; iNak < ETHRETRY; iNak++ ) {
if (iNak > 0)
fprintf(stderr,"\rretrying...");
send_dlpack(Sfd, &packet);
pDlAck = getack();
if (pDlAck != NULL && pDlAck->dl_hdr.dl_op == DLRAK)
break;
}
if (iNak == ETHRETRY) {
message("can't start eload");
return(ETH_FAILED);
}
if ((version = pDlAck->dl_hdr.dl_vers & LOWBYTE) != VERSION &&
version != ROMVERS) {
message("version mismatch");
return(ETH_FAILED);
}
aoutsize = aouthdr->a_text + aouthdr->a_data;
addr = LOADSTART;
while (aoutsize > 0) {
len = aoutsize > DLMAXD ? DLMAXD : aoutsize;
build_dlpack(DLDEP, len, addr, &packet);
for (iNak = 0; iNak < ETHRETRY; iNak++ ) {
if (iNak > 0)
fprintf(stderr,"\rretrying...");
send_dlpack(Sfd, &packet);
pDlAck = getack();
/* test for ACK & correct address sequence number */
if (pDlAck != NULL && pDlAck->dl_hdr.dl_op == DLACK &&
ntohl(pDlAck->dl_hdr.dl_addr) == addr)
break;
}
if (iNak == ETHRETRY) {
message("ethernet download failed");
return(ETH_FAILED);
}
if (!A.silent && !A.verbose)
if ((addr % 020000) == 0 ) {
fprintf(stderr,
"\rpage %d ",
addr/020000);
fflush(stderr);
}
addr += len;
aoutsize -= len;
}
/* now zero out the bss */
bsslen = aouthdr->a_bss;
for (i = 0; i <= DLMAXD; i++)
packet.dl_pt.dl_data[i] = '\0';
packet.dl_hdr.dl_vers = VERSION;
packet.dl_hdr.dl_op = DLDEP;
while (bsslen > 0) {
len = bsslen > DLMAXD ? DLMAXD : bsslen;
packet.dl_hdr.dl_len = htons(len);
packet.dl_hdr.dl_addr = htonl(addr);
for (iNak = 0; iNak < ETHRETRY; iNak++ ) {
if (iNak > 0)
fprintf(stderr,"\rretrying...");
send_dlpack(Sfd, &packet);
pDlAck = getack();
/* test for ACK & correct address sequence number */
if (pDlAck != NULL && pDlAck->dl_hdr.dl_op == DLACK &&
ntohl(pDlAck->dl_hdr.dl_addr) == addr)
break;
}
if (iNak == ETHRETRY) {
message("ethernet download failed");
return(ETH_FAILED);
}
if (!A.silent && !A.verbose)
if ((addr % 020000) == 0 ) {
fprintf(stderr,
"\rpage %d ",
addr/020000);
fflush(stderr);
}
addr += len;
bsslen -= len;
}
/* now instruct eload to perform specified autostart option */
packet.dl_pt.dl_srt.dl_entry = htonl(aouthdr->a_entry &(~1));
packet.dl_pt.dl_srt.dl_delay = htonl(A.startdelay);
build_dlpack(DLSRT, 0, 0, &packet);
for ( iNak = 0; iNak < ETHRETRY; iNak++ ) {
if (iNak > 0)
fprintf(stderr,"\rretrying...");
send_dlpack(Sfd, &packet);
pDlAck = getack();
if (pDlAck != NULL && pDlAck->dl_hdr.dl_op == DLQAK)
break;
}
return(iNak < ETHRETRY ? ETH_OK : ETH_FAILED);
}
/*
*=============================================================
* build_dlpack - construct a packet in ether download format
*=============================================================
*/
build_dlpack(op, datalen, addr, packet)
char op;
unsigned short datalen;
unsigned long addr;
struct dl_pack *packet;
{
int i;
packet->dl_hdr.dl_op = op;
packet->dl_hdr.dl_vers = VERSION;
switch (op) {
case DLDEP:
packet->dl_hdr.dl_len = htons(datalen);
packet->dl_hdr.dl_addr = htonl(addr);
if (datalen > 0)
if ( read(AOUTFD, packet->dl_pt.dl_data, datalen)
< datalen ) {
fprintf(stderr, "read error\n");
callexit(1);
}
break;
case DLSRT:
case DLID:
break;
default:
fprintf(stderr, "build_dlpack: invalid output packet type\n");
break;
}
}
/*
*============================================================
* send_dlpack - send a downloader format packet out via UDP
*============================================================
*/
send_dlpack(sockfd, dlpacket)
int sockfd;
struct dl_pack *dlpacket;
{
unsigned short len;
unsigned long addr;
unsigned int pktsize;
switch (dlpacket->dl_hdr.dl_op) {
case DLDEP:
pktsize = sizeof(struct dl_pack);
break;
case DLSRT:
pktsize = sizeof(struct dl_header)
+ sizeof(struct dl_srtval);
break;
default:
pktsize = sizeof(struct dl_header);
break;
}
if (A.verbose) {
fprintf(stderr,"packet: ");
switch(dlpacket->dl_hdr.dl_op) {
case DLDEP:
addr = ntohl(dlpacket->dl_hdr.dl_addr);
len = ntohs(dlpacket->dl_hdr.dl_len);
fprintf(stderr, "deposit, addr = %#o, len = %#o\n",
addr, (int) len);
break;
case DLSRT:
fprintf( stderr,
"start program, delay = %d, entry pt = %o\n",
ntohl(dlpacket->dl_pt.dl_srt.dl_delay),
ntohl(dlpacket->dl_pt.dl_srt.dl_entry) );
break;
case DLID:
fprintf(stderr, "ID packet\n");
break;
default:
fprintf(stderr, "send_dlpack: invalid packet type\n");
return;
}
}
if (send(sockfd, dlpacket, pktsize, 0) < 0) {
perror("udp packet send");
callexit(1);
}
}