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"]; }. jPupBooterImpl.mesa Copyright c 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 Pup Misc Server - This should get de-muxed 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.) Ê "˜codešœ™Kšœ Ïmœ1™Kšžœžœžœ˜&Kšœžœ ˜Kšœžœ'˜4Kšœžœ$˜-Kšœ žœ˜-Kšœ žœÞ˜íKšœžœ˜Kšœžœ!˜.Kšœžœžœ˜K˜——šœžœž˜Kšžœžœžœžœ6˜fK˜Kšžœžœ ˜Kšœžœ˜Kšœžœ˜ K˜šœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœžœžœžœ˜Kšœžœ˜Kšœžœ˜—K˜Kšœ žœžœ˜Kš œ žœžœžœ žœ˜&—head™*Kšœ˜šÏn œžœ˜˜ Kšœ˜Kšœ$˜$—KšœM˜MKšœ,˜,šž˜Kšœ"˜"K˜ šžœž˜šœ ˜ Jšœ˜Jšœ˜Jšžœ˜—Kšœ#˜#Kšœ(˜(Kšœ ˜ Kšžœžœ˜—Kšœ˜Kšžœ˜—K˜K˜—šŸœžœžœ˜+Kšœžœ%˜9Kšžœ žœžœ˜š žœ žœžœžœ%žœ žœž˜UKšžœ žœžœ˜,Kšœ žœ˜Kšžœžœ,˜IKšžœ˜—Kšœ˜K˜—šŸ œžœžœ˜AKšžœ˜ Kš žœžœžœ žœ žœ˜4Kšœžœ˜ Kšœ5˜5Kšœ žœžœ*˜;Kšœžœ žœžœ˜4Kšœžœ˜Kšžœ ˜$šž˜Kšœžœžœ8˜GKšžœ žœžœ˜Kšœ˜Kšžœ˜Kšžœ žœžœ!˜7Kšœ˜Kšžœ˜—Kšžœ˜Kšœ ˜ KšœJ˜JKšœ(˜(Kšœ žœ˜&Kšžœ˜Kšœ žœ˜K˜K˜—Kšœžœ ˜šŸœžœžœ˜,Kšœžœ6˜JKšžœ žœžœ˜š žœ žœžœžœ%žœ žœž˜UKšžœ žœžœ˜,Kšœ žœ˜Kšžœžœ-˜JKšžœ˜—Kšœ˜K˜—Kšœžœ˜ šŸ œžœžœ˜BKšŸœ<™BKšŸœ>™FKšœžœ˜ Kšœ5˜5Kšœ žœžœ*˜;KšœC˜CKšœžœžœžœ žœžœžœžœ˜BKšœžœ˜Kšœ ˜ Kšžœ˜ Kšœžœ9Ïc˜Ršž˜Kšœžœžœ8˜GKšžœ žœžœ˜Kšœ˜Kšœ#˜#šžœ˜ šœ˜Kšœ ˜ Kšœ"˜"Kšœ˜——Kšœ.˜.K˜Kšœ!˜!Kšœ˜Kšœžœ˜!Kšžœ˜—Kšœ#˜#Kšœ.˜.K˜Kšœ  ˜+Kšœ˜Kšœ˜Kšœ ˜ KšœJ˜JKšœ(˜(Kšœ žœ˜&Kšœ žœ˜K˜K˜—Kšœžœ5˜LšŸœžœ˜)Kšœžœ˜K˜*K˜š žœ žœžœžœ%žœ žœž˜UKšœžœ0˜>šžœ#žœ  ˜8K˜K˜K˜K˜#K˜K˜K˜K˜"K˜K˜ —Kšœ&˜&Kšœ$˜$Kšœ-˜-Kšœ$ ˜2Kšžœ˜—K˜K˜K˜K˜#K˜K˜K˜Kšœ˜K˜—š Ÿœžœ žœžœ žœ˜OKšžœ  (˜8Kšœ˜K˜—š Ÿœžœ žœžœžœ˜9Kšœžœ˜Kšœžœ  ˜%Kšžœ˜Kšœ˜K˜—š Ÿœžœ žœžœžœ˜4Kšžœ6˜˜TKšœžœ ˜Kšœ˜Kšœžœ˜Kšœžœžœžœ˜Kšœ žœžœ žœ˜=Kšžœ žœžœžœ˜Kšœ žœ)žœ žœ˜JKšžœ žœžœžœ˜Kšœ žœ˜&KšœžœR˜[Kš žœ žœžœ žœžœ˜2šž˜š žœ žœžœžœ#žœ žœž˜OKš žœžœžœžœžœžœ˜BKšžœ˜——Kšœ˜K˜—Kšžœžœ˜2K˜Kšœ˜Kšœ!˜!Kšœ'˜'Kšœ(˜(Kšœ(˜(Kšœ%˜%Kšœ%˜%šœ+˜+K˜——šœ˜K˜——…— Ò,^