DIRECTORY Basics USING [ BITOR, HighHalf, LowHalf ], Checksum USING [ComputeChecksumProc], DeviceCleanup USING [Await, Item, Perform, Reason], DLionInputOutput, MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber], MPCodes USING [processorIDChanged, powerOff], PrincOps USING [aCHKSUM, aGETF, alpha, ControlLink, flagsVacant, InterimPageState, PageCount, PageNumber, PageState, PageValue, RealPageNumber, SD, StateVector, sUnimplemented, VersionResult, zMISC], PrincOpsUtils USING [Copy, DisableInterrupts, GetReturnFrame, GetReturnLink, LongCopy, MyLocalFrame], ProcessorFace USING [gmtEpoch, GreenwichMeanTime, ProcessorID, SetMP], TrapSupport USING [BumpPC, OpTrapTable, opTrapTable]; ProcessorHeadDLion: MONITOR IMPORTS Basics, Checksum, DeviceCleanup, PrincOpsUtils, ProcessorFace, TrapSupport EXPORTS DLionInputOutput, MicrocodeBooting, ProcessorFace SHARES Checksum, ProcessorFace = { IOPage: PUBLIC LONG POINTER _ LOOPHOLE[LONG[177400B]]; ProcessorCSBOffset: CARDINAL = 127B; -- 57X ProcessorCSB: TYPE = MACHINE DEPENDENT RECORD [ data2(0): WORD, data1(1): WORD, data0(2): WORD, command(3): ProcessorCommand]; ProcessorCommand: TYPE = MACHINE DEPENDENT RECORD [ busy(0:0..0): BOOL _ TRUE, op(0:1..15): ProcessorOperation]; ProcessorOperation: TYPE = MACHINE DEPENDENT { setTOD(1), readTOD(2), readPID(3), boot(4), (32767)}; TimeOfDayOffset: CARDINAL = 320B; -- 0D0X TimeOfDayClock: TYPE = MACHINE DEPENDENT RECORD [ valid(0): WORD, -- 0 => invalid, 177777B => valid time(1): LONG CARDINAL, lowCheck(3): CARDINAL]; Go: PUBLIC SAFE PROC = TRUSTED { firstUsed: PrincOps.RealPageNumber _ DLionInputOutput.firstReservedPage + DLionInputOutput.reservedPageCount; FOR i: PrincOps.PageNumber IN [0..DLionInputOutput.numberVirtualPages) DO pv: PrincOps.PageValue _ GetPageValue[i]; IF pv.state.flags # PrincOps.flagsVacant THEN firstUsed _ MIN[pv.real, firstUsed]; ENDLOOP; specialRealPages _ firstUsed - DLionInputOutput.firstReservedPage; }; aSETMAP: PrincOps.alpha = 150B; aGETMAPFLAGS: PrincOps.alpha = 151B; aSETMAPFLAGS: PrincOps.alpha = 152B; GetPageValue: PROC [virtual: PrincOps.PageNumber] RETURNS [pv: PrincOps.PageValue] = { OldGetPageValue: PROC [virtual: CARDINAL] RETURNS [state: PrincOps.InterimPageState] = MACHINE CODE {PrincOps.zMISC, PrincOps.aGETF}; NewGetPageValue: PROC [vp: LONG CARDINAL] RETURNS [PrincOps.PageState, LONG CARDINAL] = MACHINE CODE {PrincOps.zMISC, aGETMAPFLAGS}; IF --ProcessorFace.--useLongMapOps THEN [pv.state, pv.real] _ NewGetPageValue[virtual] ELSE [flags: pv.state.flags, realPage: pv.real] _ OldGetPageValue[virtual].state; }; InitializeCleanup: PUBLIC SAFE PROC = TRUSTED { initial: ProcessorFace.ProcessorID _ processorID; item: DeviceCleanup.Item; DO reason: DeviceCleanup.Reason _ DeviceCleanup.Await[@item]; SELECT reason FROM turnOff, kill => NULL -- we have a genuine clock, so don't need to invalidate it!--; turnOn => { -- Can't call procs (maybe no frames) so copy code pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset; current: ProcessorFace.ProcessorID; WHILE pCSB.command.busy DO NULL ENDLOOP; pCSB.command _ [op: readPID]; WHILE pCSB.command.busy DO NULL ENDLOOP; current _ [pCSB.data0, pCSB.data1, pCSB.data2]; IF initial # current THEN { ProcessorFace.SetMP[MPCodes.processorIDChanged]; DO ENDLOOP; }; }; ENDCASE ENDLOOP }; processorID: PUBLIC ProcessorFace.ProcessorID _ GetProcessorID[]; GetProcessorID: PROC RETURNS [ProcessorFace.ProcessorID] = { pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset; WHILE pCSB.command.busy DO NULL ENDLOOP; pCSB.command _ [op: readPID]; WHILE pCSB.command.busy DO NULL ENDLOOP; RETURN[[pCSB.data0, pCSB.data1, pCSB.data2]]; }; firstSpecialRealPage: PUBLIC PrincOps.RealPageNumber _ DLionInputOutput.firstReservedPage; specialRealPages: PUBLIC PrincOps.PageCount _ 0; -- set correctly in initialization code GetNextAvailableVM: PUBLIC SAFE PROC [page: PrincOps.PageNumber] RETURNS [firstPage: PrincOps.PageNumber, count: PrincOps.PageCount] = TRUSTED { IF page < 376B THEN RETURN[page, 376B - page]; page _ MAX[page, 376B + 1]; IF page < 377B THEN RETURN[page, 377B - page]; page _ MAX[page, 377B + 1]; IF page < DLionInputOutput.numberVirtualPages THEN RETURN[page, DLionInputOutput.numberVirtualPages - page]; RETURN[LAST[PrincOps.PageNumber], 0] }; useLongMapOps: PUBLIC BOOL _ TRUE; GreenwichMeanTime: TYPE = ProcessorFace.GreenwichMeanTime; gmtEpoch: GreenwichMeanTime = ProcessorFace.gmtEpoch; GetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC RETURNS [gmt: GreenwichMeanTime] = TRUSTED { tod: LONG POINTER TO TimeOfDayClock = IOPage + TimeOfDayOffset; IF tod.valid = 0 THEN RETURN[gmtEpoch]; DO gmt _ tod.time; IF Basics.LowHalf[gmt] = tod.lowCheck THEN EXIT; ENDLOOP; RETURN }; SetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC [gmt: GreenwichMeanTime] = TRUSTED { pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset; tod: LONG POINTER TO TimeOfDayClock = IOPage + TimeOfDayOffset; WHILE pCSB.command.busy DO NULL ENDLOOP; pCSB.data2 _ Basics.LowHalf[gmt]; pCSB.data1 _ Basics.HighHalf[gmt]; pCSB.command _ [op: setTOD]; tod.valid _ 0; WHILE pCSB.command.busy DO NULL ENDLOOP; WHILE tod.valid = 0 DO NULL ENDLOOP; RETURN }; microsecondsPerHundredPulses: PUBLIC CARDINAL _ 2878; cvTimeoutMask: WORD = 100000B; -- DLion microcode assumes level 0 reservedNakedNotifyMask: PUBLIC WORD _ cvTimeoutMask; millisecondsPerTick: PUBLIC CARDINAL _ 52; InitializeCVTimeouts: PROC = { DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[177753B]]; DIW^ _ Basics.BITOR[DIW^, cvTimeoutMask]; }; BootButton: PUBLIC SAFE PROC = TRUSTED { pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset; PrincOpsUtils.DisableInterrupts[]; WHILE pCSB.command.busy DO NULL ENDLOOP; pCSB.command _ [op: boot]; DO ENDLOOP; }; PowerOff: PUBLIC SAFE PROC [returnIfDisabled: BOOL _ FALSE] = TRUSTED { IF powerOffCount # 0 AND returnIfDisabled THEN RETURN; PrincOpsUtils.DisableInterrupts[]; DeviceCleanup.Perform[turnOff]; DO ProcessorFace.SetMP[MPCodes.powerOff]; IF powerOffCount = 0 THEN EXIT; ENDLOOP; DO IF (GetGreenwichMeanTime[] - ProcessorFace.gmtEpoch) >= (gmtAutomaticPowerOn - ProcessorFace.gmtEpoch) AND (~externalEventRequired OR ExternalEvent[]) THEN BootButton[] ENDLOOP }; powerOffCount: INT _ 0; DisablePowerOff: PUBLIC ENTRY SAFE PROC = TRUSTED { powerOffCount _ powerOffCount + 1; }; EnablePowerOff: PUBLIC ENTRY SAFE PROC = TRUSTED { IF powerOffCount > 0 THEN powerOffCount _ powerOffCount - 1; }; gmtAutomaticPowerOn: ProcessorFace.GreenwichMeanTime; externalEventRequired: BOOL; ExternalEvent: PROC RETURNS [BOOL] = {RETURN[FALSE]}; SetAutomaticPowerOn: PUBLIC SAFE PROC [gmt: ProcessorFace.GreenwichMeanTime, externalEvent: BOOL] = TRUSTED { gmtAutomaticPowerOn _ gmt; externalEventRequired _ externalEvent; }; ResetAutomaticPowerOn: PUBLIC SAFE PROC = TRUSTED { gmtAutomaticPowerOn _ ProcessorFace.gmtEpoch - 1; }; -- infinity BootSpecificMicrocode: PUBLIC PROC [bfn: MicrocodeBooting.BootFileNumber] = { BootButton[]; }; GetBootFileNumber: PUBLIC PROC [type: MicrocodeBooting.MicrocodeType] RETURNS [bfn: MicrocodeBooting.BootFileNumber] = { RETURN[MicrocodeBooting.nullBootFileNumber]; }; UnimplementedInstruction: ERROR = CODE; Unimplemented: PROC = { v: MACHINE DEPENDENT RECORD [a, b: UNSPECIFIED, state: PrincOps.StateVector]; v.state _ STATE; ERROR UnimplementedInstruction; }; trapTable: TrapSupport.OpTrapTable _ [ALL[LOOPHOLE[Unimplemented]], ALL[LOOPHOLE[Unimplemented]]]; UnimplementedTrap: PROC = { l: PrincOps.ControlLink; code: LONG POINTER TO Code; Code: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF CodeByte]; CodeByte: TYPE = [0..255]; opcode: CodeByte; state: PrincOps.StateVector; state _ STATE; state.source _ l _ PrincOpsUtils.GetReturnLink[]; code _ LOOPHOLE[l.frame.accesslink.code.longbase]; opcode _ code[l.frame.pc]; state.dest _ IF opcode = PrincOps.zMISC THEN TrapSupport.opTrapTable.misc[code[l.frame.pc+1]] ELSE TrapSupport.opTrapTable.main[opcode]; IF ~state.dest.proc THEN state.dest.frame.returnlink _ l; RETURN WITH state; -- Flush my frame and transfer to real trap handler }; LocalGetPageValue: PROC [virtual: PrincOps.PageNumber] RETURNS [ps: PrincOps.PageState, pn: LONG CARDINAL] = { pv: PrincOps.PageValue; IF useLongMapOps THEN useLongMapOps _ FALSE ELSE ERROR; TrapSupport.BumpPC[2]; pv _ GetPageValue[virtual]; ps _ pv.state; pn _ pv.real; }; LocalBlkZ: PROC [count: CARDINAL] = { state: PrincOps.StateVector; p: POINTER; state _ STATE; TrapSupport.BumpPC[2]; IF count#0 THEN { p _ @(PrincOpsUtils.GetReturnFrame[].local[0]); p^ _ 0; IF count#1 THEN PrincOpsUtils.Copy[from: p, to: p+1, nwords: count-1]; }; state.dest.frame _ PrincOpsUtils.GetReturnFrame[]; RETURN WITH state; }; LongBlkZ: PROC [p: LONG POINTER, count: CARDINAL] RETURNS [resultP: LONG POINTER] = { state: PrincOps.StateVector; state _ STATE; TrapSupport.BumpPC[2]; IF count#0 THEN { p^ _ 0; IF count#1 THEN PrincOpsUtils.LongCopy[from: p, to: p+1, nwords: count-1]; }; resultP _ p; state.dest.frame _ PrincOpsUtils.MyLocalFrame[]; TRANSFER WITH state; }; UVersion: PROC RETURNS [PrincOps.VersionResult] = { TrapSupport.BumpPC[2]; RETURN [[ machineType: dandelion, majorVersion: 0, unused: 0, floatingPoint: FALSE, cedar: FALSE, releaseDate: ProcessorFace.gmtEpoch/86400]]; }; ComputeChecksum: PRIVATE PROC [cs, nWords: CARDINAL, p: LONG POINTER] RETURNS [CARDINAL] = { RETURN[Checksum.ComputeChecksumProc[cs, nWords, p]]; }; InitializeCVTimeouts[]; PrincOps.SD[PrincOps.sUnimplemented] _ LOOPHOLE[UnimplementedTrap]; PrincOps.SD[137B] _ LOOPHOLE[@trapTable]; TrapSupport.opTrapTable.misc[PrincOps.aCHKSUM] _ LOOPHOLE[ComputeChecksum]; TrapSupport.opTrapTable.misc[100B] _ LOOPHOLE[LocalBlkZ]; TrapSupport.opTrapTable.misc[102B] _ LOOPHOLE[LongBlkZ]; TrapSupport.opTrapTable.misc[104B] _ LOOPHOLE[UVersion]; TrapSupport.opTrapTable.misc[aGETMAPFLAGS] _ LOOPHOLE[LocalGetPageValue]; }. LOG August 5, 1980 10:28 AM Forrest Created file. August 12, 1980 10:41 AM McJones Added dedicatedRealMemory. September 18, 1980 1:26 PM Sandman Changed cvTimeoutMask, millisecondsPerTick for new PSB format. October 2, 1980 2:43 PM Forrest Changed microsecondsPerHundredPulses to 2878 from 2880. October 3, 1980 5:26 PM Forrest Moved in unimplemented trap. November 10, 1980 4:10 PM Forrest Added memory allocation junk. January 23, 1981 approx Gobbel ? February 6, 1981 12:04 PM Knutsen Make compatible with new PrincOps. August 27, 1982 9:38 am Taft Add TrapSupport, MicrocodeBooting, MicrocodeVersion, etc. February 27, 1983 2:31 pm Taft Export HeadStartChain.Start; absorb TrapSupportImpl June 4, 1986 6:48:39 pm PDT; Orr Take out ProcessorFaceExtras, change in PrincOps.SD, GetPageValue, OldGetPageValue (local of GetPageValue), NewGetPageValue (local of GetPageValue), InitializeCleanup, useLongMapOps, ResetAutomaticPowerOn, TrapSupport, January ŒProcessorHeadDLion.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Taft, February 27, 1983 3:40 pm Willie-Sue, January 31, 1985 3:05:00 pm PST Russ Atkinson (RRA) June 13, 1986 5:46:56 pm PDT Doug Wyatt, February 26, 1985 5:56:58 pm PST Hal Murray, May 24, 1986 10:16:49 pm PDT DLionInputOutput Initialization By now start trap has occurred and main-body code has run. Scan the VM looking for the lowest real page mapped. Use this as upper bound on special real memory area (The microcode likes to use some of the bank 0 real memory for the Germ). NOTE: Ideally GetPageValue should be from a common definitions file. We share this definition with BootFile and VMInternal. Gets the state and real page of a virtual page. Rollback on a different machine? Processor ID Real memory configuration Virtual memory layout I believe that 376B and 377B are actually available on DLions, but at present the Germ assumes they aren't. ADB 1/23/84 GreenwichMeanTime Interval time Naked notifies Condition variable time Booting and power control NOTE: This code depends on the greenwich mean time clock running with interrupts disabled and devices turned off. forever Bumps the power off disable count. This is useful during a critical operation to avoid power off operations. Decrements the power off disable count (pins at 0). MicrocodeBooting; degenerate implementation for now TrapSupport Software assist for microcode assumes return link is a frame, and has been started. This trap procedure is called only if the Cedar TrapSupport microcode is NOT present. If the microcode IS present, it calls the appropriate trap routine directly. If handler is fixed-frame, manually plant the return link. (Microcode does that for traps, but not for ordinary XFERs to frames.) Trap support for Cedar-related opcodes Main body code Russ Atkinson (RRA) June 4, 1986 6:24:56 pm PDT Added support for long map opcodes. Κ Θ˜codešœ™Kšœ Οmœ7™BKšœ™K™+K™0K™,K™(—˜šΟk ˜ Kšœžœžœ˜*Kšœ žœ˜%Kšœžœ ˜3K˜Kšœžœ5˜KKšœžœ ˜-Kšœ žœ‚žœ5˜ΗKšœžœR˜eKšœžœ3˜FKšœ žœ$˜5K˜——šΟnœž˜KšžœK˜RKšžœ2˜9Kšžœ˜"—K˜šœ™K˜Kš œžœžœžœžœžœ ˜6K˜Kšœžœ Οc˜+K˜š œžœžœž œžœ˜/Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜K˜K˜—š œžœžœž œžœ˜3Kšœžœžœ˜K˜!K˜—šœžœžœž œ˜.K˜5K˜—Kšœžœ  ˜)K˜š œžœžœž œžœ˜1Kšœ žœ !˜1Kšœ žœžœ˜Kšœ žœ˜K˜——šœ™K˜š Ÿœžœžœžœžœ˜ Kšœ:™:Kšœ³™³Kšœm˜mšžœžœ*ž˜IKšœ)˜)Kšžœ'žœ žœ˜RKšžœ˜—KšœB˜BKšœ˜—K˜šΠblœ Ÿ œb™|K˜K˜$K˜$—šŸ œžœ žœ˜VKšœ/™/Kš Ÿœžœ žœžœ&žœžœ"˜…KšŸœžœžœžœžœžœžœžœžœ ˜„šžœ œ ˜"Kšžœ/˜3KšžœM˜Q—Kšœ˜—K˜š Ÿœžœžœžœžœ˜/Kšœ1˜1Kšœ˜šž˜Kšœ:˜:šžœž˜Kšœžœ =œ˜Tšœ>˜>Kšœžœžœžœ,˜AKšž œž˜#Kšžœžœžœžœ˜(K˜Kšžœžœžœžœ˜(Kšœ/˜/šžœžœ˜Kšœ ™ Kšœ0˜0Kšžœžœ˜——Kšž˜—Kšž˜—Kšœ˜—K˜—šœ ™ K˜Kšœ žœ.˜AšŸœžœžœ ˜˜ZK˜Kšœžœ '˜XK˜—šœ™K˜š Ÿœžœžœžœžœ?žœ˜Kšœy™yKšžœ žœžœ˜.Kšœžœ˜Kšžœ žœžœ˜.Kšœžœ˜Kšžœ+˜-Kšž œ3˜>Kšžœžœ˜$Kšœ˜K˜—šœž œžœ˜"K˜——šœ™K˜Kšœžœ#˜:K˜5K˜š Ÿœžœž œžœžœžœ˜YKšœžœžœžœ+˜?Kšžœžœžœ ˜'šž˜K˜Kšžœ$žœžœ˜0Kšžœ˜—Kšž˜Kšœ˜K˜—š Ÿœžœž œžœžœ˜QKšœžœžœžœ,˜AKšœžœžœžœ+˜?Kšžœžœžœžœ˜(K˜!K˜"K˜K˜Kšžœžœžœžœ˜(Kšžœžœžœžœ˜$Kšž˜Kšœ˜K˜——šœ ™ K˜Kšœžœžœ˜5K˜—šœ™K˜Kšœžœ  "˜AKšœžœžœ˜5K˜—šœ™K˜Kšœžœžœ˜*šŸœžœ˜Kšžœžœžœžœžœžœžœ ˜4Kšžœ žœžœ˜)Kšœ˜K˜——šœ™K˜š Ÿ œžœžœžœžœ˜(Kšœžœžœžœ,˜AK˜"Kšžœžœžœžœ˜(K˜Kšžœžœ˜ Kšœ˜K˜—šŸœžœžœžœžœžœžœ˜GKšœ@™@Kšœ0™0Kšžœžœžœžœ˜6K˜"K˜šž˜K˜&Kšžœžœžœ˜Kšžœ˜—šž˜Kšœ™šžœ2˜4K˜1Kšžœžœžœ ˜A—Kšž˜—Kšœ˜K˜—šœžœ˜K˜—š Ÿœžœžœžœž˜3Kšœm™mKšœ"˜"Kšœ˜K™—š Ÿœžœžœžœž˜2Kšœ3™3Kšžœžœ#˜