-- File: Script.Mesa
-- Last edited by Sandman; July 10, 1980  8:01 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [PageSize],
  BootmesaOps,
  CommanderDefs USING [AddCommand],
  ControlDefs USING [GlobalFrameHandle],
  InlineDefs USING [COPY],
  MiscDefs USING [Zero],
  SegmentDefs USING [
    AddressFromPage, DeleteFileSegment, FileSegmentAddress, FileSegmentHandle,
    NewFileSegment, Read, SwapIn, Unlock, Write],
  SegOps USING [DefaultFile, EnumerateSegs, ffvmp, lfvmp, NewSeg, Seg],
  StreamDefs USING [CleanupDiskStream, GetIndex, WriteBlock],
  Storage USING [Pages, FreePages, PagesForWords],
  WartDefs USING [
    Header, LinkEntry, LinkHandle, LinkIndex, SegEntry, SegHandle, SegIndex,
    TableBase, VersionID];

Script: PROGRAM
  IMPORTS
    BootmesaOps, MiscDefs, InlineDefs, StreamDefs, SegmentDefs, SegOps, Storage,
    CommanderDefs
  EXPORTS BootmesaOps
  SHARES ControlDefs =
  BEGIN OPEN WartDefs;
  
  data: POINTER TO BootmesaOps.BootData ← @BootmesaOps.dataObject;
  
  -- Wart Script Management
  
  tableFileSegment: SegmentDefs.FileSegmentHandle ← NIL;
  segIndex: SegIndex;
  linkIndex: LinkIndex;
  segPages, linkPages: CARDINAL;
  segTable, linkTable, vmTable: PUBLIC TableBase;
  enableHyperspace: BOOLEAN ← TRUE;
  
  DisableHyperspace: PUBLIC PROCEDURE = BEGIN enableHyperspace ← FALSE END;
    
  InitializeBootScript: PUBLIC PROCEDURE =
    BEGIN
    segTable ← Storage.Pages[segPages ← 1];
    segIndex ← LOOPHOLE[SIZE[Header]];
    linkTable ← Storage.Pages[linkPages ← 1];
    linkIndex ← FIRST[LinkIndex];
    MiscDefs.Zero[@header, SIZE[Header]];
    data.header ← @header;
    header.version ← VersionID;
    header.useHyperSpace ← enableHyperspace;
    RETURN
    END;
    
  header: Header;
  
  FinishBootScript: PUBLIC PROCEDURE [startframe: ControlDefs.GlobalFrameHandle]
    RETURNS [headerloc: POINTER] =
    BEGIN
    header.tablebase ← vmTable;
    header.user ← BootmesaOps.UserControl[];
    header.nub ← BootmesaOps.NubFrame[];
    header.ffvmp ← SegOps.ffvmp;
    header.lfvmp ← SegOps.lfvmp;
    segTable↑ ← header;
    SegmentDefs.Unlock[tableFileSegment];
    SegmentDefs.DeleteFileSegment[tableFileSegment];
    RETURN[vmTable]
    END;
    
  BootTableOverflow: ERROR = CODE;
  ExpandingAllowed: BOOLEAN ← TRUE;
  
  ExpandSegTable: PROCEDURE =
    BEGIN
    newbase: POINTER;
    IF ~ExpandingAllowed THEN BootmesaOps.BootmesaError["SegTableOverflow"L];
    newbase ← Storage.Pages[segPages + 1];
    InlineDefs.COPY[
      from: segTable, to: newbase, nwords: segPages*AltoDefs.PageSize];
    segPages ← segPages + 1;
    Storage.FreePages[segTable];
    segTable ← newbase;
    RETURN
    END;
    
  AppendSegEntry: PUBLIC PROCEDURE [seg: SegHandle] RETURNS [index: SegIndex] =
    BEGIN
    WHILE LOOPHOLE[segIndex, CARDINAL] + SIZE[SegEntry] >
      segPages*AltoDefs.PageSize DO ExpandSegTable[]; ENDLOOP;
    index ← segIndex;
    InlineDefs.COPY[from: seg, to: @segTable[index], nwords: SIZE[SegEntry]];
    segIndex ← segIndex + SIZE[SegEntry];
    RETURN
    END;
    
  ExpandLinkTable: PROCEDURE =
    BEGIN
    newbase: POINTER;
    IF ~ExpandingAllowed THEN BootmesaOps.BootmesaError["LinkTableOverflow"L];
    newbase ← Storage.Pages[linkPages + 1];
    InlineDefs.COPY[
      from: linkTable, to: newbase, nwords: linkPages*AltoDefs.PageSize];
    linkPages ← linkPages + 1;
    Storage.FreePages[linkTable];
    linkTable ← newbase;
    RETURN
    END;
    
  AppendLinkEntry: PUBLIC PROCEDURE [link: LinkHandle]
    RETURNS [index: LinkIndex] =
    BEGIN
    WHILE LOOPHOLE[linkIndex, CARDINAL] + SIZE[LinkEntry] >
      linkPages*AltoDefs.PageSize DO ExpandLinkTable[]; ENDLOOP;
    index ← linkIndex;
    InlineDefs.COPY[from: link, to: @linkTable[index], nwords: SIZE[LinkEntry]];
    linkIndex ← linkIndex + SIZE[LinkEntry];
    RETURN
    END;
    
  NILZ: POINTER = LOOPHOLE[0];
  
  PagePointer: TYPE = MACHINE DEPENDENT RECORD [page, byte: [0..256)];
  
  DeclareSeg: PUBLIC PROCEDURE [s: SegOps.Seg] RETURNS [BOOLEAN] =
    BEGIN
    entry: SegEntry ← SegEntry[
      data: s.data, write: s.write, locked: s.resident, in: s.in, base: 0,
      pages: s.pages, vmPage: s.vmPage, handle: NIL];
    s.index ← AppendSegEntry[@entry];
    RETURN[FALSE];
    END;
    
  DeclareSegs: PUBLIC PROCEDURE =
    BEGIN [] ← SegOps.EnumerateSegs[DeclareSeg]; RETURN END;
    
  DeclareCodeLinks: PUBLIC PROCEDURE =
    BEGIN
    entry: LinkEntry;
    i: CARDINAL;
    mt: DESCRIPTOR FOR ARRAY OF BootmesaOps.ModuleInfo = data.moduleTable;
    FOR i IN [1..LENGTH[mt]) DO
      IF i # mt[i].mth.gfi THEN LOOP;
      entry ← LinkEntry[codeseg: mt[i].code.index, frame: mt[i].frame];
      [] ← AppendLinkEntry[@entry];
      ENDLOOP;
    RETURN
    END;
    
  WriteScriptSegments: PUBLIC PROCEDURE =
    BEGIN OPEN SegOps, StreamDefs;
    pages, segWords, linkWords, left: CARDINAL;
    tseg, daSeg: Seg;
    tEntry, daEntry: SegEntry;
    tIndex: SegIndex ← AppendSegEntry[@tEntry];
    daIndex: SegIndex ← AppendSegEntry[@daEntry];
    segWords ← LOOPHOLE[header.segLength ← segIndex];
    header.linkOffset ← LOOPHOLE[segIndex];
    linkWords ← LOOPHOLE[header.linkLength ← linkIndex];
    pages ← Storage.PagesForWords[segWords + linkWords];
    data.vmTableSeg ← tseg ← NewSeg[DefaultFile, SegOps.ffvmp, pages, TRUE];
    data.daSeg ← daSeg ← NewSeg[DefaultFile, SegOps.ffvmp, 1, TRUE];
    data.image.prefix.diskAddresses ← header.diskAddresses ←
      SegmentDefs.AddressFromPage[daSeg.vmPage];
    BootmesaOps.SegmentToMap[tseg];
    vmTable ← SegmentDefs.AddressFromPage[tseg.vmPage];
    header.segOffset ← 0;
    tEntry ← SegEntry[
      data: TRUE, write: FALSE, locked: TRUE, in: TRUE, pages: pages,
      vmPage: tseg.vmPage, base: 0, handle: NIL];
    tseg.index ← tIndex;
    BootmesaOps.EnterMapSegment[tseg];
    tEntry.base ← GetIndex[data.imageStream].page + 1;
    segTable[tIndex] ← tEntry;
    daEntry ← SegEntry[
      data: TRUE, write: FALSE, locked: TRUE, in: TRUE, pages: 1,
      vmPage: daSeg.vmPage, base: 0, handle: NIL];
    daSeg.index ← daIndex;
    segTable[daSeg.index ← daIndex] ← daEntry;
    IF WriteBlock[data.imageStream, segTable, segWords] # segWords THEN ERROR;
    IF WriteBlock[data.imageStream, linkTable, linkWords] # linkWords THEN ERROR;
    left ← AltoDefs.PageSize - (segWords + linkWords) MOD AltoDefs.PageSize;
    IF left # AltoDefs.PageSize THEN
      BEGIN
      p: POINTER = Storage.Pages[1];
      MiscDefs.Zero[p, left];
      IF WriteBlock[data.imageStream, p, left] # left THEN ERROR;
      Storage.FreePages[p];
      END;
    CleanupDiskStream[data.imageStream];
    Storage.FreePages[segTable];
    Storage.FreePages[linkTable];
    tableFileSegment ← SegmentDefs.NewFileSegment[
      data.imageFile, tEntry.base, pages, SegmentDefs.Read + SegmentDefs.Write];
    SegmentDefs.SwapIn[tableFileSegment];
    segTable ← SegmentDefs.FileSegmentAddress[tableFileSegment];
    linkTable ← segTable + header.linkOffset;
    ExpandingAllowed ← FALSE;
    RETURN
    END;
    
  [] ← CommanderDefs.AddCommand[
    "DisableHyperspace", LOOPHOLE[DisableHyperspace], 0];
  
  END..