-- Copyright (C) 1983 by Xerox Corporation. All rights reserved.
-- PupBootServer.mesa, HGM, 24-Sep-83 15:37:02
DIRECTORY
Process USING [Detach],
String USING [AppendChar],
BootServerDefs USING [
pleaseStop, booting, slowBooting, statBootDir, statFile, statSun, statFileSent,
statFileSentSlow, statMicrocodeBooted, statFileTroubles, statFileNeverStarted,
statBusyDisk, statBusyBooting, statUnknown, FastBooter, SlowBooter,
MicrocodeBooter, LookAtBootDir, bootStatsRequest, BootServerStats,
lockBooterRequest, lockBooterReply, unlockBooterRequest, unlockBooterReply,
microcodeRequest, microcodeVersionNumber, 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];
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] =
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, 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}] =
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;
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.