-- Wart.Mesa   Edited by Geschke on September 20, 1978  8:45 AM

DIRECTORY
  AltoFileDefs: FROM "altofiledefs" USING [CFP, FP],
  BootDefs: FROM "bootdefs" USING [
    BootDataSegment, BootFile, BootFileSegment],
  CodeDefs: FROM "codedefs" USING [MesaCompatible],
  ControlDefs: FROM "controldefs" USING [
    FrameHandle, GetReturnFrame, GlobalFrameHandle, Greg, StateVector, WDCreg,
    XTSreg],
  DirectoryDefs: FROM "directorydefs" USING [EnumerateDirectory],
  DiskDefs: FROM "diskdefs" USING [DA, VirtualDA],
  FrameDefs: FROM "framedefs" USING [Restart, Start, SwapOutCode],
  ImageDefs: FROM "imagedefs" USING [FileRequest, FirstImageDataPage],
  NovaOps: FROM "novaops" USING [NovaJSR, Stop],
  NucleusDefs: FROM "nucleusdefs" USING [
    DiskIO, DiskKD, Files, LoadState, NonResident, Process, Resident,
    Segments, Signaller, Swapper],
  SDDefs: FROM "sddefs" USING [sAddFileRequest, sBreak],
  SegmentDefs: FROM "segmentdefs" USING [
    AddressFromPage, DataSegmentHandle, DeleteDataSegment, DeleteFileSegment,
    EnumerateFileSegments, FileHandle, FileHint, FileSegmentHandle,
    InsertFile, NewDataSegment, PageFromAddress, PageNumber, Read, Unlock,
    VMtoDataSegment, Write],
  StringDefs: FROM "stringdefs" USING [
    EquivalentString, EquivalentSubStrings, SubStringDescriptor],
  TrapDefs: FROM "trapdefs" USING [TraceOff],
  WartDefs: FROM "wartdefs" USING [
    BootIndex, BootScriptEntry, BootScriptHeader, NullBootIndex],
  XMESA: FROM "xmesaprivatedefs" USING [InitMemoryConfig, MoveLockedCode];

DEFINITIONS FROM WartDefs, ControlDefs, SegmentDefs;

Wart: PROGRAM [h: POINTER TO BootScriptHeader] RETURNS [PROGRAM]
  IMPORTS BootDefs, DirectoryDefs, DiskDefs, FrameDefs, NucleusDefs,
    SegmentDefs, StringDefs, CodeDefs, XMESA
  EXPORTS NucleusDefs SHARES ControlDefs, DiskDefs, ImageDefs, SegmentDefs =
  BEGIN

  WartBreak: PROCEDURE  =
    BEGIN OPEN NovaOps;
    s: StateVector;
    f: FrameHandle;
    break: RECORD[a,b: WORD];
    s ← STATE;
    break ← [77400B, 1400B];
    f ← GetReturnFrame[];
    s.dest ← f;
    f.pc ← [IF f.pc < 0 THEN -f.pc ELSE (1-f.pc)];
    s.instbyte ← NovaJSR[JSR, @break, 0];
    RETURN WITH s;
    END;

  Nub: TYPE = PROGRAM [GlobalFrameHandle];

  ProcessWartList: PROCEDURE RETURNS [PROGRAM] =
    BEGIN
    eb: CARDINAL = h.tablebase;
    imagefile: SegmentDefs.FileHandle;
    oldp, p: BootIndex ← FIRST[WartDefs.BootIndex];
    OldBreak: PROCEDURE;
    MyBreak: PROCEDURE ← WartBreak;
    SD: POINTER TO ARRAY [0..1) OF UNSPECIFIED = h.sd;
    ptSegment: DataSegmentHandle ← NIL;
    pPageTable: POINTER TO PageTable = ppPageTable↑;
    vmaddr: POINTER;
    RequestHead: POINTER TO ImageDefs.FileRequest ← NIL;
    AddFileRequest: PROCEDURE [r: POINTER TO ImageDefs.FileRequest] =
      BEGIN
      r.link ← RequestHead;
      RequestHead ← r;
      END;
    ProcessFileRequests: PROCEDURE =
      BEGIN OPEN AltoFileDefs;
      checkone: PROCEDURE [fp: POINTER TO FP, dname: STRING] RETURNS [BOOLEAN] =
	BEGIN
	ss: StringDefs.SubStringDescriptor ← [dname,0,dname.length];
	r: POINTER TO ImageDefs.FileRequest;
	prev: POINTER TO ImageDefs.FileRequest ← NIL;
	FOR r ← RequestHead, r.link UNTIL r = NIL DO
	  IF (WITH r SELECT FROM
		long => StringDefs.EquivalentSubStrings[@ss,@name],
		short => StringDefs.EquivalentString[dname,name],
		ENDCASE => FALSE) THEN
	    BEGIN
	    IF r.file = NIL THEN r.file ← InsertFile[fp,r.access]
	    ELSE r.file.fp ← fp↑;
	    IF prev = NIL THEN RequestHead ← r.link
	    ELSE prev.link ← r.link;
	    END
	  ELSE prev ← r;
	  ENDLOOP;
	RETURN[RequestHead = NIL]
	END;
      DirectoryDefs.EnumerateDirectory[checkone];
      END;

    REGISTER[WDCreg] ← 0;  -- interrupts on
    SD[SDDefs.sBreak] ← MyBreak;
    SD[SDDefs.sAddFileRequest] ← AddFileRequest;
    DO -- exited by a Stop BootScriptEntry
      WITH (eb+p) SELECT FROM
	Command =>
	  BEGIN
	  SELECT command FROM
	    bc0 =>
	      BEGIN
	      FrameDefs.Start[LOOPHOLE[NucleusDefs.Resident]];
	      FrameDefs.Start[LOOPHOLE[NucleusDefs.NonResident]];
	      OldBreak ← SD[SDDefs.sBreak];
	      SD[SDDefs.sBreak] ← MyBreak;
	      START CodeDefs.MesaCompatible;
	      START NucleusDefs.DiskIO;
	      START NucleusDefs.Swapper[h.ffvmp, h.lfvmp];
	      ptSegment ← NewDataSegment[PageFromAddress[pPageTable], 1];
	      START NucleusDefs.Process;
	      START NucleusDefs.Signaller;
	      START NucleusDefs.Segments;
	      START NucleusDefs.Files;
	      imagefile ← BootDefs.BootFile[Read+Write];
	      END;
	    bc1 =>
	      BEGIN
	      START NucleusDefs.DiskKD;
	      START NucleusDefs.LoadState[(eb+h.loadState).handle,
		(eb+h.initLoadState).handle, (eb+h.bcd).handle];
	      SegmentDefs.Unlock[(eb+h.bcd).handle];
	      SegmentDefs.DeleteFileSegment[(eb+h.bcd).handle];
	      START LOOPHOLE[h.nub, Nub][h.user];
	      END;
	    bc2 =>
	      BEGIN
	      RESTART NucleusDefs.Resident;
	      END;
 	    ENDCASE;
	  p ← p + SIZE [Command BootScriptEntry];
	  END;
	SwapOutCode =>
	  BEGIN
	  FrameDefs.SwapOutCode[frame];
	  p ← p + SIZE [SwapOutCode BootScriptEntry];
	  END;
	OpenFile =>
	  BEGIN
	  ProcessFileRequests[];
	  p ← p + SIZE [OpenFile BootScriptEntry];
	  END;
	Segment =>
	  BEGIN OPEN BootDefs;
	  vmaddr ← IF vmpage = 0 THEN NIL ELSE AddressFromPage[vmpage];
	  handle ← IF data
	    THEN LOOPHOLE[BootDataSegment[base,pages]]
	    ELSE BootFileSegment[imagefile, base, pages, access, vmaddr];
	  p ← p + SIZE [Segment BootScriptEntry];
	  END;
	CodeLink =>
	  BEGIN
	  --Note: all codesegments from Wart begin life in bank 0--			--XM
	  frame.codesegment ← (eb+codeseg).handle;
	  (eb+codeseg).handle.class ← code;
	  IF frame = LOOPHOLE[REGISTER[Greg], GlobalFrameHandle] THEN
	    BEGIN
	    BootPageTable[imagefile, pPageTable];
	    DeleteDataSegment[ptSegment];
	    END;
	  p ← p + SIZE [CodeLink BootScriptEntry];
	  END;
	Unlock =>
	  BEGIN
	  IF seg#NullBootIndex THEN Unlock[(eb+seg).handle];
	  p ← p + SIZE [Unlock BootScriptEntry];
	  END;
	Stop =>
	  BEGIN
	  OPEN XMESA;
	  InitMemoryConfig[]; MoveLockedCode[direction: up];
	  EXIT
	  END;
	ENDCASE => NovaOps.Stop[Punt];
      IF p=oldp THEN NovaOps.Stop[Punt];
      oldp ← p;
      ENDLOOP;

    DeleteDataSegment[VMtoDataSegment[LOOPHOLE[eb]]];
    SD[SDDefs.sAddFileRequest] ← 0;
    SD[SDDefs.sBreak] ← OldBreak;
    GetReturnFrame[].returnlink ← LOOPHOLE[FrameDefs.Restart];
    RETURN[LOOPHOLE[h.nub]];
    END;


-- page table

  PageTable: TYPE = MACHINE DEPENDENT RECORD [
    fp: AltoFileDefs.CFP,
    firstpage: CARDINAL,
    table: ARRAY [0..1) OF DiskDefs.DA];
  ppPageTable: POINTER TO POINTER TO PageTable = LOOPHOLE[24B];

  BootPageTable: PROCEDURE [file:FileHandle, pt:POINTER TO PageTable] =
    BEGIN OPEN AltoFileDefs, DiskDefs;
    lastpage: PageNumber;
    pageInc: PageNumber = pt.firstpage - ImageDefs.FirstImageDataPage;
    PlugHint: PROCEDURE [seg:FileSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      IF seg.file = file THEN
	BEGIN
	seg.base ← seg.base + pageInc;
	IF seg.base IN [pt.firstpage..lastpage] THEN
          WITH s: seg SELECT FROM
	    disk => s.hint ← FileHint[
              page: s.base,
              da: DiskDefs.VirtualDA[pt.table[s.base-pt.firstpage]]];
	    ENDCASE;
	END;
      RETURN[FALSE]
      END;
    file.open ← TRUE;
    file.fp ← FP[serial: pt.fp.serial, leaderDA: pt.fp.leaderDA];
    FOR lastpage ← 0, lastpage+1
    UNTIL pt.table[lastpage] = DA[0,0,0,0,0]
      DO NULL ENDLOOP;
    IF lastpage = 0 THEN RETURN;
    lastpage ← lastpage+pt.firstpage-1;
    [] ← EnumerateFileSegments[PlugHint];
    RETURN
    END;

  REGISTER[ControlDefs.XTSreg] ← TrapDefs.TraceOff;
  RETURN[ProcessWartList[]];

  END..