PupBooterImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Hal Murray, October 25, 1986 4:57:27 pm PDT
Russ Atkinson (RRA) April 25, 1986 5:07:14 pm PST
DIRECTORY
Basics USING [bytesPerWord, HighHalf, LowHalf],
BasicTime USING [GetClockPulses, GMT, Pulses, PulsesToMicroseconds, ToPupTime],
Convert USING [RopeFromInt],
EFTP USING [CreateSender, Finish, Handle, PutBlock, SetSendTimeout, Timeout, Trouble],
Endian USING [bytesPerHWord, FWORD, HWORD],
FS USING [Error, GetInfo, Open, OpenFile, StreamFromOpenFile],
IO USING [GetBlock, SetIndex, STREAM],
PrincOpsUtils USING [LongCopy],
Process USING [Detach, priorityNormal, SetPriority],
Pup USING [Address, allHosts, allNets, Host],
PupBuffer USING [Buffer, maxOldGatewayBytes],
PupSocket USING [AllocBuffer, AppendRope, CreateEphemeral, CreateServer, Destroy, FixupSourceAndDest, FreeBuffer, Get, GetUserBytes, GetUserHWords, Put, ReturnToSender, SetRemoteAddress, SetUserBytes, SetUserHWords, Socket, waitForever],
PupWKS USING [misc],
RefText USING [ObtainScratch, ReleaseScratch],
Rope USING [Cat, Length, ROPE];
PupBooterImpl: CEDAR MONITOR
IMPORTS Basics, BasicTime, Convert, EFTP, FS, IO, PrincOpsUtils, Process, PupSocket, RefText, Rope = {
BYTE: TYPE = [0..100H);
bytesPerPupPage: INT = 512;
Buffer: TYPE = PupBuffer.Buffer;
BootFile: TYPE = RECORD [
number: Endian.HWORD,
create: BasicTime.GMT,
fileName: Rope.ROPENIL,
stream: IO.STREAMNIL,
count: INT ← 0,
ms: INT ← 0 ];
booting: BOOLFALSE;
bootFiles: LIST OF REF BootFile ← NIL;
Pup Misc Server - This should get de-muxed
socket: PupSocket.Socket;
PupMiscServer: PROC = {
socket ← PupSocket.CreateServer[
local: PupWKS.misc,
getTimeout: PupSocket.waitForever ];
PupSocket.SetRemoteAddress[socket, [Pup.allNets, Pup.allHosts, PupWKS.misc]];
Process.SetPriority[Process.priorityNormal];
DO
b: Buffer ← PupSocket.Get[socket];
PupSocket.FixupSourceAndDest[b];
SELECT b.type FROM
echoMe => {
b.type ← iAmEcho;
PupSocket.ReturnToSender[b];
LOOP; };
bootFileSend => BootFileRequest[b];
microcodeRequest => MicrocodeRequest[b];
bootDirReq => BootDirRequest[b];
ENDCASE => NULL;
PupSocket.FreeBuffer[b];
ENDLOOP;
};
BootFileRequest: ENTRY PROC [b: Buffer] = {
target: Endian.HWORD ← ExtractBootFileNumberFromId[b.id];
IF booting THEN RETURN;
FOR bootFile: LIST OF REF BootFile ← bootFiles, bootFile.rest UNTIL bootFile = NIL DO
IF bootFile.first.number # target THEN LOOP;
booting ← TRUE;
TRUSTED { Process.Detach[FORK SendBootFile[b.source, bootFile.first]]; };
ENDLOOP;
};
SendBootFile: PROC [who: Pup.Address, bootFile: REF BootFile] = {
IO.SetIndex[bootFile.stream, 0];
BEGIN ENABLE EFTP.Timeout, EFTP.Trouble => CONTINUE;
micro: INT;
start: BasicTime.Pulses ← BasicTime.GetClockPulses[];
scratch: REF TEXT ← RefText.ObtainScratch[bytesPerPupPage];
sender: EFTP.Handle ← EFTP.CreateSender[who, FALSE];
total: INT ← 0;
EFTP.SetSendTimeout[sender, 100, 5];
DO
bytes: NATIO.GetBlock[bootFile.stream, scratch, 0, bytesPerPupPage];
IF bytes = 0 THEN EXIT;
scratch.length ← bytes;
EFTP.PutBlock[sender, scratch];
IF total = 0 THEN EFTP.SetSendTimeout[sender, 250, 20];
total ← total + bytes;
ENDLOOP;
EFTP.Finish[sender];
RefText.ReleaseScratch[scratch];
micro ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]-start];
bootFile.ms ← bootFile.ms + micro/1000;
bootFile.count ← bootFile.count.SUCC;
END;
booting ← FALSE;
};
microcodeFudge: INT = 3000B;
MicrocodeRequest: ENTRY PROC [b: Buffer] = {
target: Endian.HWORD ← ExtractBootFileNumberFromId[b.id] + microcodeFudge;
IF booting THEN RETURN;
FOR bootFile: LIST OF REF BootFile ← bootFiles, bootFile.rest UNTIL bootFile = NIL DO
IF bootFile.first.number # target THEN LOOP;
booting ← TRUE;
TRUSTED { Process.Detach[FORK SendMicrocode[b.source, bootFile.first]]; };
ENDLOOP;
};
microcodeVersionNumber: NAT = 1;
SendMicrocode: PROC [who: Pup.Address, bootFile: REF BootFile] = {
Beware: This won't work for D0s. (Must have 3*n words per packet.)
Reminder: Dorado's can't boot through gateways. (Hop count must be 0.)
micro: INT;
start: BasicTime.Pulses ← BasicTime.GetClockPulses[];
scratch: REF TEXT ← RefText.ObtainScratch[bytesPerPupPage];
blaster: PupSocket.Socket ← PupSocket.CreateEphemeral[remote: who];
base: LONG POINTER = LOOPHOLE[scratch, LONG POINTER]+TEXT[0].SIZE;
packetNumber: NAT ← 0;
b: Buffer;
IO.SetIndex[bootFile.stream, 0];
[] ← IO.GetBlock[bootFile.stream, scratch, 0, bytesPerPupPage]; -- Skip first page
DO
bytes: NATIO.GetBlock[bootFile.stream, scratch, 0, bytesPerPupPage];
IF bytes = 0 THEN EXIT;
scratch.length ← bytes;
b ← PupSocket.AllocBuffer[blaster];
TRUSTED {
PrincOpsUtils.LongCopy[
from: base,
nwords: bytes/Basics.bytesPerWord,
to: @b.byte ]; };
b.id ← [microcodeVersionNumber, packetNumber];
b.type ← microcodeReply;
PupSocket.SetUserBytes[b, bytes];
PupSocket.Put[blaster, b];
packetNumber ← packetNumber.SUCC;
ENDLOOP;
b ← PupSocket.AllocBuffer[blaster];
b.id ← [microcodeVersionNumber, packetNumber];
b.type ← microcodeReply;
PupSocket.SetUserBytes[b, 0]; -- end marker
PupSocket.Put[blaster, b];
PupSocket.Destroy[blaster];
RefText.ReleaseScratch[scratch];
micro ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]-start];
bootFile.ms ← bootFile.ms + micro/1000;
bootFile.count ← bootFile.count.SUCC;
booting ← FALSE;
};
maxHWordsPerOldPup: INT = PupBuffer.maxOldGatewayBytes/Endian.bytesPerHWord;
BootDirRequest: PROC [buffer: Buffer] = {
words: CARDINAL ← 0;
b: Buffer ← PupSocket.AllocBuffer[socket];
PupSocket.SetUserBytes[b, 0];
FOR bootFile: LIST OF REF BootFile ← bootFiles, bootFile.rest UNTIL bootFile = NIL DO
size: CARDINAL ← 1+2+HWordsForString[bootFile.first.fileName];
IF words + size > maxHWordsPerOldPup THEN { -- won't fit
b.id ← buffer.id;
b.type ← bootDirReply;
b.ovh.encap ← buffer.ovh.encap;
b.ovh.network ← buffer.ovh.network;
b.dest ← buffer.dest;
b.source ← buffer.source;
PupSocket.ReturnToSender[b];
b ← PupSocket.AllocBuffer[socket];
PupSocket.SetUserBytes[b, 0];
words ← 0; };
AppendHWord[b, bootFile.first.number];
AppendGMT[b, bootFile.first.create];
AppendBcplString[b, bootFile.first.fileName];
words ← PupSocket.GetUserHWords[b]; -- Rounds Down
ENDLOOP;
b.id ← buffer.id;
b.type ← bootDirReply;
b.ovh.encap ← buffer.ovh.encap;
b.ovh.network ← buffer.ovh.network;
b.dest ← buffer.dest;
b.source ← buffer.source;
PupSocket.ReturnToSender[b];
};
ExtractBootFileNumberFromId: PROC [id: Endian.FWORD] RETURNS [Endian.HWORD] = {
RETURN[id.low]; -- assumes id is words rather than bytes
};
HWordsForString: PROC [rope: Rope.ROPE] RETURNS [INT] = {
chars: INT ← Rope.Length[rope];
bytes: INT ← 1 + chars; -- count byte
RETURN[HWordsRoundedUp[bytes]];
};
HWordsRoundedUp: PROC [bytes: INT] RETURNS [INT] = {
RETURN[(bytes+Endian.bytesPerHWord-1)/Endian.bytesPerHWord];
};
AppendByte: PROC [b: Buffer, byte: BYTE] = {
bytes: CARDINAL ← PupSocket.GetUserBytes[b];
b.byte[bytes] ← byte;
bytes ← bytes + 1;
PupSocket.SetUserBytes[b, bytes];
};
AppendHWord: PROC [b: Buffer, hWord: Endian.HWORD] = {
words: CARDINAL ← PupSocket.GetUserHWords[b]; -- Rounds Down
b.hWord[words] ← hWord;
words ← words + 1;
PupSocket.SetUserHWords[b, words];
};
AppendGMT: PROC [b: Buffer, create: BasicTime.GMT] = {
pupTime: LONG CARDINAL ← BasicTime.ToPupTime[create];
AppendHWord[b, Basics.HighHalf[pupTime]];
AppendHWord[b, Basics.LowHalf[pupTime]];
};
AppendBcplString: PROC [b: Buffer, rope: Rope.ROPE] = {
bytes: INT = Rope.Length[rope];
AppendByte[b, bytes];
PupSocket.AppendRope[b, rope];
PupSocket.SetUserHWords[b, HWordsRoundedUp[PupSocket.GetUserBytes[b]]];
};
InsertEntry: PROC [number: Endian.HWORD, fileName: Rope.ROPE] = {
numberAsRope: Rope.ROPE = Convert.RopeFromInt[number, 8, FALSE];
ivyFileName: Rope.ROPE = Rope.Cat["/Ivy/System/Boot/", numberAsRope, "-", fileName];
new: REF BootFile;
openFile: FS.OpenFile;
create: BasicTime.GMT;
stream: IO.STREAMNIL;
openFile ← FS.Open[name: ivyFileName ! FS.Error => CONTINUE];
IF openFile = NIL THEN RETURN;
stream ← FS.StreamFromOpenFile[openFile: openFile ! FS.Error => CONTINUE];
IF stream = NIL THEN RETURN;
create ← FS.GetInfo[openFile].created;
new ← NEW[BootFile ← [number: number, create: create, fileName: fileName, stream: stream]];
IF bootFiles = NIL THEN bootFiles ← CONS[new, NIL]
ELSE
FOR finger: LIST OF REF BootFile ← bootFiles, finger.rest UNTIL finger = NIL DO
IF finger.rest = NIL THEN { finger.rest ← CONS[new, NIL]; EXIT; };
ENDLOOP;
};
TRUSTED { Process.Detach[FORK PupMiscServer[]]; };
InsertEntry[0B, "DMT.boot"];
InsertEntry[10B, "NetExec.boot"];
InsertEntry[200B, "CedarNetExec.boot"];
InsertEntry[3110B, "AltoMesaDorado.eb"];
InsertEntry[3112B, "AltoMesaDorado.eb"];
InsertEntry[3113B, "CedarDorado.eb"];
InsertEntry[5100B, "CedarDorado.eg"];
InsertEntry[45103B, "BasicCedarDorado.pb"];
}.