-- File: BootChannelDicentra.mesa - last edit: -- AOF 11-Feb-88 16:57:45 -- HGM 5-Dec-83 20:40:38 -- Copyright (C) 1983, 1988 by Xerox Corporation. All rights reserved. << This isn't really a Channel, but it saves a lot of space in the initial microcode. This module must be first on the chain. It responds to a deviceType of anyEthernet by adjusting the bootLocation so that some other channel will do the work. General plan: Look for a valid boot location in the EERom. If not, try for one in page 0 of the Germ EProm. (Not implemented yet.) If that fails too, use a wired in default location. (NS Booting.) If the altBoot button is down, cycle magic numbers through the MP until altBoot goes up. Currently, there are 3 clumps of numbers. One for NS booting, a second for phone booting, and another for Pup booting. The thousands digit is the device index. >> DIRECTORY Boot USING [Location], BootChannel USING [Create, Handle, Operation, Result], Checksum USING [ComputeChecksum], DeviceTypes USING [anyEthernet, ethernet, ethernetOne], Environment USING [Byte, bytesPerWord], Inline USING [BytePair, HighByte, LowByte], NSConstants USING [bootServerSocket], PilotMP USING [cGermAction], ProcessorFace USING [mp, SetMP], System USING [ broadcastHostNumber, GetClockPulses, HostNumber, MicrosecondsToPulses, NetworkAddress, nullNetworkNumber, Pulses], DicentraInputOutput USING [GetExternalStatus, IOAddress, Input, Output], EERom USING [BootLocation, bootLocationVersion, bytesPerChip, WholeEERom], MultibusAddresses USING [eprom, timeout], PhoneFace USING [krockDeivceOffsetForBooting, phoneLine, TurnOff]; BootChannelDicentra: PROGRAM IMPORTS remainingChannels: BootChannel, Checksum, ProcessorFace, System, Inline, DicentraInputOutput, PhoneFace EXPORTS BootChannel = BEGIN pupBootFileBase: CARDINAL = 140000B; nsBootFileBase: BootFileNumberRep = [0, 0AA00H, 400H]; Create: PUBLIC PROC [ pLocation: LONG POINTER TO Boot.Location, operation: BootChannel.Operation, buffer: LONG POINTER ← NIL] RETURNS [result: BootChannel.Result, handle: BootChannel.Handle] = BEGIN PhoneFace.TurnOff[]; -- START Trap allocates CSB IF pLocation.deviceType = DeviceTypes.ethernet AND pLocation.deviceOrdinal >= PhoneFace.krockDeivceOffsetForBooting THEN BEGIN -- Krockery because Phone Booting isn't in any interface pLocation.deviceType ← PhoneFace.phoneLine; pLocation.deviceOrdinal ← pLocation.deviceOrdinal - PhoneFace.krockDeivceOffsetForBooting; END; IF pLocation.deviceType = DeviceTypes.anyEthernet THEN BEGIN SELECT TRUE FROM GetLocationFromEERom[pLocation] => NULL; GetLocationFromGermProm[pLocation] => NULL; ENDCASE => GetDefaultLocation[pLocation]; IF DicentraInputOutput.GetExternalStatus[].altBoot THEN GetLocationFromButton[pLocation]; END; RETURN remainingChannels.Create[pLocation, operation]; END; GetLocationFromEERom: PROCEDURE [location: LONG POINTER TO Boot.Location] RETURNS [BOOLEAN] = BEGIN temp: EERom.BootLocation; FetchBootLocation[@temp]; IF ~VersionValid[@temp] THEN RETURN[FALSE]; IF ~ChecksumValid[@temp] THEN RETURN[FALSE]; location↑ ← temp.location; RETURN[TRUE]; END; GetLocationFromGermProm: PROCEDURE [location: LONG POINTER TO Boot.Location] RETURNS [BOOLEAN] = BEGIN RETURN[FALSE]; END; GetDefaultLocation: PROCEDURE [location: LONG POINTER TO Boot.Location] = BEGIN FabricateEthernetLocation[location, 0]; END; GetLocationFromButton: PROCEDURE [location: LONG POINTER TO Boot.Location] = BEGIN teMP: CARDINAL = ProcessorFace.mp; Where: TYPE = {ethernet, phone, ethernetOne}; mp: ARRAY Where OF CARDINAL = [240, 260, 280]; DeactivateWatchdog[]; -- Enable booting over slow lines FOR device: CARDINAL IN [0..3) DO FOR where: Where IN Where DO FOR i: CARDINAL IN [0..5) DO ProcessorFace.SetMP[mp[where] + i + device * 1000]; PauseAWhile[]; IF ~DicentraInputOutput.GetExternalStatus[].altBoot THEN BEGIN SELECT where FROM ethernet => FabricateEthernetLocation[location, i]; phone => FabricatePhoneLocation[location, i]; ethernetOne => FabricateEthernetOneLocation[location, i]; ENDCASE => ERROR; location.deviceOrdinal ← device; ProcessorFace.SetMP[teMP]; ProcessorFace.SetMP[PilotMP.cGermAction]; -- Bug in GermOpsImpl RETURN; END; ENDLOOP; ENDLOOP; ENDLOOP; -- Maybe the MP is unplugged? FabricateEthernetLocation[location, 0]; END; PauseAWhile: PROCEDURE = BEGIN duration: System.Pulses = System.MicrosecondsToPulses[700000]; start: System.Pulses = System.GetClockPulses[]; UNTIL (System.GetClockPulses[]-start) > duration DO ENDLOOP; END; FabricateEthernetLocation: PROCEDURE [ location: LONG POINTER TO Boot.Location, bootFileOffset: CARDINAL] = BEGIN where: EthernetLocation; bfn: BootFileNumberRep ← nsBootFileBase; bfn.c ← bfn.c + bootFileOffset; where ← [ bfn: LOOPHOLE[bfn], address: [ net: System.nullNetworkNumber, host: System.broadcastHostNumber, socket: NSConstants.bootServerSocket] ]; location↑ ← [ deviceType: DeviceTypes.ethernet, deviceOrdinal: 0, vp: TRASH ]; LOOPHOLE[@location.vp, LONG POINTER TO EthernetLocation]↑ ← LOOPHOLE[where]; END; FabricatePhoneLocation: PROCEDURE [ location: LONG POINTER TO Boot.Location, bootFileOffset: CARDINAL] = BEGIN FabricateEthernetLocation[location, bootFileOffset]; location.deviceType ← PhoneFace.phoneLine; END; FabricateEthernetOneLocation: PROCEDURE [ location: LONG POINTER TO Boot.Location, bootFileOffset: CARDINAL] = BEGIN location↑ ← [ deviceType: DeviceTypes.ethernetOne, deviceOrdinal: 0, vp: ethernetOne [ bootFileNumber: pupBootFileBase + bootFileOffset, net: 0, host: 0 ] ]; END; BootFileNumber: TYPE = RECORD [System.HostNumber]; BootFileNumberRep: TYPE = MACHINE DEPENDENT RECORD [a, b, c: WORD]; EthernetLocation: TYPE = MACHINE DEPENDENT RECORD [ bfn(0): BootFileNumber, address(3): System.NetworkAddress]; defaultBootFileNumber: BootFileNumber = LOOPHOLE[nsBootFileBase]; -- This code should live in other modules. Having it here avoids dragging in trash. eprom: DicentraInputOutput.IOAddress = MultibusAddresses.eprom; timeout: DicentraInputOutput.IOAddress = MultibusAddresses.timeout; DeactivateWatchdog: PROCEDURE = BEGIN DicentraInputOutput.Output[002H, timeout + 00CH]; -- Counter 3 Cntrl ← Trgr, Gate off END; eeRom: POINTER TO EERom.WholeEERom = LOOPHOLE[8000H]; writePulse: WORD = 0800H; -- NB: Low TRUE firstChip: CARDINAL = 4; ReadByte: PROCEDURE [loc: POINTER, offset: CARDINAL] RETURNS [data: Environment.Byte] = BEGIN byteIndex, chip, byteWithinChip: CARDINAL; byteIndex ← Environment.bytesPerWord*LOOPHOLE[loc, CARDINAL] + offset; chip ← firstChip + (byteIndex / EERom.bytesPerChip); byteWithinChip ← byteIndex MOD EERom.bytesPerChip; byteWithinChip ← byteWithinChip + writePulse; DicentraInputOutput.Output[Inline.HighByte[byteWithinChip], eprom + 00DH]; -- Port A Data DicentraInputOutput.Output[Inline.LowByte[byteWithinChip], eprom + 00EH]; -- Port B Data DicentraInputOutput.Output[0FFH, timeout + 023H]; -- Port A Direction ← All in DicentraInputOutput.Output[000H, eprom + 00FH]; -- Port C Data ← Output Enable DicentraInputOutput.Output[chip, timeout + 00EH]; -- Port B Data data ← DicentraInputOutput.Input[timeout + 00DH]; -- Port A Data DicentraInputOutput.Output[008H, eprom + 00FH]; -- Port C Data ← No Output Enable DicentraInputOutput.Output[00FH, timeout + 00EH]; -- Port B Data ← Idle END; FetchBootLocation: PROCEDURE [bits: LONG POINTER TO EERom.BootLocation] = BEGIN info: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← LOOPHOLE[bits]; address: POINTER ← @eeRom.bootLocation; FOR i: CARDINAL IN [0..Environment.bytesPerWord*SIZE[EERom.BootLocation]) DO info[i] ← ReadByte[address, i]; ENDLOOP; END; VersionValid: PROCEDURE [bootLocation: POINTER TO EERom.BootLocation] RETURNS [ok: BOOLEAN] = BEGIN RETURN[bootLocation.version = EERom.bootLocationVersion]; END; ChecksumValid: PROCEDURE [bootLocation: POINTER TO EERom.BootLocation] RETURNS [ok: BOOLEAN] = BEGIN -- checksum is known to be the first word checksum: WORD = Checksum.ComputeChecksum[0, SIZE[EERom.BootLocation]-1, bootLocation+1]; RETURN[checksum = bootLocation.checksum]; END; END....