Cedar Nucleus (Files): initialisation
FileInit.mesa
Andrew Birrell July 8, 1983 3:01 pm
Last Edited by: Levin, June 28, 1983 4:49 pm
DIRECTORY
BootFile USING[ Location ],
BootStartList USING [EntryPointer, Enumerate, IndexToEntryPointer, IndexToSpaceEntryPointer, Proc, SpaceEntryPointer],
DebuggerSwap USING[ CallDebugger, NoteDiskDebugger ],
Disk USING[ Channel, DriveAttributes, GetPageNumber, PageNumber ],
DiskFace USING[ Type ],
File USING[ Error, FP, GetRoot, Handle, NextVolume, Open, PageCount, PageNumber, Read, Volume ],
FileInternal USING[ RegisterVMFile, VolumeObject ],
GermSwap USING[ bootedFrom, switches ],
MPCodes USING[ fileInitialized ],
PhysicalVolume USING[ SubVolumeDetails ],
Process USING [Detach],
ProcessorFace USING[ SetMP ],
VM USING [Interval, MakeReadOnly, PageNumberToAddress],
VolumeFormat USING[ nullDiskFileID, RelID ];
FileInit: CEDAR MONITOR
IMPORTS BootStartList, DebuggerSwap, Disk, File, FileInternal, GermSwap, Process, ProcessorFace, VM
EXPORTS DiskFace--RelID--, File =
BEGIN
Operations on the system volume: finding it, finding debugger, finding VM backing file
Volume: TYPE = REF VolumeObject;
VolumeObject: PUBLIC TYPE = FileInternal.VolumeObject;
FindVolumeFromLocation: PROC[loc: BootFile.Location] RETURNS[File.Volume] =
BEGIN
channel: Disk.Channel ← NIL;
FOR v: Volume ← File.NextVolume[NIL,FALSE], File.NextVolume[v,FALSE] UNTIL v = NIL
DO FOR sv: LIST OF PhysicalVolume.SubVolumeDetails ← v.subVolumes, sv.rest
UNTIL sv = NIL
DO type: DiskFace.Type;
ordinal: CARDINAL;
[type: type, ordinal: ordinal] ← Disk.DriveAttributes[sv.first.channel];
IF type = loc.deviceType AND ordinal = loc.deviceOrdinal
THEN BEGIN
page: Disk.PageNumber = Disk.GetPageNumber[sv.first.channel, loc.diskFileID.firstLink];
IF page >= sv.first.address AND page < (sv.first.address + sv.first.size)
THEN RETURN[v];
END;
ENDLOOP;
ENDLOOP;
RETURN[NIL]
END;
FindSystemVolume: PROC RETURNS[File.Volume] =
BEGIN
IF GermSwap.switches[n] THEN RETURN[NIL];
RETURN[ FindVolumeFromLocation[GermSwap.bootedFrom.location] ]
END;
--File.--SystemVolume: PUBLIC PROC RETURNS[volume: Volume] =
{ RETURN[systemVolume] };
FindDebugger: PROC = TRUSTED
BEGIN
IF GermSwap.switches[n] OR systemVolume = NIL THEN RETURN;
FOR v: Volume ← File.NextVolume[NIL], File.NextVolume[v] UNTIL v = NIL
DO IF (v.rootStatus = ok OR v.rootStatus = nonCedarVolume)
AND v.root.bootingInfo[debuggee] # VolumeFormat.nullDiskFileID
AND systemVolume # NIL
AND ( SELECT systemVolume.root.type FROM
pilot => v.root.type = pilotDebugger,
pilotDebugger => v.root.type = pilotDebuggerDebugger,
pilotDebuggerDebugger => FALSE,
cedar => IF v.root.type = cedar
THEN ( NOT systemVolume.root.coCedar AND v.root.coCedar)
ELSE v.root.type = pilotDebugger -- change to FALSE after bootstrap to 5.0--,
ENDCASE => FALSE)
THEN BEGIN
type: DiskFace.Type;
ordinal: CARDINAL;
[type: type, ordinal: ordinal] ← Disk.DriveAttributes[v.subVolumes.first.channel];
DebuggerSwap.NoteDiskDebugger[
debugger: [type, ordinal, disk[v.root.bootingInfo[debugger]]],
debuggee: [type, ordinal, disk[v.root.bootingInfo[debuggee]]]
];
EXIT
END;
ENDLOOP;
END;
CheckVMFP: PROC[volume: Volume] RETURNS[BOOL] =
BEGIN
fp: File.FP = File.GetRoot[volume, VM ! File.Error => GOTO noGo ].fp;
file: File.Handle = File.Open[volume, fp ! File.Error => GOTO noGo ];
FileInternal.RegisterVMFile[file];
RETURN[TRUE];
EXITS noGo => RETURN[FALSE]
END;
FindVM: PROC = TRUSTED
BEGIN
IF GermSwap.switches[n] OR systemVolume = NIL THEN RETURN;
IF CheckVMFP[systemVolume] THEN RETURN;
FOR v: Volume ← File.NextVolume[NIL], File.NextVolume[v] UNTIL v = NIL
DO weAreCoCedar: BOOL = systemVolume.rootStatus = ok AND systemVolume.root.coCedar;
itsCoCedar: BOOL = v.rootStatus = ok AND v.root.coCedar;
IF itsCoCedar = weAreCoCedar AND CheckVMFP[v] THEN RETURN;
ENDLOOP;
END;
Copying in the non-initial-loaded part of the boot file
--DiskFace.--RelID: PUBLIC TYPE = VolumeFormat.RelID;
CopyBootFile: PROC = TRUSTED
BEGIN
maxProcesses: NAT = 2;
processesInUse: NAT ← 0;
processAvailable: CONDITION ← [timeout: 0];
bootFileVolume: File.Volume;
bootFileFP: RelID;
bootFileHandle: File.Handle;
ForkedRead: UNSAFE PROC [from: File.PageNumber, nPages: File.PageCount, to: LONG POINTER] = UNCHECKED {
File.Read[file: bootFileHandle, from: from, nPages: nPages, to: to];
NotifyProcessAvailable[];
};
WaitForAProcess: ENTRY PROC = CHECKED {
WHILE processesInUse = maxProcesses DO WAIT processAvailable ENDLOOP;
processesInUse ← processesInUse + 1;
};
NotifyProcessAvailable: ENTRY PROC = CHECKED {
processesInUse ← processesInUse - 1;
NOTIFY processAvailable;
};
WaitUntilDone: ENTRY PROC = CHECKED {
UNTIL processesInUse = 0 DO WAIT processAvailable ENDLOOP;
};
SwapIn: BootStartList.Proc = UNCHECKED {
OPEN BootStartList;
entry: EntryPointer = IndexToEntryPointer[index];
WITH e: entry SELECT FROM
space =>
IF ~e.bootLoaded THEN {
WaitForAProcess[];
Process.Detach[FORK ForkedRead[
from: [e.backingPage],
nPages: e.pages,
to: VM.PageNumberToAddress[e.vmPage]
]];
};
swapUnit => NULL;
ENDCASE => ERROR;
};
MakeReadOnly: BootStartList.Proc = UNCHECKED {
OPEN BootStartList;
entry: EntryPointer = IndexToEntryPointer[index];
WITH e: entry SELECT FROM
swapUnit => {
parent: SpaceEntryPointer = IndexToSpaceEntryPointer[e.parent];
IF ~parent.bootLoaded AND e.info.readOnly THEN
VM.MakeReadOnly[VM.Interval[parent.vmPage+e.base, e.pages]];
};
space => NULL;
ENDCASE => ERROR;
};
IF GermSwap.switches[n] THEN RETURN;
"bootFileVolume" is logically independent of "SystemVolume[]"
bootFileVolume ← FindVolumeFromLocation[GermSwap.bootedFrom.location];
IF bootFileVolume = NIL THEN RETURN;
bootFileFP ← GermSwap.bootedFrom.location.diskFileID.fID.relID;
bootFileHandle ← File.Open[systemVolume, bootFileFP ! File.Error => GOTO noGo];
BootStartList.Enumerate[SwapIn];
BootStartList.Enumerate[MakeReadOnly];
WaitUntilDone[];
EXITS noGo => NULL
END;
Main body
systemVolume: Volume ← FindSystemVolume[];
FindDebugger[];
FindVM[];
CopyBootFile[];
TRUSTED {IF GermSwap.switches[three] THEN DebuggerSwap.CallDebugger["Key stop 3"L]};
TRUSTED {ProcessorFace.SetMP[MPCodes.fileInitialized]};
END.