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