DIRECTORY BootFile USING [ Location, MemorySizeToFileSize ], Booting USING [ Bootee, BootFileNumber, CheckpointProc, MicrocodeType, RollbackProc, Switches ], DeviceCleanup USING [ Perform ], File USING [ Create, Error, Info, FP, Handle, Open, nullFP, nullVolumeID, PageCount, SetSize, SystemVolume, Volume, VolumeFile, VolumeID ], FileBackdoor USING [ GetRoot, SetRoot], FileInternal USING [ GetFileLocation, GetLogicalLocation, GetPhysicalLocation ], GermSwap USING [ bootedFrom, InLoad, OutLoad, switches ], MicrocodeBooting USING [ GetBootFileNumber, BootSpecificMicrocode ], MPCodes USING [ emptyMP ], PhysicalVolume USING [ GetPhysical, NextPhysical, Physical, PhysicalInfo ], ProcessorFace USING [ BootButton, SetMP ], PrincOps USING [ maxPagesInVM, PageValue, PsbHandle, wordsPerPage ], PrincOpsUtils USING [ DisableInterrupts, EnableInterrupts, ReadPSB, ReadPTC, ReadWDC, WritePSB, WritePTC, WriteWDC ], Rope USING [ Length, ROPE ], VM USING [ VMPartition ], VMBacking USING [ RecoverRealMemory ], VMSideDoor USING [ rmPages ], VMStatistics USING [ VirtualAllocation ], VolumeFormat USING [ nullDiskFileID ]; BootingImpl: CEDAR MONITOR IMPORTS BootFile, DeviceCleanup, File, FileBackdoor, FileInternal, GermSwap, MicrocodeBooting, PhysicalVolume, ProcessorFace, PrincOpsUtils, Rope, VMBacking, VMSideDoor, VMStatistics EXPORTS Booting = { pagesInMap: INT = PrincOps.maxPagesInVM / (PrincOps.wordsPerPage / SIZE[PrincOps.PageValue]); switches: PUBLIC Booting.Switches _ GermSwap.switches; GetBootFileNumber: PUBLIC PROC [type: Booting.MicrocodeType] RETURNS [Booting.BootFileNumber] = TRUSTED { RETURN[ MicrocodeBooting.GetBootFileNumber[type] ]; }; Boot: PUBLIC PROC [boot: Booting.Bootee, switches: Booting.Switches, outload: Booting.Bootee _ [noOp[]] ] RETURNS [rejection: Rope.ROPE _ NIL] = TRUSTED { sys: File.Volume = File.SystemVolume[]; GetLocation: PROC [from: Booting.Bootee] RETURNS [loc: BootFile.Location] = TRUSTED { WITH b: from SELECT FROM noOp => NULL; file => loc _ FileInternal.GetFileLocation[b.file, b.firstPage]; logical => { v: File.Volume = IF b.volume = NIL THEN sys ELSE b.volume; IF v = NIL THEN ERROR File.Error[unknownFile]; loc _ FileInternal.GetLogicalLocation[v, b.root]; IF loc.diskFileID = VolumeFormat.nullDiskFileID THEN ERROR File.Error[unknownFile]; }; physical => { id: File.VolumeID = IF b.volume = File.nullVolumeID AND sys # NIL THEN PhysicalVolume.PhysicalInfo[PhysicalVolume.GetPhysical[sys]].id ELSE b.volume; FOR p: PhysicalVolume.Physical _ PhysicalVolume.NextPhysical[NIL], PhysicalVolume.NextPhysical[p] UNTIL p = NIL DO IF PhysicalVolume.PhysicalInfo[p].id = id THEN { loc _ FileInternal.GetPhysicalLocation[p, b.root]; IF loc.diskFileID = VolumeFormat.nullDiskFileID THEN ERROR File.Error[unknownFile]; EXIT }; REPEAT FINISHED => ERROR File.Error[unknownFile] ENDLOOP; }; microcode => NULL; bootButton => NULL; self => loc _ GermSwap.bootedFrom.location; ENDCASE; }; outloadWanted: BOOL _ outload.type # noOp; outloadLoc, inloadLoc: BootFile.Location; IF (rejection _ CallBootingProcs[]) # NIL THEN RETURN; IF NOT outloadWanted AND sys # NIL AND FileBackdoor.GetRoot[sys, debugger].fp # File.nullFP THEN { outloadWanted _ TRUE; outload _ [logical[sys, debugger]]; }; IF outloadWanted THEN outloadLoc _ GetLocation[outload]; inloadLoc _ GetLocation[boot]; rejection _ BootFromLocation[ outloadLoc: IF outloadWanted THEN @outloadLoc ELSE NIL, boot: WITH b: boot SELECT FROM noOp => [noOp[]], bootButton => [bootButton[]], microcode => [microcode[b.bfn]], ENDCASE => [inload[@inloadLoc]], switches: switches]; }; CallBootingProcs: PUBLIC ENTRY PROC RETURNS [rejection: Rope.ROPE _ NIL] = TRUSTED { FOR this: REF ProcsRec _ checkpoints, this.nextC UNTIL this = NIL DO IF this.b # NIL THEN { rejection _ (this.b)[this.clientData]; IF rejection.Length[] # 0 THEN RETURN; }; ENDLOOP; rejection _ NIL; }; inloadedOnce: PUBLIC BOOL _ FALSE; BootRecord: TYPE = RECORD[SELECT t: * FROM noOp => NULL, inload => [inloadLoc: POINTER TO BootFile.Location], bootButton => NULL, microcode => [bfn: Booting.BootFileNumber], ENDCASE]; BootFromLocation: ENTRY PROC [outloadLoc: POINTER TO BootFile.Location _ NIL, boot: BootRecord, switches: Booting.Switches] RETURNS [rejection: Rope.ROPE _ NIL] = TRUSTED { ENABLE UNWIND => NULL; self: BootFile.Location _ GermSwap.bootedFrom.location; inloaded: BOOL _ FALSE; IF outloadLoc # NIL THEN { rejection _ CallCheckpointProcs[]; IF rejection # NIL THEN RETURN }; inloadedOnce _ FALSE; PrincOpsUtils.DisableInterrupts[]; -- make it hold still first DeviceCleanup.Perform[turnOff]; IF outloadLoc # NIL THEN { psb: PrincOps.PsbHandle; ptc: CARDINAL; wdc: CARDINAL; -- should be in outload file? psb _ PrincOpsUtils.ReadPSB[]; ptc _ PrincOpsUtils.ReadPTC[]; wdc _ PrincOpsUtils.ReadWDC[]; inloaded _ GermSwap.OutLoad[outloadLoc, restore] # outLoaded; PrincOpsUtils.WriteWDC[wdc]; PrincOpsUtils.WritePTC[ptc]; PrincOpsUtils.WritePSB[psb]; }; IF NOT inloaded THEN { WITH b: boot SELECT FROM noOp => NULL; bootButton => ProcessorFace.BootButton[--switches--]; microcode => MicrocodeBooting.BootSpecificMicrocode[b.bfn--, switches--]; inload => { VMBacking.RecoverRealMemory[]; -- so that the germ can find it for the next guy. DeviceCleanup.Perform[disconnect]; GermSwap.InLoad[NIL, NIL, 0, b.inloadLoc, switches]; }; ENDCASE => ERROR; }; IF inloadedOnce THEN { newSwitches: Booting.Switches _ ALL[FALSE]; newSwitches[w] _ TRUE; GermSwap.InLoad[NIL, NIL, 0,@self, newSwitches]; }; DeviceCleanup.Perform[turnOn]; ProcessorFace.SetMP[MPCodes.emptyMP]; PrincOpsUtils.EnableInterrupts[]; IF outloadLoc # NIL THEN CallRollbackProcs[]; }; ProcsRec: TYPE = RECORD[ c: Booting.CheckpointProc, r: Booting.RollbackProc, b: Booting.CheckpointProc, clientData: REF ANY, nextC: REF ProcsRec _ NIL, nextR: REF ProcsRec _ NIL]; checkpoints: REF ProcsRec _ NIL; -- one end of a two-way linked list rollbacks: REF ProcsRec _ NIL; -- other end of that list RegisterProcs: PUBLIC ENTRY PROC [c: Booting.CheckpointProc _ NIL, r: Booting.RollbackProc _ NIL, b: Booting.CheckpointProc _ NIL, clientData: REF ANY _ NIL] = { ENABLE UNWIND => NULL; new: REF ProcsRec = NEW[ProcsRec _ [c: c, r: r, b: b, clientData: clientData]]; IF rollbacks = NIL THEN rollbacks _ new; IF checkpoints # NIL THEN checkpoints.nextR _ new; new.nextC _ checkpoints; checkpoints _ new; }; Deregister: PUBLIC ENTRY PROC [c: Booting.CheckpointProc _ NIL, r: Booting.RollbackProc _ NIL, b: Booting.CheckpointProc _ NIL] = { ENABLE UNWIND => NULL; prev: REF ProcsRec _ NIL; FOR this: REF ProcsRec _ checkpoints, this.nextC UNTIL this = NIL DO IF this.c = c AND this.r = r AND this.b = b THEN { IF this.nextR = NIL THEN checkpoints _ this.nextC ELSE this.nextR.nextC _ this.nextC; IF this.nextC = NIL THEN rollbacks _ this.nextR ELSE this.nextC.nextR _ this.nextR; EXIT }; prev _ this; ENDLOOP; }; CallCheckpointProcs: INTERNAL PROC RETURNS [rejection: Rope.ROPE _ NIL] = TRUSTED { FOR this: REF ProcsRec _ checkpoints, this.nextC UNTIL this = NIL DO IF this.c # NIL THEN { rejection _ (this.c)[this.clientData]; IF rejection.Length[] = 0 THEN rejection _ NIL ELSE { -- undo the damage caused so far ... FOR undo: REF ProcsRec _ this.nextR, undo.nextR UNTIL undo = NIL DO IF undo.c # NIL AND undo.r # NIL THEN (undo.r)[this.clientData] ENDLOOP; RETURN }; }; ENDLOOP; }; CallRollbackProcs: INTERNAL PROC = TRUSTED { FOR this: REF ProcsRec _ rollbacks, this.nextR UNTIL this = NIL DO IF this.r # NIL THEN (this.r)[this.clientData]; ENDLOOP; }; Checkpoint: PUBLIC PROC RETURNS [rejection: Rope.ROPE _ NIL] = { mySwitches: Booting.Switches _ ALL[FALSE]; mySwitches[v] _ TRUE; -- => copy VM for checkpoint VerifyFile[File.SystemVolume[], checkpoint]; RETURN[Boot[ boot: [self[]], switches: mySwitches, outload: [logical[root: checkpoint]] ]] }; VerifyFile: PROC [volume: File.Volume, which: File.VolumeFile] = TRUSTED { size: File.PageCount _ BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+256; oldFP: File.FP = FileBackdoor.GetRoot[volume, which].fp; new: File.Handle; { -- try to guess the correct size, so our FS will do volume flushing size _ size - VMSideDoor.rmPages; -- size _ boot file overhead FOR p: VM.VMPartition IN VM.VMPartition DO pagesAllocated, pagesFreed, pagesInPartition: INT; [pagesAllocated, pagesFreed, pagesInPartition] _ VMStatistics.VirtualAllocation[p]; size _ size + (pagesAllocated-pagesFreed); ENDLOOP; size _ size + pagesInMap + 2; -- guess for checkpoint file overhead }; new _ File.Open[volume, oldFP ! File.Error => { new _ NIL; CONTINUE} ]; IF new = NIL THEN new _ File.Create[volume, size]; IF File.Info[new].size < size THEN File.SetSize[new, size]; FileBackdoor.SetRoot[which, new]; }; }. ͺBootingImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Cedar Nucleus (Files): per-file operations, locking file header data structures Andrew Birrell September 20, 1983 3:35 pm Russ Atkinson February 20, 1985 2:58:08 pm PST Bob Hagmann January 31, 1985 11:26:52 am PST # of pages in the VM map that exists inside of the inload/outload file ******** Exports to Booting interface ******** Calls the booting procs to determine if there is any reason to NOT boot. NIL is returned if it is OK to boot. The booting procs should perform no significant state changes (forcing flushes of files is OK, for example). nww _ PrincOpsUtils.ReadNWW[]; PrincOpsUtils.WriteNWW[Basics.BitOR[nww, PrincOpsUtils.ReadNWW[]]]; Can't get here Inloaded twice: VM backing file has been disturbed by a previous inload, so re-boot ******** Checkpoint facilities ******** Add to head of CheckpointProcs and tail of RollbackProcs Κ 3˜codešœ™Kšœ Οmœ1™˜PKšœ žœ+˜9Kšœžœ.˜DKšœžœ ˜Kšœžœ7˜KKšœžœ˜*Kšœ žœ6˜DKšœžœb˜uKšœžœ žœ˜Kšžœžœ˜Kšœ žœ˜&Kšœ žœ ˜Kšœ žœ˜)Kšœ žœ˜&—K˜šœ žœž˜Kšžœ―˜ΆKšžœžœžœ˜K˜—šœ žœ˜Kšœ1žœ˜KKšœF™F—K˜Kšœ.™.˜Kšœ žœ&˜6K˜š Οnœžœžœžœžœ˜iKšžœ-˜3Kšœ˜—K˜šŸœžœžœXžœžœžœžœ˜šKšœ'˜'šŸ œžœžœžœ˜Ušžœ žœž˜Kšœžœ˜ šœ˜Kšœ8˜8—šœ ˜ Kš œžœ žœžœžœ ˜:Kšžœžœžœžœ˜.Kšœ1˜1Kšžœ-˜/Kšžœžœ˜#Kšœ˜—šœ ˜ šœžœžœž˜AKšžœ@˜DKšžœ ˜—šžœ:žœ˜BKšœžœž˜/šžœ'žœ˜0Kšœ2˜2Kšžœ-˜/Kšžœžœ˜#Kšž˜Kšœ˜——Kšžœžœžœ˜0Kšžœ˜Kšœ˜—Kšœ žœ˜Kšœžœ˜šœ˜Kšœ#˜#——Kšžœ˜Kšœ˜—Kšœžœ˜*Kšœ)˜)Kšžœ$žœžœžœ˜6š žœžœžœžœžœ5žœ˜bKšœžœ˜Kšœ#˜#Kšœ˜—Kšžœžœ#˜8Kšœ˜šœ˜Kš œ žœžœ žœžœ˜7šœžœ žœž˜Kšœ˜Kšœ˜Kšœ ˜ Kšžœ˜ —Kšœ˜—Kšœ˜—K˜šŸœžœžœžœžœžœžœžœ˜TK™άš žœžœ$žœžœž˜Dšžœ žœžœ˜Kšœ&˜&Kšžœžœžœ˜&Kšœ˜—Kšžœ˜—Kšœ žœ˜Kšœ˜K˜—Kšœžœžœžœ˜"K˜šœ žœžœžœž˜*Kšœžœ˜ Kšœžœžœ˜4Kšœžœ˜Kšœ+˜+Kšžœ˜ —K˜šŸœžœžœžœžœžœ0žœžœžœžœ˜¬Kšžœžœžœ˜Kšœ7˜7Kšœ žœžœ˜šžœžœ˜Kšœ"˜"Kšžœ žœžœžœ˜!—Kšœžœ˜Kšœ#Οc˜>Kšœ˜šžœžœ˜Kšœžœžœ ˜TKšœ˜Kšœ˜Kšœ˜Kšœ™Kšœ=˜=KšœC™CKšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœžœ žœ˜šžœ žœž˜Kšœžœ˜ Kšœ'  œ˜5Kšœ9 œ˜Išœ ˜ Kšœ 1˜PK˜"Kšœžœžœ˜4Kšœ˜——Kšžœžœ˜Kšœ™Kšœ˜—šžœžœ˜KšœS™SKšœ žœžœ˜+Kšœžœ˜Kšœžœžœ˜0Kšœ˜—Kšœ˜K˜%Kšœ!˜!Kšžœžœ˜-Kšœ˜—K˜—Kšœ'™'™šœ žœžœ˜K˜K˜K˜Kšœ žœžœ˜Kšœžœ žœ˜Kšœžœ žœ˜—K˜Kšœ žœ žœ #˜DKšœ žœ žœ ˜8K˜šŸ œžœžœžœžœžœžœžœžœžœ˜‘Kšžœžœžœ˜Kšœžœ žœ8˜OKšœ8™8Kšžœ žœžœ˜(Kšžœžœžœ˜2Kšœ+˜+Kšœ˜—K˜šŸ œžœžœžœžœžœžœ˜ƒKšžœžœžœ˜Kšœžœ žœ˜š žœžœ$žœžœž˜Dšžœ žœ žœ žœ˜2Kšžœžœžœžœ˜UKšžœžœžœžœ˜SKšž˜Kšœ˜—K˜ Kšžœ˜—Kšœ˜—K˜šŸœžœžœžœžœžœžœ˜Sš žœžœ$žœžœž˜Dšžœ žœ˜Kšœ&˜&Kšžœ˜Kšžœ ž˜šžœ $˜+Kšžœžœ#žœž˜@Kšžœžœ žœžœ žœžœžœ˜KKšž˜Kšœ˜—Kšœ˜——Kšžœ˜Kšœ˜—K˜šŸœžœžœžœ˜,šžœžœ"žœž˜BKšžœ žœžœ˜/Kšžœ˜—Kšœ˜—K˜š Ÿ œžœžœžœžœžœ˜@Kšœžœžœ˜*Kšœžœ ˜3Kšœ,˜,šžœ˜ Kšœ˜Kšœ˜Kšœ$˜$K˜—Kšœ˜—K˜šŸ œžœ1žœ˜JKšœM˜MKšœ žœ*˜8Kšœ˜šœ C˜EKšœ" ˜>š žœžœ žœžœ ž˜*Kšœ.žœ˜2KšœS˜SKšœ*˜*Kšžœ˜—Kšœ %˜CKšœ˜—Kšœ6žœžœ˜GKšžœžœžœ!˜2Kšžœžœ˜;Kšœ!˜!Kšœ˜—K˜—Kšœ˜—…—!ΰ0½