<> <> <> DIRECTORY BootFile USING[ Location, MemorySizeToFileSize ], Booting USING[ Bootee, BootFileNumber, CheckpointProc, MicrocodeType, RollbackProc, Switches ], DeviceCleanup USING[ Perform ], File USING[ Create, Error, Info, FP, GetRoot, Handle, Open, nullFP, nullVolumeID, PageCount, SetRoot, SetSize, SystemVolume, Volume, VolumeFile, VolumeID ], 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[ PsbHandle ], 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, FileInternal, GermSwap, MicrocodeBooting, PhysicalVolume, ProcessorFace, PrincOpsUtils, Rope, VMBacking, VMSideDoor, VMStatistics EXPORTS Booting = BEGIN <<******** Exports to Booting interface ********>> switches: PUBLIC Booting.Switches _ GermSwap.switches; --Booting.--GetBootFileNumber: PUBLIC PROC[type: Booting.MicrocodeType] RETURNS[Booting.BootFileNumber] = TRUSTED { RETURN[ MicrocodeBooting.GetBootFileNumber[type] ] }; --Booting.--Boot: PUBLIC PROC[ boot: Booting.Bootee, switches: Booting.Switches, outload: Booting.Bootee _ [noOp[]] ] RETURNS[rejection: Rope.ROPE _ NIL] = TRUSTED BEGIN sys: File.Volume = File.SystemVolume[]; GetLocation: PROC[from: Booting.Bootee] RETURNS[loc: BootFile.Location] = TRUSTED BEGIN WITH b: from SELECT FROM noOp => NULL; file => loc _ FileInternal.GetFileLocation[b.file, b.firstPage]; logical => BEGIN 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]; END; physical => BEGIN 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 BEGIN loc _ FileInternal.GetPhysicalLocation[p, b.root]; IF loc.diskFileID = VolumeFormat.nullDiskFileID THEN ERROR File.Error[unknownFile]; EXIT END; REPEAT FINISHED => ERROR File.Error[unknownFile] ENDLOOP; END; microcode => NULL; bootButton => NULL; self => loc _ GermSwap.bootedFrom.location; ENDCASE; END; outloadWanted: BOOL _ outload.type # noOp; outloadLoc, inloadLoc: BootFile.Location; IF NOT outloadWanted AND sys # NIL AND File.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]; END; inloadedOnce: PUBLIC BOOL _ FALSE; BootFromLocation: ENTRY PROC[ outloadLoc: POINTER TO BootFile.Location _ NIL, boot: RECORD[SELECT t: * FROM noOp => NULL, inload => [inloadLoc: POINTER TO BootFile.Location], bootButton => NULL, microcode => [bfn: Booting.BootFileNumber], ENDCASE], switches: Booting.Switches ] RETURNS[rejection: Rope.ROPE _ NIL] = TRUSTED BEGIN 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 BEGIN 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]; END; IF NOT inloaded THEN BEGIN WITH b: boot SELECT FROM noOp => NULL; bootButton => ProcessorFace.BootButton[--switches--]; microcode => MicrocodeBooting.BootSpecificMicrocode[b.bfn--, switches--]; inload => BEGIN VMBacking.RecoverRealMemory[]; -- so that the germ can find it for the next guy. DeviceCleanup.Perform[disconnect]; GermSwap.InLoad[NIL, NIL, 0, b.inloadLoc, switches]; END; ENDCASE => ERROR; <> END; IF inloadedOnce THEN BEGIN <> newSwitches: Booting.Switches _ ALL[FALSE]; newSwitches[w] _ TRUE; GermSwap.InLoad[NIL, NIL, 0,@self, newSwitches]; END; DeviceCleanup.Perform[turnOn]; ProcessorFace.SetMP[MPCodes.emptyMP]; PrincOpsUtils.EnableInterrupts[]; IF outloadLoc # NIL THEN CallRollbackProcs[]; END; <<******** Checkpoint facilities ********>> <<>> ProcsRec: TYPE = RECORD[ c: Booting.CheckpointProc, r: Booting.RollbackProc, 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, clientData: REF ANY _ NIL] = BEGIN ENABLE UNWIND => NULL; new: REF ProcsRec = NEW[ProcsRec _ [c: c, r: r, clientData: clientData]]; <> IF rollbacks = NIL THEN rollbacks _ new; IF checkpoints # NIL THEN checkpoints.nextR _ new; new.nextC _ checkpoints; checkpoints _ new; END; Deregister: PUBLIC ENTRY PROC[c: Booting.CheckpointProc _ NIL, r: Booting.RollbackProc _ NIL] = BEGIN 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 THEN BEGIN 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 END; prev _ this; ENDLOOP; END; CallCheckpointProcs: INTERNAL PROC RETURNS[rejection: Rope.ROPE _ NIL] = TRUSTED BEGIN FOR this: REF ProcsRec _ checkpoints, this.nextC UNTIL this = NIL DO IF this.c # NIL THEN BEGIN rejection _ (this.c)[this.clientData]; IF rejection.Length[] = 0 THEN rejection _ NIL ELSE BEGIN -- 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 END; END; ENDLOOP; END; CallRollbackProcs: INTERNAL PROC = TRUSTED BEGIN FOR this: REF ProcsRec _ rollbacks, this.nextR UNTIL this = NIL DO IF this.r # NIL THEN (this.r)[this.clientData] ENDLOOP; END; Checkpoint: PUBLIC PROC RETURNS[rejection: Rope.ROPE _ NIL] = BEGIN 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]] ]] END; VerifyFile: PROC[volume: File.Volume, which: File.VolumeFile] = TRUSTED BEGIN size: File.PageCount _ BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+256; oldFP: File.FP = File.GetRoot[volume, which].fp; new: File.Handle; BEGIN -- 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 + 256; -- guess for checkpoint file overhead END; 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]; File.SetRoot[which, new]; END; END.