<> <> <> <> <<>> 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.ROPE _ NIL, stream: IO.STREAM _ NIL, count: INT _ 0, ms: INT _ 0 ]; booting: BOOL _ FALSE; bootFiles: LIST OF REF BootFile _ NIL; <> 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: NAT _ IO.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] = { <> <> 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: NAT _ IO.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.STREAM _ NIL; 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"]; }.