-- OthelloOpsImpl.mesa (last edited by: Forrest on: July 29, 1980 9:21 AM)

DIRECTORY
Boot USING [
BootFileType, Location, LVBootFiles, nullDiskFileID, PVBootFiles],
BootFile USING [
currentVersion, Entry, Header, maxEntriesPerHeader,
maxEntriesPerTrailer, MDSIndex, Trailer],
Device USING [Type],
DiskChannel USING [GetDriveAttributes, PVHandle],
Environment,
File,
Inline USING [LongDivMod, LongNumber, LowHalf],
KernelFile,
OthelloOps,
PhysicalVolume,
Space USING [
Create, Delete, Handle, LongPointer, Map, Unmap, virtualMemory],
SpecialFile,
SpecialVolume,
StartList USING [BootLocation, Header, VersionID],
TemporaryBooting USING [
defaultSwitches, MakeBootable, MakeUnbootable, Switch, Switches,
UpDown],
Utilities USING [Bit, BitIndex, BitPut],
Volume;

OthelloOpsImpl: PROGRAM
IMPORTS
DiskChannel, File, Inline, KernelFile, PhysicalVolume, Space,
SpecialFile, SpecialVolume, TemporaryBooting, Utilities, Volume
EXPORTS OthelloOps, PhysicalVolume
SHARES File=
PUBLIC BEGIN OPEN OthelloOps;

maxFilePermissions: File.Permissions = File.read+File.write+File.grow+File.shrink+File.delete;

ImpossibleBootFileType: ERROR = CODE;
ConvertBootFileType: PROC [
x: BootFileType] RETURNS [Boot.BootFileType] =
BEGIN
SELECT x FROM
hardMicrocode => RETURN[hardMicrocode];
softMicrocode => RETURN[softMicrocode];
germ => RETURN[germ];
pilot => RETURN[pilot];
ENDCASE => ERROR ImpossibleBootFileType;
END;

BadSwitch: SIGNAL [c: CHARACTER] = CODE;
DecodeSwitches: PROC [switchString: STRING]
RETURNS [switches: TemporaryBooting.Switches] =
BEGIN
c: CHARACTER;
aOffset: Utilities.BitIndex = LOOPHOLE[TemporaryBooting.Switch[a]];
zeroOffset: Utilities.BitIndex =
LOOPHOLE[TemporaryBooting.Switch[zero]];
SetSwitch: PROC [switch: Utilities.BitIndex] =
BEGIN
down: Utilities.Bit = LOOPHOLE[TemporaryBooting.UpDown[down]];
Utilities.BitPut[down, @switches, switch];
END;
switches ← TemporaryBooting.defaultSwitches;
FOR i: CARDINAL IN [0..switchString.length) DO
SELECT (c ← switchString[i]) FROM
IN [’0..’9] => SetSwitch[(c-’0)+zeroOffset];
IN [’a..’z] => SetSwitch[(c-’a)+aOffset];
IN [’A..’Z] => SetSwitch[(c-’A)+aOffset];
ENDCASE => SIGNAL BadSwitch[c];
ENDLOOP;
END;

-- do an old style delete temps. Volume should be Open
VolumeNotClosed: ERROR = CODE;
DeleteTempFiles: PROC [lvID: Volume.ID] =
BEGIN
DeleteTempsInner: PROC =
BEGIN
lastCap: File.Capability ← File.nullCapability;
DO
temp, immutable: BOOLEAN;
thisCap: File.Capability = KernelFile.GetNextFile[lvID, lastCap];
IF thisCap = File.nullCapability THEN EXIT;
[immutable: immutable, temporary: temp] ← File.GetAttributes[thisCap];
IF ~temp THEN lastCap ← thisCap
ELSE IF immutable THEN File.DeleteImmutable[thisCap, lvID]
ELSE File.Delete[thisCap];
ENDLOOP;
END;
IF Volume.GetStatus[lvID]=open THEN ERROR VolumeNotClosed;
Volume.Open[lvID];
DeleteTempsInner[! UNWIND => Volume.Close[lvID]];
Volume.Close[lvID];
END;

Handle: PUBLIC TYPE = DiskChannel.PVHandle;
GetDriveSize: PROC [
h: Handle] RETURNS [nPages: LONG CARDINAL] =
{RETURN[DiskChannel.GetDriveAttributes[h.drive].nPages]};

MakeBootable: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeBootable[file, firstPage];
ENDCASE =>
BEGIN
lvID: Volume.ID = File.GetAttributes[file].volume;
l: SpecialFile.Link = SpecialFile.MakeBootable[
file: file, firstPage: firstPage, count: File.GetSize[file]-firstPage,
lastLink: SpecialFile.eofLink];
END;
END;

MakeUnbootable: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeUnbootable[file, firstPage];
ENDCASE => SpecialFile.MakeUnbootable[
file: file, firstPage: firstPage, count: File.GetSize[file]-firstPage];
END;

SetVolumeBootFile: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
lvID: Volume.ID = File.GetAttributes[file].volume;
l: SpecialFile.Link = KernelFile.GetBootLocation[file, firstPage].link;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
bootFiles[ConvertBootFileType[type]] ← [file.fID, firstPage, LOOPHOLE[l]];
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @bootFiles];
END;

SetPhysicalVolumeBootFile: PROC[
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
pvID: PhysicalVolume.ID =
PhysicalVolume.GetContainingPhysicalVolume[
File.GetAttributes[file].volume];
l: SpecialFile.Link = KernelFile.GetBootLocation[file, firstPage].link;
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]]
← [file.fID, firstPage, LOOPHOLE[l]];
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;

GetVolumeBootFile: PROC [lvID: Volume.ID, type: BootFileType]
RETURNS [cap: File.Capability, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
cType: Boot.BootFileType = ConvertBootFileType[type];
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
IF bootFiles[cType].fID = File.nullID THEN
RETURN[File.nullCapability, 0]
ELSE RETURN[
[bootFiles[cType].fID, maxFilePermissions], bootFiles[cType].firstPage];
END;

GetPhysicalVolumeBootFile: PROC
[pvID: PhysicalVolume.ID, type: BootFileType]
RETURNS [cap: File.Capability, firstPage: File.PageNumber] =
BEGIN
cType: Boot.BootFileType = ConvertBootFileType[type];
bootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @bootFiles];
IF bootFiles[cType].fID = File.nullID THEN RETURN[File.nullCapability, 0]
ELSE RETURN[
[bootFiles[cType].fID, maxFilePermissions], bootFiles[cType].firstPage];
END;

VoidVolumeBootFile: PROC [lvID: Volume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.LVBootFiles;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]] ← Boot.nullDiskFileID;
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @pBootFiles];
END;

VoidPhysicalVolumeBootFile: PROC
[pvID: PhysicalVolume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]] ← Boot.nullDiskFileID;
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;

-- Set Debug implemenation
BootHeadPtr: PRIVATE TYPE = LONG POINTER TO BootFile.Header;
StartListHeadPtr: PRIVATE TYPE = LONG POINTER TO StartList.Header;

SetDebugger: PROC [
debuggeeCap: File.Capability, debuggeeFirstPage: File.PageNumber,
debugger: Volume.ID, debuggerType: Device.Type,
debuggerOrdinal: CARDINAL]
RETURNS [setDebuggerSuccess] =
BEGIN
bootSpace: Space.Handle;
debuggerBootFiles: Boot.LVBootFiles;
memPage: Environment.PageNumber;
offset: CARDINAL;
pBootHeader: BootHeadPtr;
pStartListHeader: StartListHeadPtr;

IF debuggeeCap=File.nullCapability THEN RETURN[nullBootFile];
SpecialVolume.GetLogicalVolumeBootFiles[
debugger, @debuggerBootFiles];
IF debuggerBootFiles[pilot].fID=File.nullID OR
debuggerBootFiles[debugger].fID=File.nullID OR
debuggerBootFiles[debuggee].fID=File.nullID THEN
RETURN[noDebugger];
bootSpace ← Space.Create[1, Space.virtualMemory];
BEGIN ENABLE UNWIND => Space.Delete[bootSpace];
Space.Map[bootSpace, [debuggeeCap, debuggeeFirstPage]];
pBootHeader ← LOOPHOLE[Space.LongPointer[bootSpace]];
IF pBootHeader.version#BootFile.currentVersion THEN
{ Space.Delete[bootSpace]; RETURN[startListHeaderHasBadVersion]; };
IF pBootHeader.continuation.kind#initial THEN
{ Space.Delete[bootSpace]; RETURN[notInitialBootFile]; };
[memPage, offset] ← PointerMunge[
pBootHeader.pStartListHeader,
WITH pBootHeader.continuation SELECT FROM
initial=>mdsi, ENDCASE=>[0]];
pStartListHeader ← FindStartListHeader[
bootSpace, debuggeeCap, pBootHeader, debuggeeFirstPage,
memPage, offset];
IF pStartListHeader=NIL THEN
{ Space.Delete[bootSpace]; RETURN[cantFindStartListHeader]; };
IF pStartListHeader.version#StartList.VersionID THEN
{ Space.Delete[bootSpace]; RETURN[startListHeaderHasBadVersion]; };
pStartListHeader.locDebuggerMicrocode ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[softMicrocode]]]];
pStartListHeader.locDebuggerGerm ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[germ]]]];
pStartListHeader.locDebugger ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[debugger]]]];
pStartListHeader.locDebuggee ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[debuggee]]]];
END;
Space.Delete[bootSpace];
RETURN[success];
END;

FindStartListHeader: PRIVATE PROC
[sp: Space.Handle, file: File.Capability,
pHeader: LONG POINTER TO BootFile.Header,
firstPage: File.PageNumber, page: Environment.PageNumber,
offset: CARDINAL]
RETURNS [p: StartListHeadPtr] =
BEGIN
pTrailer: LONG POINTER TO BootFile.Trailer;
pagesRemaining: File.PageCount ← pHeader.countData;
curBase: File.PageNumber ← firstPage+1; -- start at first data page
nEntries: CARDINAL ← Inline.LowHalf[
MIN[pagesRemaining, BootFile.maxEntriesPerHeader]];
entries: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry ←
@pHeader.entries;
i: CARDINAL ;
DO
FOR i IN [0..nEntries) DO
IF entries[i].page=page THEN GOTO Found;
ENDLOOP;
curBase ← curBase+nEntries;
pagesRemaining ← pagesRemaining-nEntries;
IF pagesRemaining=0 THEN RETURN[NIL];
Space.Unmap[sp]; Space.Map[sp, [file, curBase]];
curBase ← curBase+1;
pTrailer ← LOOPHOLE[Space.LongPointer[sp]];
nEntries ← Inline.LowHalf[
MIN[pagesRemaining, BootFile.maxEntriesPerTrailer]];
entries ← @pTrailer.entries;
REPEAT Found => NULL;
ENDLOOP;
curBase ← curBase+i;
Space.Unmap[sp]; Space.Map[sp, [file, curBase]];
RETURN[LOOPHOLE[Space.LongPointer[sp]+offset]];
END;

PointerMunge: PRIVATE PROC [p: POINTER, n: BootFile.MDSIndex]
RETURNS [page: Environment.PageNumber, offset: CARDINAL] =
BEGIN
ln: Inline.LongNumber = [num[lowbits: LOOPHOLE[p], highbits: n]];
[page, offset] ← Inline.LongDivMod[ln.lc, Environment.wordsPerPage];
END;

SubVolumeUnknown: ERROR [sv: SubVolume] = CODE;

GetNextSubVolume: PROC [pvID: PhysicalVolume.ID, thisSv: SubVolume]
RETURNS [SubVolume] =
BEGIN
sv: SpecialVolume.SubVolume = SpecialVolume.GetNextSubVolume[
pvID,
IF thisSv=nullSubVolume THEN SpecialVolume.nullSubVolume
ELSE
[lvID: thisSv.lvID, firstLVPageNumber: thisSv.firstLVPageNumber,
firstPVPageNumber: thisSv.firstPVPageNumber,
subVolumeSize: thisSv.subVolumeSize]
! SpecialVolume.SubVolumeUnknown => GOTO error];
RETURN[
IF sv=SpecialVolume.nullSubVolume THEN nullSubVolume
ELSE
[lvID: sv.lvID, subVolumeSize: sv.subVolumeSize,
firstLVPageNumber: sv.firstLVPageNumber,
firstPVPageNumber: sv.firstPVPageNumber]];
EXITS
error => ERROR SubVolumeUnknown[thisSv];
END;


END.
LOG
Time: May 31, 1980 9:54 PM By: Forrest Action: Re-created file from combines of old VolumeImplA & B.
Time: July 13, 1980 8:10 PM By: Forrest Action: Another run at the old fence.