-- 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.