-- File: PupBootServer.mesa, Last Edit: HGM February 4, 1981 11:29 PM DIRECTORY InlineDefs USING [BcplLongNumber, MesaToBcplLongNumber], StringDefs USING [BcplSTRING], Process USING [Detach], BootServerDefs USING [ pleaseStop, booting, slowBooting, statBootDir, statFile, statFileSent, statFileSentSlow, statMicrocodeBooted, statFileTroubles, statFileNeverStarted, statBusyDisk, statBusyBooting, statUnknown, BootFile, FastBooter, lock, SlowBooter, MicrocodeBooter, LookAtBootDir, bootStatsRequest, BootServerStats, lockBooterRequest, lockBooterReply, unlockBooterRequest, unlockBooterReply, microcodeRequest, microcodeVersionNumber], StatsDefs USING [StatIncr], PupDefs USING [ GetFreePupBuffer, ReturnFreePupBuffer, Pair, PupAddress, PupBuffer, PupRouterBroadcastThis, PupRouterSendThis, ReturnPup, FastPath, SetPupContentsWords, SwapPupSourceAndDest], PupTypes USING [maxDataWordsPerGatewayPup, miscSrvSoc], BufferDefs; PupBootServer: MONITOR LOCKS BootServerDefs.lock IMPORTS InlineDefs, Process, BootServerDefs, StatsDefs, PupDefs EXPORTS BootServerDefs SHARES BufferDefs = -- network BEGIN OPEN StatsDefs, PupDefs, BootServerDefs; first: BootFile _ NIL; -- maybe we should allow several slow booters lock: BOOLEAN _ FALSE; -- This won't work with small buffers dwpb: CARDINAL = PupTypes.maxDataWordsPerGatewayPup; microcodeOffset: CARDINAL = 3000B; GetPointerToBootTable: PUBLIC PROCEDURE RETURNS [POINTER TO BootFile] = BEGIN RETURN[@first]; END; PupBootServer: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN SELECT b.pupType FROM bootFileSend => SendBootFile[b]; microcodeRequest => SendMicrocode[b]; bootDirReq => SendBootDir[b]; bootDirReply => BEGIN IF lock OR pleaseStop THEN ReturnFreePupBuffer[b] ELSE LookAtBootDir[b]; END; bootStatsRequest => BootServerStats[b]; lockBooterRequest => BEGIN lock _ TRUE; ReturnPup[b, lockBooterReply, 0]; END; unlockBooterRequest => BEGIN lock _ FALSE; ReturnPup[b, unlockBooterReply, 0]; END; ENDCASE => ReturnFreePupBuffer[b]; END; SendBootFile: PROCEDURE [b: PupBuffer] = BEGIN bf: BootFile; him: PupAddress; slow: BOOLEAN; code: WORD = b.pupID.b; SwapPupSourceAndDest[b]; -- fixup defaults him _ b.dest; ReturnFreePupBuffer[b]; IF lock THEN RETURN; slow _ ~FastPath[him]; IF (booting AND ~slow) OR (slowBooting AND slow) THEN BEGIN StatIncr[statBusyBooting]; RETURN; END; IF (bf _ FindEntry[code]) = NIL THEN RETURN; StatIncr[statFile]; IF slow THEN slowBooting _ TRUE ELSE booting _ TRUE; Process.Detach[FORK Booter[bf, him, IF slow THEN slow ELSE fast]]; END; SendMicrocode: PROCEDURE [b: PupBuffer] = BEGIN bf: BootFile; him: PupAddress; version: WORD _ b.pupID.a; code: WORD = microcodeOffset + b.pupID.b; SwapPupSourceAndDest[b]; -- fixup defaults him _ b.dest; ReturnFreePupBuffer[b]; IF lock THEN RETURN; IF version # microcodeVersionNumber THEN RETURN; IF booting THEN BEGIN StatIncr[statBusyBooting]; RETURN; END; IF (bf _ FindEntry[code]) = NIL THEN RETURN; StatIncr[statFile]; booting _ TRUE; Process.Detach[FORK Booter[bf, him, micro]]; END; FindEntry: ENTRY PROCEDURE [code: WORD] RETURNS [bf: BootFile] = BEGIN previous: BootFile _ NIL; FOR bf _ first, bf.next UNTIL bf = NIL DO IF bf.code = code AND ~bf.unknown THEN EXIT; previous _ bf; REPEAT FINISHED => BEGIN StatIncr[statUnknown]; RETURN; END; ENDLOOP; IF previous # NIL THEN BEGIN previous.next _ bf.next; bf.next _ first; first _ bf; END; END; Booter: PROCEDURE [bf: BootFile, who: PupAddress, what: {fast, slow, micro}] = BEGIN StatIncr[ SELECT (SELECT what FROM fast => FastBooter[bf, who], slow => SlowBooter[bf, who], micro => MicrocodeBooter[bf, who], ENDCASE => ERROR) FROM fast => statFileSent, slow => statFileSentSlow, micro => statMicrocodeBooted, diskBusy => statBusyDisk, neverStarted => statFileNeverStarted, troubles => statFileTroubles, ENDCASE => ERROR]; IF what = slow THEN slowBooting _ FALSE ELSE booting _ FALSE; END; -- If b is NIL, then we broadcast the info. SendBootDir: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN me, him: PupAddress; word, size: CARDINAL _ 0; bf: BootFile; id: Pair; broadcast: BOOLEAN _ b = NIL; IF lock THEN BEGIN IF b # NIL THEN ReturnFreePupBuffer[b]; RETURN; END; IF ~broadcast THEN BEGIN id _ b.pupID; SwapPupSourceAndDest[b]; -- fixup broadcast me _ b.source; him _ b.dest; END ELSE BEGIN id _ [0, 0]; b _ GetFreePupBuffer[]; me.socket _ him.socket _ PupTypes.miscSrvSoc; END; FOR bf _ first, bf.next UNTIL bf = NIL DO IF bf.unknown THEN LOOP; size _ ((1 + bf.fileName.length) + 1)/2; IF (word + size + 1 + 2) > dwpb THEN BEGIN -- this buffer is full, send it and get another one b.pupType _ bootDirReply; b.pupID _ id; SetPupContentsWords[b, word]; b.dest _ him; b.source _ me; IF broadcast THEN PupRouterBroadcastThis[b] ELSE PupRouterSendThis[b]; word _ 0; b _ GetFreePupBuffer[]; END; b.pupWords[word] _ bf.code; LOOPHOLE[@b.pupWords[word + 1], LONG POINTER TO InlineDefs.BcplLongNumber]^ _ InlineDefs.MesaToBcplLongNumber[bf.create]; CopyString[bf.fileName, LOOPHOLE[@b.pupWords + word + 1 + 2]]; word _ word + size + 1 + 2; ENDLOOP; b.pupType _ bootDirReply; b.pupID _ id; SetPupContentsWords[b, word]; b.dest _ him; b.source _ me; IF broadcast THEN PupRouterBroadcastThis[b] ELSE PupRouterSendThis[b]; StatIncr[statBootDir]; END; CopyString: PROCEDURE [s: STRING, d: LONG POINTER TO StringDefs.BcplSTRING] = BEGIN d.length _ s.length; FOR i: CARDINAL IN [0..s.length) DO d.char[i] _ s[i]; ENDLOOP; END; END.