<> <> 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 <> <= base>> <<[base..exBase) have been searched exhaustively and are known to be free>> 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. <> <> <> <<>> <<>>