DIRECTORY CedarInitPrivate USING [ErrorCode], CedarVersion USING [MachineType], Directory USING [CreateSystemDirectory, Error, InsertFile, Lookup], File USING [Capability, MakePermanent, nullCapability, PageCount, Type], FileInternal USING [Descriptor, maxPermissions, PageGroup], FileImpl USING [TmpsEnter, LOCK], Format USING [Date, LongString, StringProc], Heap USING [systemZone], KernelFile USING [Pin], LogicalVolume USING [Handle, PageNumber, VolumeAccess, VolumeAccessProc], LongString USING [AppendString], MicrocodeVersion USING [MachineType, VERSION, VersionResult], Process USING [Pause, Ticks], ProcessOperations USING [Enter, Exit], ProcessorFace USING [SetMP], PupDefs USING [PupPackageMake], System USING [GetUniversalID, gmtEpoch, GreenwichMeanTime, SecondsSinceEpoch], VolAllocMap USING [AccessVAM, AllocPageGroup], VolFileMap USING [InsertPageGroup], Volume USING [ID, PageCount, systemID]; CedarInitBasement: PROGRAM IMPORTS Directory, File, FileImpl, Format, Heap, KernelFile, LogicalVolume, LongString, MicrocodeVersion, Process, ProcessOperations, ProcessorFace, PupDefs, System, VolAllocMap, VolFileMap, Volume EXPORTS CedarInitPrivate, CedarVersion SHARES File, FileImpl = BEGIN -- Exports to CedarVersion -- machineType: PUBLIC CedarVersion.MachineType; uCodeDate: PUBLIC System.GreenwichMeanTime; uCodeVersion: PUBLIC CARDINAL; uCodeFloatingPoint: PUBLIC BOOLEAN; uCodeCedar: PUBLIC BOOLEAN; -- Exports to CedarInitPrivate -- FatalError: PUBLIC PROC [code: CedarInitPrivate.ErrorCode] = { ProcessorFace.SetMP[LOOPHOLE[code]]; DO Process.Pause[LAST[Process.Ticks]] ENDLOOP; }; ValidateMicrocode: PUBLIC PROC RETURNS [error: LONG STRING _ NIL] = { DMachines: TYPE = MicrocodeVersion.MachineType[dolphin..dicentra]; Append: Format.StringProc = { IF error = NIL OR error.length + s.length > error.maxlength THEN { oldSize: CARDINAL = IF error = NIL THEN 0 ELSE error.length; newError: LONG STRING _ Heap.systemZone.NEW[StringBody[3*(oldSize+s.length)/2]]; IF error ~= NIL THEN { LongString.AppendString[newError, error]; Heap.systemZone.FREE[@error]; }; error _ newError; }; LongString.AppendString[error, s]; }; expectedVersion: CARDINAL = 0; vintages: ARRAY DMachines OF System.GreenwichMeanTime = [[23102203300B], -- 12-May-82 1200 GMT [23234170100B], -- 9-Feb-83 1200 GMT System.gmtEpoch, System.gmtEpoch]; v: MicrocodeVersion.VersionResult = MicrocodeVersion.VERSION[]; machineType _ LOOPHOLE[v.machineType]; uCodeVersion _ v.majorVersion; uCodeDate _ [(LONG[v.releaseDate]*24+--noon--12)*60*60]; uCodeFloatingPoint _ v.floatingPoint; uCodeCedar _ v.cedar; SELECT TRUE FROM ~(v.machineType IN DMachines) => Format.LongString["This isn't a D-machine."L, Append]; uCodeVersion ~= expectedVersion => Format.LongString["The microcode and boot file are incompatible."L, Append]; System.SecondsSinceEpoch[vintages[v.machineType]] > System.SecondsSinceEpoch[uCodeDate] => { Format.LongString["The microcode (of "L, Append]; Format.Date[uCodeDate, dateOnly, Append]; Format.LongString[") is too old ("L, Append]; Format.Date[vintages[v.machineType], dateOnly, Append]; Format.LongString[" is the earliest acceptable version)."L, Append]; }; ENDCASE => NULL; }; -- VM backing file logic -- EnsureCedarVMBackingFile: PROC = { vmFileName: STRING = "CedarVM.DontDeleteMe"L; vmFile: File.Capability _ File.nullCapability; filePages: File.PageCount; volID: Volume.ID _ Volume.systemID; CreateVMBackingFile: PROC [filePages: File.PageCount] RETURNS [file: File.Capability] = { backingFileType: File.Type = [500]; fileD: FileInternal.Descriptor; MakeVMBackingFile: LogicalVolume.VolumeAccessProc = { runThreshold: Volume.PageCount = 128; group: FileInternal.PageGroup _ [filePage: 0, volumePage: , nextFilePage: ]; WHILE filePages > 0 DO size: Volume.PageCount; [group.volumePage, size] _ FindDiskHole[volume, filePages]; IF size < runThreshold THEN EXIT; -- terminal fragmentation has set in; give up group.nextFilePage _ group.filePage + size; VolAllocMap.AllocPageGroup[volume, @fileD, @group, group.filePage = 0]; IF group.filePage + size ~= group.nextFilePage THEN FatalError[implementationBug]; VolFileMap.InsertPageGroup[volume, @fileD, @group]; group.filePage _ group.nextFilePage; filePages _ filePages - size; ENDLOOP; RETURN[FALSE] }; file _ [[System.GetUniversalID[]], FileInternal.maxPermissions]; FileImpl.TmpsEnter[@file, @volID]; fileD _ [file.fID, Volume.systemID, local[FALSE, TRUE, 0, backingFileType]]; WHILE ~ProcessOperations.Enter[@FileImpl.LOCK] DO NULL ENDLOOP; IF LogicalVolume.VolumeAccess[@volID, MakeVMBackingFile, TRUE] ~= ok THEN FatalError[implementationBug]; ProcessOperations.Exit[@FileImpl.LOCK]; }; SELECT machineType FROM dorado => filePages _ 6000; dolphin => filePages _ 5000; -- is this plausible? dandelion => filePages _ 5000; -- is this plausible? ENDCASE => FatalError[implementationBug]; vmFile _ Directory.Lookup[vmFileName ! Directory.Error => CONTINUE]; IF vmFile = File.nullCapability AND (vmFile _ CreateVMBackingFile[filePages]) ~= File.nullCapability THEN { Directory.InsertFile[vmFileName, vmFile]; File.MakePermanent[vmFile]; }; IF vmFile ~= File.nullCapability THEN KernelFile.Pin[vmFile]; }; FindDiskHole: PROC [volume: LogicalVolume.Handle, nPages: Volume.PageCount] RETURNS [page: LogicalVolume.PageNumber, size: Volume.PageCount] = { State: TYPE = --LONG-- POINTER TO StateObject; StateObject: TYPE = RECORD [ base: LogicalVolume.PageNumber, largestHoleStart: LogicalVolume.PageNumber, largestHoleSize: Volume.PageCount, maxPages: Volume.PageCount]; PageInUse: PROC [page: LogicalVolume.PageNumber] RETURNS [BOOL] = INLINE {RETURN[VolAllocMap.AccessVAM[volume, page, FALSE, FALSE]]}; FindNextHole: PROC [nPages: File.PageCount, state: State] RETURNS [found: BOOL] = { IF nPages <= state.maxPages THEN { base, exBase: LogicalVolume.PageNumber _ state.base; lastPage: LogicalVolume.PageNumber _ state.maxPages - nPages; UNTIL base > lastPage DO top: LogicalVolume.PageNumber = base + nPages - 1; FOR page: LogicalVolume.PageNumber DECREASING IN [exBase..top] DO IF PageInUse[page] THEN { IF top - page > state.largestHoleSize THEN { state.largestHoleSize _ top - page; state.largestHoleStart _ page + 1}; base _ page + 1; exBase _ top + 1; EXIT }; REPEAT FINISHED => {state.base _ base; RETURN [TRUE]}; ENDLOOP; ENDLOOP; }; RETURN[FALSE] }; state: StateObject _ [0, 0, , volume.volumeSize]; IF FindNextHole[nPages, @state] THEN RETURN[state.base, nPages]; IF state.largestHoleSize = 0 THEN FOR page: LogicalVolume.PageNumber IN [0..state.maxPages) DO IF ~PageInUse[page] THEN {state.base _ page; state.largestHoleSize _ 1; EXIT}; REPEAT FINISHED => RETURN[0, 0]; -- disk is completely full ENDLOOP; WHILE FindNextHole[state.largestHoleSize + 1, @state] DO page: LogicalVolume.PageNumber _ state.base + state.largestHoleSize + 1; WHILE page < state.maxPages AND ~PageInUse[page] DO page _ page + 1; ENDLOOP; state.largestHoleSize _ page - state.base; state.largestHoleStart _ state.base; state.base _ page + 1; ENDLOOP; RETURN [state.largestHoleStart, state.largestHoleSize] }; { ENABLE ANY => FatalError[implementationBug]; ucodeError: LONG STRING _ ValidateMicrocode[]; IF ucodeError ~= NIL THEN { Heap.systemZone.FREE[@ucodeError]; ProcessorFace.SetMP[LOOPHOLE[CedarInitPrivate.ErrorCode[unsuitableMachine]]]; }; Directory.CreateSystemDirectory[Volume.systemID ! Directory.Error => CONTINUE]; EnsureCedarVMBackingFile[]; PupDefs.PupPackageMake[]; }; END. ψCedarInitBasement.mesa last edited by Levin on February 18, 1983 2:34 pm This module must execute before initialization of safe storage occurs. watchers in TerminalMultiplexImpl can still get us to the debugger... The following must be altered when incompatible microcode changes occur: The release date returned by the microcode is relative to the local time zone in effect at the point of release. If we blindly converted it to GMT, subsequent conversions back to local time would cause the date to be decremented by 1, assuming that the microcode was released somewhere in the western hemisphere. To eliminate this, we "define" microcode releases to occur at Greenwich noon, which will force the same apparent release date anywhere in the world. The following limit the compatible versions (warning: can't call DateAndTime yet): This procedure is expected to be invoked from a LogicalVolume.VolumeAccessProc, to ensure appropriate mutual exclusion in access to the volume Handle. It never alters anything, either in the volume Handle or in the VAM. FindDiskHole attempts to find a (contiguous) run of free disk pages of length nPages. It returns the largest run of size less than or equal to nPages that it actually found. (This code was adapted from DiskFindHole.bcpl(!)) Attempts to find a contiguous hole nPages long beginning at a page greater than or equal to state.base. If successful, returns TRUE and updates state.base to point to the start of the hole. If unsuccessful, returns FALSE, leaves state.base unchanges, and sets state.largestHoleStart and state.largestHoleSize to indicate the largest hole actually encountered during the scan (which, however, may not be the largest hole present in the region scanned). Invariants: exBase >= base [base..exBase) have been searched exhaustively and are known to be free Try now for a new hole starting at page+1. (page..top] are known to be free. forge ahead and hope for the best Edited on December 15, 1982 5:39 pm, by Levin Set style to "Cedar" changes to: , END. Κ“– "Cedar" style˜Jšœ™Jšœ1™1J˜šΟk ˜ Jšœœ ˜#Jšœ œ˜!Jšœ œ4˜CJšœœ>˜HJšœ œ)˜;Jšœ œ œ˜!Jšœœ ˜,Jšœœ˜Jšœ œ˜Jšœœ6˜IJšœ œ˜ Jšœœœ˜=Jšœœ˜Jšœœ˜&Jšœœ ˜Jšœœ˜JšœœB˜NJšœ œ˜.Jšœ œ˜#Jšœœœ˜'J˜J˜—šœ˜š˜J˜CJ˜HJ˜0—Jšœ˜&Jšœ˜J˜—Jš˜J˜JšœF™FJ˜J˜JšΟc˜J˜J˜Jšœ œ˜-J˜Jšœ œ˜+Jšœœœ˜J˜Jšœœœ˜#Jšœ œœ˜J˜J˜Jšž!˜!J˜šΟn œœœ'˜>Jšœœ˜$Jšœœœ˜.JšœE™EJ˜J˜J˜—šŸœœœœ œœœ˜EJšœ œ3˜B˜šœ œœ+œ˜BJš œ œœ œœœ˜