-- 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.