-- File: BootServersA.mesa - last edit: -- AOF 3-Feb-88 11:56:32 -- HGM 25-Jun-85 15:24:48 -- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. DIRECTORY Inline USING [LongCOPY, LowHalf], Process USING [Detach], Space USING [Activate, Deactivate, Interval, nullInterval], Stream USING [Delete, Handle, PutBlock], System USING [ GetClockPulses, NetworkAddress, nullSocketNumber, Pulses, PulsesToMicroseconds, SocketNumber], BootServerBasics USING [BootFileNumber], BootServer USING [BootFileType, Counters, MachineType], BootServerTypes USING [BootFileRequest, dataWords], BootServerFriends USING [ ActivateFiles, AddBootFile, BootFile, DeactivateFiles, DeleteBootFileTable, FindBootFile, LockFileRead, pagesPerSwapUnit, SetupSpace, UnlockFile], NSBuffer USING [Body, Buffer], NetworkStream USING [ Close, ConnectionID, ConnectionFailed, ConnectionSuspended, CreateTransducer, GetUniqueConnectionID], NSConstants USING [bootServerSocket], NSTypes USING [ConnectionID], ServerHeap USING [Create, Destroy], Socket USING [ AssignNetworkAddress, ChannelHandle, Create, Delete, GetDestination, GetPacket, GetSendBuffer, PutPacket, ReturnBuffer, SetDestination, SetPacketWords, SetWaitTime, SwapSourceAndDestination, TimeOut], Stats USING [StatCounterIndex, StatIncr, StatsStringToIndex]; BootServersA: MONITOR IMPORTS Inline, Process, Space, Stream, System, BootServerFriends, NetworkStream, ServerHeap, Socket, Stats EXPORTS NetworkStream, BootServer = BEGIN ConnectionID: PUBLIC TYPE = NSTypes.ConnectionID; counters: BootServer.Counters ¬ [0, 0, 0, 0, 0, 0]; pleaseStop: BOOLEAN; bootServerFork: PROCESS ¬ NIL; bootRequests: Stats.StatCounterIndex; CreateServer: PUBLIC ENTRY PROCEDURE = BEGIN ServerHeap.Create[]; END; AddBootFileToList: PUBLIC PROCEDURE [ fileName: LONG STRING, bootFileNumber: BootServerBasics.BootFileNumber, fileType: BootServer.BootFileType, machineType: BootServer.MachineType, pup: BOOLEAN] = BEGIN BootServerFriends.AddBootFile[ bootFileNumber, fileName, fileType, machineType, pup]; END; ActivateServer: PUBLIC ENTRY PROCEDURE = BEGIN BootServerFriends.ActivateFiles[]; pleaseStop ¬ FALSE; bootServerFork ¬ FORK Server[]; END; DeactivateServer: PUBLIC ENTRY PROCEDURE = BEGIN pleaseStop ¬ TRUE; JOIN bootServerFork; bootServerFork ¬ NIL; BootServerFriends.DeactivateFiles[]; END; ForgetBootFileList: PUBLIC PROCEDURE = BEGIN BootServerFriends.DeleteBootFileTable[]; END; DeleteServer: PUBLIC ENTRY PROCEDURE = BEGIN ServerHeap.Destroy[]; END; GetStatistics: PUBLIC PROCEDURE RETURNS [BootServer.Counters] = BEGIN RETURN[counters]; END; Server: PROCEDURE = BEGIN cH: Socket.ChannelHandle; b: NSBuffer.Buffer; cH ¬ Socket.Create[NSConstants.bootServerSocket, 0, 2]; Socket.SetWaitTime[cH, 10000--ms--]; UNTIL pleaseStop DO b ¬ NIL; b ¬ Socket.GetPacket[cH ! Socket.TimeOut => CONTINUE]; IF b = NIL THEN LOOP; IF b.ns.packetType = bootServerPacket THEN BEGIN header: LONG POINTER TO BootServerTypes.BootFileRequest = LOOPHOLE[@b.ns.nsWords[0]]; SELECT header.etherBootPacketType FROM simpleRequest => BEGIN bootFileHeader: LONG POINTER TO simpleRequest BootServerTypes.BootFileRequest = LOOPHOLE[header]; target: System.NetworkAddress; Socket.SwapSourceAndDestination[b]; target ¬ Socket.GetDestination[b]; Stats.StatIncr[bootRequests]; counters.microcodeBootFilesRequested ¬ counters.microcodeBootFilesRequested + 1; IF ~booting THEN BEGIN bf: BootServerFriends.BootFile; bf ¬ BootServerFriends.FindBootFile[bootFileHeader.bootFileNumber]; IF bf # NIL THEN BEGIN booting ¬ TRUE; Process.Detach[FORK MicrocodeBooter[bf, target]]; END; END; END; -- busy sppRequest => BEGIN bootFileHeader: LONG POINTER TO sppRequest BootServerTypes.BootFileRequest = LOOPHOLE[header]; target: System.NetworkAddress; connection: NetworkStream.ConnectionID; Socket.SwapSourceAndDestination[b]; target ¬ Socket.GetDestination[b]; connection ¬ bootFileHeader.connectionID; Stats.StatIncr[bootRequests]; counters.bootFilesRequested ¬ counters.bootFilesRequested + 1; IF ~booting THEN BEGIN bf: BootServerFriends.BootFile; bf ¬ BootServerFriends.FindBootFile[bootFileHeader.bootFileNumber]; IF bf # NIL THEN BEGIN booting ¬ TRUE; Process.Detach[FORK FastBooter[bf, target, connection]]; END; END; END; -- busy ENDCASE; END; IF b # NIL THEN Socket.ReturnBuffer[b]; ENDLOOP; Socket.Delete[cH]; END; booting: BOOLEAN ¬ FALSE; wordsPerSwapUnit: CARDINAL = BootServerFriends.pagesPerSwapUnit*BootServerTypes.dataWords; MicrocodeBooter: PUBLIC PROCEDURE [ bf: BootServerFriends.BootFile, target: System.NetworkAddress] = BEGIN pulses: System.Pulses ¬ System.GetClockPulses[]; b: NSBuffer.Buffer; body: NSBuffer.Body; packetNumber: CARDINAL ¬ 1; from: LONG POINTER; wordsLeft: LONG CARDINAL ¬ bf.bytes/2; pagesLeft: CARDINAL ¬ bf.pages; cH: Socket.ChannelHandle; bootData: LONG POINTER TO simpleData BootServerTypes.BootFileRequest; overhead: CARDINAL = SIZE[simpleData BootServerTypes.BootFileRequest]; clumpSize: CARDINAL ¬ BootServerTypes.dataWords; this, next: Space.Interval ¬ Space.nullInterval; IF ~BootServerFriends.LockFileRead[bf] THEN BEGIN booting ¬ FALSE; RETURN; END; IF bf.space = Space.nullInterval THEN BootServerFriends.SetupSpace[bf]; from ¬ bf.space.pointer; next ¬ [from, MIN[BootServerFriends.pagesPerSwapUnit, bf.pages]]; Space.Activate[next]; cH ¬ Socket.Create[System.nullSocketNumber]; FOR page: CARDINAL ¬ 0, page + 1 UNTIL wordsLeft = 0 DO IF (page MOD BootServerFriends.pagesPerSwapUnit) = 0 THEN BEGIN IF this # Space.nullInterval THEN Space.Deactivate[this]; this ¬ next; IF next # Space.nullInterval THEN BEGIN next.pointer ¬ this.pointer + wordsPerSwapUnit; pagesLeft ¬ pagesLeft - BootServerFriends.pagesPerSwapUnit; next.count ¬ MIN[next.count, pagesLeft]; IF pagesLeft = 0 THEN next ¬ Space.nullInterval; END; IF next # Space.nullInterval THEN Space.Activate[next]; END; IF wordsLeft < BootServerTypes.dataWords THEN clumpSize ¬ Inline.LowHalf[wordsLeft]; body ¬ (b ¬ Socket.GetSendBuffer[cH]).ns; Socket.SetDestination[b, target]; body.packetType ¬ bootServerPacket; bootData ¬ LOOPHOLE[@body.nsWords]; bootData­ ¬ [simpleData[ bootFileNumber: bf.code, packetNumber: packetNumber, data:]]; Inline.LongCOPY[from: from, nwords: clumpSize, to: @bootData.data]; Socket.SetPacketWords[b, overhead + clumpSize]; Socket.PutPacket[cH, b]; packetNumber ¬ packetNumber + 1; from ¬ from + clumpSize; wordsLeft ¬ wordsLeft - clumpSize; ENDLOOP; body ¬ (b ¬ Socket.GetSendBuffer[cH]).ns; Socket.SetDestination[b, target]; body.packetType ¬ bootServerPacket; bootData ¬ LOOPHOLE[@body.nsWords]; bootData­ ¬ [simpleData[ bootFileNumber: bf.code, packetNumber: packetNumber, data:]]; Socket.SetPacketWords[b, overhead]; Socket.PutPacket[cH, b]; -- End Marker for Initial Space.Deactivate[this]; IF next # Space.nullInterval THEN Space.Deactivate[next]; Socket.Delete[cH]; pulses ¬ System.Pulses[System.GetClockPulses[] - pulses]; bf.count ¬ bf.count + 1; bf.ms ¬ bf.ms + System.PulsesToMicroseconds[pulses]/1000; BootServerFriends.UnlockFile[bf]; counters.microcodeBootFilesSent ¬ counters.microcodeBootFilesSent + 1; booting ¬ FALSE; END; FastBooter: PUBLIC PROCEDURE [ bf: BootServerFriends.BootFile, target: System.NetworkAddress, connection: NetworkStream.ConnectionID] = BEGIN pulses: System.Pulses ¬ System.GetClockPulses[]; from: LONG POINTER; wordsLeft: LONG CARDINAL ¬ bf.bytes/2; pagesLeft: CARDINAL ¬ bf.pages; clumpSize: CARDINAL ¬ BootServerTypes.dataWords; this, next: Space.Interval ¬ Space.nullInterval; stream: Stream.Handle ¬ NIL; good: BOOLEAN ¬ FALSE; IF ~BootServerFriends.LockFileRead[bf] THEN BEGIN booting ¬ FALSE; RETURN; END; IF bf.space = Space.nullInterval THEN BootServerFriends.SetupSpace[bf]; from ¬ bf.space.pointer; stream ¬ NetworkStream.CreateTransducer[ local: Socket.AssignNetworkAddress[], remote: target, localConnID: NetworkStream.GetUniqueConnectionID[], remoteConnID: connection, activelyEstablish: FALSE, classOfService: transactional ! NetworkStream.ConnectionFailed => CONTINUE]; IF stream = NIL THEN BEGIN -- It happened once. /HGM BootServerFriends.UnlockFile[bf]; booting ¬ FALSE; RETURN; END; next ¬ [from, MIN[BootServerFriends.pagesPerSwapUnit, bf.pages]]; Space.Activate[next]; FOR page: CARDINAL ¬ 0, page + 1 UNTIL wordsLeft = 0 DO IF (page MOD BootServerFriends.pagesPerSwapUnit) = 0 THEN BEGIN IF this # Space.nullInterval THEN Space.Deactivate[this]; this ¬ next; IF next # Space.nullInterval THEN BEGIN next.pointer ¬ this.pointer + wordsPerSwapUnit; pagesLeft ¬ pagesLeft - BootServerFriends.pagesPerSwapUnit; next.count ¬ MIN[next.count, pagesLeft]; IF pagesLeft = 0 THEN next ¬ Space.nullInterval; END; IF next # Space.nullInterval THEN Space.Activate[next]; END; IF wordsLeft < BootServerTypes.dataWords THEN clumpSize ¬ Inline.LowHalf[wordsLeft]; Stream.PutBlock[ stream, [from, 0, 2*clumpSize], TRUE ! NetworkStream.ConnectionSuspended => EXIT]; from ¬ from + clumpSize; wordsLeft ¬ wordsLeft - clumpSize; REPEAT FINISHED => good ¬ NetworkStream.Close[stream] = good; ENDLOOP; Space.Deactivate[this]; IF next # Space.nullInterval THEN Space.Deactivate[next]; Stream.Delete[stream]; pulses ¬ System.Pulses[System.GetClockPulses[] - pulses]; IF good THEN BEGIN bf.count ¬ bf.count + 1; bf.ms ¬ bf.ms + System.PulsesToMicroseconds[pulses]/1000; END; BootServerFriends.UnlockFile[bf]; counters.bootFilesSent ¬ counters.bootFilesSent + 1; booting ¬ FALSE; END; bootRequests ¬ Stats.StatsStringToIndex["Boot Server Requests"]; END.