/* LarkMonELoad.c TeleLoad server using trivial ether driver L. Stewart, February 11, 1983 2:21 PM, created from LarkELoad.c L. Stewart, February 18, 1983 7:00 PM, SendState L. Stewart, February 24, 1983 2:17 PM, Advice & setHost bits L. Stewart, March 3, 1983 2:39 PM, access to statics L. Stewart, April 28, 1983 11:27 AM, tl stuff to LarkMonML L. Stewart, April 28, 1983 11:36 AM, larger state block, CheckState L. Stewart, April 28, 1983 5:27 PM, Checksum */ #include #include #include #include #include /* the format of junk is struct Advice { bit setAddr; bit setAdvice; bit(14) advice; }; */ struct Core { int advice, addrlo, addrhi, count; char data[1]; }; /* from system */ extern SingleStep(); extern GoNormal(); extern GoFromBreak(); extern int mState[1]; extern int advice; /* from runtime */ extern MoveBlock(); extern ByteBlt(); extern Swab(); extern DoubleEQ(); /* from Trivial Pup package */ extern SLCReset(); extern SStartRx(); extern struct PBI *SCheckRx(); extern SStartTx(); extern int SCheckTx(); /* BOOL */ /* local variables */ static int elBuf[130]; static struct PBI elPBI; static int tlID[2]; static int stateTimer; static int stateInterval; static int gotReply; /* next section must stay in order for GetDebugPtrs to work (why?) */ extern int tlNet; extern int tlHost; extern int tlImHost; extern int localNet; #define ELWrite 0x00c0 #define ELRead 0x00c2 #define ELStateWrite 0x00c4 #define ELStateRead 0x00c6 #define ELDebug 0x00c8 #define ELBooted 0x00c9 /* these are for new break and single step facilities */ #define ELSingleStep 0x00ca #define ELGoFromBreak 0x00cc /* read and write the slave address space */ #define ELSWrite 0x00ce #define ELSRead 0x00d0 /* call a procedure */ #define ELCall 0x00d2 /* call ELoad to set up a TeleDebug server */ StartEL() { SLCReset(); elPBI.pup = (struct Pup *) &elBuf[2]; tlID[0] = tlID[1] = 0x6767; SStartRx(&elPBI, 256); }; CheckEL() { if (SCheckRx() == 0) return; ELoadProc(&elPBI); SStartRx(&elPBI, 256); }; static ELoadProc(pbi) struct PBI *pbi; { struct Pup *pup; char *caddr; char *cdata; int cAdvice; int ccount; int pupType; int maxLength; int dHost; struct Core *core; pup = pbi->pup; /* check for various bad things */ if (pup->dPort.socket.LS != 0) goto reject; if (pup->dPort.socket.ms != 0x3000) goto reject; /* accept broadcase teledeb packets for now */ dHost = pup->dPort.host; if ((dHost != EtherHost()) && (dHost != 0)) goto reject; if (!CheckCheckSum(pup)) goto reject; core = (struct Core *) &pup->data; if (core->addrhi) goto reject; ccount = Swab(core->count); if (ccount < 0) goto reject; maxLength = ((128 - pupOvWords) - 3) << 1; if (ccount > maxLength) { ccount = maxLength; core->count = Swab(maxLength); }; caddr = Swab(core->addrlo); cdata = &core->data[0]; cAdvice = Swab(core->advice); if (dHost == 0) cAdvice &= 0x3fff; core->advice = Swab(advice); pupType = pup->type; switch (pupType) { case ELStateWrite: case ELSingleStep: case ELGoFromBreak: if (dHost == 0) goto reject; if (((int) caddr != 1) || (ccount != 28)) goto reject; ByteBlt(mState, cdata, ccount); case ELStateRead: if ((int) caddr != 1) goto reject; ByteBlt(cdata, mState, ccount); pup->length = Swab((31 + ccount) & 0xfffe); pup->type = pup->type + 1; ReplyTo(cAdvice, pbi); if (pupType == ELStateWrite) GoNormal(); if (pupType == ELGoFromBreak) GoFromBreak(); if (pupType == ELSingleStep) SingleStep(); goto ok; case ELWrite: if (dHost == 0) goto reject; ByteBlt(caddr, cdata, ccount); case ELRead: if (Ugt(caddr, 0xffcf)) goto reject; if (Ugt(ccount, 0xffd0 - ((int) caddr))) goto reject; ByteBlt(cdata, caddr, ccount); pup->length = Swab((31 + ccount) & 0xfffe); pup->type = pup->type + 1; ReplyTo(cAdvice, pbi); goto ok; case ELDebug: { if (dHost != 0) CallDebugger(0xfffa); goto reject; }; case ELSWrite: if (dHost == 0) goto reject; SlaveBLT(caddr, cdata, ccount); /* how tell when it is done ? */ case ELSRead: SlaveBLT(cdata, caddr, ccount); pup->length = Swab((31 + ccount) & 0xfffe); pup->type = pup->type + 1; ReplyTo(cAdvice, pbi); goto ok; case ELCall: CallPkt(cdata); pup->type = pup->type + 1; ReplyTo(cAdvice, pbi); goto ok; default: goto reject; }; ok: gotReply = true; reject: }; /* Call this routine with a filled in pup which came from the right place. */ static ReplyTo(cAdvice, pbi) int cAdvice; struct PBI *pbi; { struct Pup *pup; struct EtherEncapsulation *ee; int temp; if (cAdvice & 0x4000) advice = cAdvice & 0x3fff; pup = pbi->pup; temp = (int) pup; temp -= 4; ee = (struct EtherEncapsulation *) temp; /* save Pup ID and source */ MoveBlock(tlID, &pup->id[0], 2); if (cAdvice & 0x8000) { tlNet = pup->sPort.net; tlHost = pup->sPort.host; tlImHost = ee->src; }; /* always believe net we are told we are on */ if (pup->dPort.net != 0) localNet = pup->dPort.net; /* Swap source and destination */ ee->dst = ee->src; ee->src = EtherHost(); ee->type = 2; SwapSourceAndDest(pup); pup->transport = 0; ReallySetCheckSum(pup); SStartTx(pbi); while (!SCheckTx(pbi)) CheckWDT(); }; SetCheckSum(pup) int *pup; /* struct Pup *pup; */ { /* pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1] = -1; */ pup[((Swab(*pup) +1) >> 1) - 1] = -1; }; CheckCheckSum(pup) int *pup; /* struct Pup *pup; */ { int ck; /* ck = pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1]; */ ck = pup[((Swab(*pup) +1) >> 1) - 1]; if ((ck == -1) || (ck == CheckSum(pup))) return(true); return(false); }; ReallySetCheckSum(pup) int *pup; /* struct Pup *pup; */ { /* pup->data.words[((Swab(pup->length)-pupOvBytes)+1)>>1] = CheckSum(pup); */ pup[((Swab(*pup) +1) >> 1) - 1] = CheckSum(pup); }; SwapSourceAndDest(pup) struct Pup *pup; { int temp[3]; MoveBlock(temp, &pup->dPort, 3); MoveBlock(&pup->dPort, &pup->sPort, 3); MoveBlock(&pup->sPort, temp, 3); }; FirstSendState() { gotReply = false; stateInterval = 1000; SendState(); }; CheckState() { if (gotReply) return; if (TmrExp(&stateTimer)) { if (stateInterval < 0) stateInterval = 1000; if (stateInterval >= 5000) { tlNet = 0; tlHost = 0; localNet = 0; tlImHost = 0; }; if (stateInterval < 30000) stateInterval += 1000; SendState(); StartEL(); }; }; static SendState() { struct Pup *pup; struct EtherEncapsulation *ee; int temp; struct Core *core; SLCReset(); elPBI.pup = (struct Pup *) &elBuf[2]; pup = elPBI.pup; temp = (int) pup; temp -= 4; ee = (struct EtherEncapsulation *) temp; ee->src = tlImHost; pup->sPort.net = tlNet; pup->sPort.host = tlHost; pup->dPort.net = localNet; pup->dPort.host = EtherHost(); pup->sPort.socket.LS = pup->dPort.socket.LS = 0; pup->sPort.socket.ms = pup->dPort.socket.ms = 0x3000; pup->type = ELBooted; DoubleIncrement(tlID, 1); MoveBlock(&pup->id[0], tlID, 2); core = (struct Core *) &pup->data; core->count = Swab(38); core->addrhi = 0; core->addrlo = Swab(1); ByteBlt(&core->data[0], mState, 48); pup->length = Swab((31 + 48) & 0xfffe); ReplyTo(false, &elPBI); SetTmr(stateInterval, &stateTimer); }; int *GetELBuf() { return(elBuf); }; int *GetDebugPtrs() { return(&tlNet); }; SlaveBLT(dest, src, count) int dest, src, count; { StoreW(src, BltFrom); StoreW(dest, BltTo); /* works in words */ StoreW(count >> 1, BltCount); StartSlave(4, 0); SetTmr(count, &dest); while (!TmrExp(&dest)) CheckWDT(); }; /* the packet data field contains proc nargs arguments first word past end is at cdata+4+(2*nargs) */ struct CPArgs { int proc; int nargs; int returnSlot; int args[5]; }; extern int stackLimit; extern int monEnd; CallPkt(cp) struct CPArgs *cp; { int stklimit; BlockSwab(cp, 8); if (cp->nargs > 5) return; stklimit = stackLimit; stackLimit = (int) &monEnd; stackLimit += 20; cp->returnSlot = Apply(&cp->args[0], cp->proc, cp->nargs); BlockSwab(cp, 8); stackLimit = stklimit; }; BlockSwab(ptr, count) int *ptr, count; { int i; for (i = 0; i < count; i += 1) ptr[i] = Swab(ptr[i]); };