-- Copyright (C) 1983 by Xerox Corporation. All rights reserved. -- PupBootServer.mesa, HGM, 18-Jun-85 5:58:57 DIRECTORY Process USING [Detach], String USING [AppendChar], BootServerDefs USING [ pleaseStop, booting, slowBooting, statBootDir, statFile, statSun, statFileSent, statFileSentSlow, statMicrocodeBooted, statSlowMicrocodeBooted, statFileTroubles, statFileNeverStarted, statBusyDisk, statBusyBooting, statUnknown, FastBooter, SlowBooter, MicrocodeBooter, LookAtBootDir, bootStatsRequest, BootServerStats, lockBooterRequest, lockBooterReply, unlockBooterRequest, unlockBooterReply, microcodeRequest, microcodeVersionNumber, SlowMicrocodeBooter, slowMicrocodeRequest, sunBootRequest], BootServer USING [], BootServerBasics USING [BootFileNumber], BootServerFriends USING [BootFile, FindBootFile, FindBootFileByName, GetPointerToBootTable], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], PupWireFormat USING [BcplLongNumber, MesaToBcplLongNumber, BcplSTRING], PupDefs USING [ GetPupContentsBytes, Pair, PupAddress, PupBuffer, PupRouterBroadcastThis, PupRouterSendThis, ReturnPup, FastPath, SetPupContentsWords, SwapPupSourceAndDest], PupTypes USING [maxDataWordsPerGatewayPup, miscSrvSoc], Stats USING [StatIncr]; PupBootServer: PROGRAM IMPORTS Process, String, BootServerDefs, BootServerFriends, Buffer, PupWireFormat, PupDefs, Stats EXPORTS BootServer, BootServerDefs SHARES Buffer = -- network BEGIN OPEN Stats, PupDefs, BootServerDefs; BootFileNumber: TYPE = BootServerBasics.BootFileNumber; -- maybe we should allow several slow booters lock: BOOLEAN ← FALSE; -- This won't work with small buffers dwpb: CARDINAL = PupTypes.maxDataWordsPerGatewayPup; microcodeOffset: CARDINAL = 3000B; PupBootServer: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN SELECT b.pup.pupType FROM bootFileSend => SendBootFile[b]; microcodeRequest => SendMicrocode[b, FALSE]; slowMicrocodeRequest => SendMicrocode[b, TRUE]; bootDirReq => SendBootDir[b]; bootDirReply => BEGIN IF lock OR pleaseStop THEN Buffer.ReturnBuffer[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; sunBootRequest => SendSunBootFile[b]; ENDCASE => Buffer.ReturnBuffer[b]; END; SendBootFile: PROCEDURE [b: PupBuffer] = BEGIN bf: BootServerFriends.BootFile; him: PupAddress; slow: BOOLEAN; code: WORD = b.pup.pupID.b; SwapPupSourceAndDest[b]; -- fixup defaults him ← b.pup.dest; Buffer.ReturnBuffer[b]; IF lock THEN RETURN; slow ← ~FastPath[him]; IF (booting AND ~slow) OR (slowBooting AND slow) THEN BEGIN StatIncr[statBusyBooting]; RETURN; END; IF (bf ← BootServerFriends.FindBootFile[CardinalToPupBFN[code]]) = NIL OR ~bf.pup THEN BEGIN StatIncr[statUnknown]; RETURN; END; 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, slow: BOOL] = BEGIN bf: BootServerFriends.BootFile; him: PupAddress; version: WORD ← b.pup.pupID.a; code: WORD = microcodeOffset + b.pup.pupID.b; SwapPupSourceAndDest[b]; -- fixup defaults him ← b.pup.dest; Buffer.ReturnBuffer[b]; IF lock THEN RETURN; IF version # microcodeVersionNumber THEN RETURN; IF booting THEN BEGIN StatIncr[statBusyBooting]; RETURN; END; IF (bf ← BootServerFriends.FindBootFile[CardinalToPupBFN[code]]) = NIL OR ~bf.pup THEN BEGIN StatIncr[statUnknown]; RETURN; END; StatIncr[statFile]; booting ← TRUE; Process.Detach[FORK Booter[bf, him, IF slow THEN slowMicro ELSE micro]]; END; SendSunBootFile: PROCEDURE [b: PupBuffer] = BEGIN bf: BootServerFriends.BootFile; him: PupAddress; slow: BOOLEAN; name: STRING = [100]; SwapPupSourceAndDest[b]; -- fixup defaults him ← b.pup.dest; FOR i: CARDINAL IN [0..PupDefs.GetPupContentsBytes[b]) DO IF i > name.maxlength THEN LOOP; -- Truncate String.AppendChar[name, b.pup.pupChars[i]]; ENDLOOP; Buffer.ReturnBuffer[b]; IF lock THEN RETURN; slow ← ~FastPath[him]; IF (booting AND ~slow) OR (slowBooting AND slow) THEN BEGIN StatIncr[statBusyBooting]; RETURN; END; IF (bf ← BootServerFriends.FindBootFileByName[name]) = NIL OR ~bf.pup THEN BEGIN StatIncr[statUnknown]; RETURN; END; StatIncr[statSun]; IF slow THEN slowBooting ← TRUE ELSE booting ← TRUE; Process.Detach[FORK Booter[bf, him, IF slow THEN slow ELSE fast]]; END; Booter: PROCEDURE [ bf: BootServerFriends.BootFile, who: PupAddress, what: {fast, slow, micro, slowMicro}] = BEGIN StatIncr[ SELECT (SELECT what FROM fast => FastBooter[bf, who], slow => SlowBooter[bf, who], micro => MicrocodeBooter[bf, who], slowMicro => SlowMicrocodeBooter[bf, who], ENDCASE => ERROR) FROM fast => statFileSent, slow => statFileSentSlow, micro => statMicrocodeBooted, slowMicro => statSlowMicrocodeBooted, diskBusy => statBusyDisk, neverStarted => statFileNeverStarted, troubles => statFileTroubles, ENDCASE => ERROR]; IF what = slow THEN slowBooting ← FALSE ELSE booting ← FALSE; END; first: LONG POINTER TO BootServerFriends.BootFile = BootServerFriends.GetPointerToBootTable[]; -- If b is NIL, then we broadcast the info. SendBootDir: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN pool: Buffer.AccessHandle ← NIL; me, him: PupAddress; word, size: CARDINAL ← 0; id: Pair; broadcast: BOOLEAN ← b = NIL; IF lock THEN BEGIN IF b # NIL THEN Buffer.ReturnBuffer[b]; RETURN; END; IF ~broadcast THEN BEGIN id ← b.pup.pupID; SwapPupSourceAndDest[b]; -- fixup broadcast me ← b.pup.source; him ← b.pup.dest; END ELSE BEGIN id ← [0, 0]; pool ← Buffer.MakePool[send: 1, receive: 0]; b ← Buffer.GetBuffer[pup, pool, send]; me.socket ← him.socket ← PupTypes.miscSrvSoc; END; FOR bf: BootServerFriends.BootFile ← first↑, bf.next UNTIL bf = NIL DO IF bf.unknown OR ~bf.pup 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.pup.pupType ← bootDirReply; b.pup.pupID ← id; SetPupContentsWords[b, word]; b.pup.dest ← him; b.pup.source ← me; IF broadcast THEN PupRouterBroadcastThis[b] ELSE PupRouterSendThis[b]; word ← 0; IF pool = NIL THEN pool ← Buffer.MakePool[send: 1, receive: 0]; b ← Buffer.GetBuffer[pup, pool, send]; END; b.pup.pupWords[word] ← PupBFNToCardinal[bf.code]; LOOPHOLE[@b.pup.pupWords[word + 1], LONG POINTER TO PupWireFormat.BcplLongNumber]↑ ← PupWireFormat.MesaToBcplLongNumber[ bf.create]; CopyString[bf.fileName, LOOPHOLE[@b.pup.pupWords + word + 1 + 2]]; word ← word + size + 1 + 2; ENDLOOP; b.pup.pupType ← bootDirReply; b.pup.pupID ← id; SetPupContentsWords[b, word]; b.pup.dest ← him; b.pup.source ← me; IF broadcast THEN PupRouterBroadcastThis[b] ELSE PupRouterSendThis[b]; StatIncr[statBootDir]; IF pool # NIL THEN Buffer.DestroyPool[pool]; END; CopyString: PROCEDURE [ s: LONG STRING, d: LONG POINTER TO PupWireFormat.BcplSTRING] = BEGIN d.length ← s.length; FOR i: CARDINAL IN [0..s.length) DO d.char[i] ← s[i]; ENDLOOP; END; magicSecondWord: WORD = 125026B; CardinalToPupBFN: PUBLIC PROCEDURE [n: CARDINAL] RETURNS [BootFileNumber] = BEGIN foo: RECORD [a, b, c: WORD] = [0, magicSecondWord, n]; RETURN[LOOPHOLE[foo]]; END; NotPupBootFileNumber: ERROR = CODE; PupBFNToCardinal: PUBLIC PROCEDURE [bfn: BootFileNumber] RETURNS [CARDINAL] = BEGIN foo: RECORD [a, b, c: WORD] = LOOPHOLE[bfn]; IF foo.b # magicSecondWord THEN ERROR NotPupBootFileNumber; RETURN[foo.c]; END; END.