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 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; 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. êCedar Nucleus (Files): per-file operations, locking file header data structures BootingImpl.mesa Andrew Birrell September 20, 1983 3:35 pm ******** Exports to Booting interface ******** 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 Ê ý˜JšœP™PJšœ™Jšœ*™*šÏk ˜ Jšœ œ#˜1JšœœR˜_Jšœœ ˜Jšœœœy˜œJšœ œ=˜OJšœ œ*˜8Jšœœ-˜CJšœœ ˜Jšœœ6˜JJšœœ˜)Jšœ œ˜Jšœœa˜tJšœœ œ˜Jšœœ˜Jšœ œ˜%Jšœ œ ˜Jšœ œ˜(Jšœ œ˜%—J˜šœ œ˜Jšœ¡˜¨Jšœœ˜—J˜š˜J˜—J˜Jšœ.™.˜Jšœ œ&˜6J˜š Ïc Ïnœœœœ˜qJšœœ0˜8—J˜šž Ÿœœœ˜Jšœ˜Jšœ˜Jšœ$˜$Jšœœœ˜-Jš˜Jšœ'˜'šŸ œœœ˜QJš˜šœ œ˜Jšœœ˜ šœ˜Jšœ8˜8—šœ ˜ Jš˜Jš œœ œœœ ˜:Jšœœœœ˜.Jšœ1˜1Jšœ-˜/Jšœœ˜#Jšœ˜—šœ ˜ Jš˜šœœœ˜AJšœ@˜DJšœ ˜—šœ:œ˜BJšœœ˜,—šœœ'˜,šœ˜ Jšœ2˜2Jšœ-˜/Jšœœ˜#Jš˜Jšœ˜——Jšœœœ˜0Jšœ˜Jšœ˜—Jšœ œ˜Jšœœ˜šœ˜Jšœ#˜#——Jšœ˜Jšœ˜—Jšœœ˜*Jšœ)˜)Jš œœœœœ-˜SJšœœ'˜BJšœœ#˜8Jšœ˜šœ˜Jš œ œœ œœ˜7šœœ œ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜ —Jšœ˜—Jšœ˜—J˜Jšœœœœ˜"J˜šŸœœœ˜Jšœ œœœ˜/šœœœ˜Jšœœ˜ Jšœœœ˜4Jšœœ˜Jšœ+˜+Jšœ˜ —Jšœ˜Jšœœœœ˜/Jš˜Jšœœœ˜Jšœ7˜7Jšœ œœ˜Jšœ˜Jš œ&œ œœœ˜KJšœœ˜Jšœ#ž˜>Jšœ˜Jšœ˜šœ˜ Jšœœœž˜TJšœ˜Jšœ˜Jšœ˜Jšœ™Jšœ=˜=JšœC™CJšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœœ ˜šœ˜ šœ œ˜Jšœœ˜ Jšœ'ž œ˜5Jšœ9žœ˜Išœ ˜ Jš˜Jšœž1˜PJ˜"Jšœœœ˜4Jšœ˜——Jšœœ˜Jšœ™Jšœ˜—Jšœ ˜šœ˜ JšœS™SJšœ œœ˜+Jšœœ˜Jšœœœ˜0Jšœ˜—Jšœ˜J˜%Jšœ!˜!Jšœ˜Jšœ˜Jšœ˜—J˜J˜J˜—Jšœ'™'™šœ œœ˜J˜J˜Jšœ œœ˜Jšœœ œ˜Jšœœ œ˜—J˜Jšœ œ œž#˜DJšœ œ œž˜8J˜šŸ œœœœœœœœœ˜}Jš˜Jšœœœ˜Jšœœ œ2˜IJšœ8™8Jšœ œœ˜(Jšœœœ˜2Jšœ+˜+Jšœ˜—J˜š Ÿ œœœœœœ˜_Jš˜Jšœœœ˜Jšœœ œ˜Jšœœ$œ˜Ašœœ œ ˜šœ˜ Jšœœœœ˜UJšœœœœ˜SJš˜Jšœ˜—J˜ —Jšœ˜Jšœ˜—J˜š Ÿœœœœœœ˜PJš˜Jšœœ$œ˜Ašœœ ˜šœ˜ Jšœ&˜&Jšœ˜Jšœ ˜šœœž$˜/Jšœœ#œ˜@Jšœœ œœ œœœ˜KJš˜Jšœ˜—Jšœ˜——Jšœ˜Jšœ˜—J˜šŸœœœ˜*Jš˜Jšœœ"œ˜?Jš œœ œœœ˜:Jšœ˜—J˜š Ÿ œœœœœœ˜=Jš˜Jšœœœ˜*Jšœœž˜3Jšœ,˜,šœ˜ Jšœ˜Jšœ˜Jšœ$˜$J˜—Jšœ˜—J˜šŸ œœ0˜GJš˜JšœM˜MJšœ œ"˜0Jšœ˜šœžC˜IJšœ"ž˜>Jšœœ œœ ˜'šœ/œ˜5JšœS˜SJšœ*˜*—Jšœ˜Jšœž%˜8—Jšœ˜Jšœ6œœ˜GJšœœœ!˜2Jšœœ˜;Jšœ˜Jšœ˜—J˜—Jšœ˜—…—¦,