-- Wart.Mesa   Edited by Sandman on September 2, 1980  7:52 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoFileDefs USING [CFP, FP],
  BcplOps USING [BcplJSR],
  ControlDefs USING [
    AV, FrameHandle, GlobalFrameHandle, GFT, NullFrame, StateVector, TraceOff],
  CoreSwapDefs USING [level],
  DirectoryDefs USING [EnumerateDirectory],
  DiskDefs USING [DA, VirtualDA],
  ForgotOps USING [disableInterrupt],
  FrameOps USING [GetReturnFrame, MyGlobalFrame, Restart, Start],
  ImageFormat USING [FirstImageDataPage],
  ImageDefs USING [FileRequest, PuntMesa],
  InlineDefs USING [COPY],
  LoadStateFormat USING [LoadState, LoadStateObject],
  LoadStateOps USING [dirty, gft, initstate, loadstate, ReleaseLoadState, state],
  NucleusOps,
  ProcessDefs USING [
    CV, Detach, DisableTimeout, EnableInterrupts, GetPriority, ParityLevel,
    Priority, SetPriority, SetTimeout],
  ProcessOps USING [FirstProcess, WriteWDC],
  SDDefs,
  SDOps,
  SegmentDefs USING [
    AccessOptions, AddressFromPage, DataSegmentHandle, DeleteDataSegment,
    DeleteFileSegment, EnumerateFileSegments, FileHandle, FileHint,
    FileSegmentAddress, FileSegmentHandle, FrameDS, InsertFile, LockFile,
    PageNumber, Read, SwapOut, SystemDS, Unlock, VMtoDataSegment, Write],
  StringDefs USING [EquivalentString],
  SwapperOps USING [
    BootDataSegment, BootFile, BootFileSegment, EnableHyperspace, InitMemory,
    MoveCode],
  TrapOps USING [WriteXTS],
  WartDefs USING [
    Header, LinkEntry, LinkIndex, SegIndex, SegEntry, SegHandle, TableBase,
    VersionID];

Wart: PROGRAM [h: POINTER TO WartDefs.Header] RETURNS [PROGRAM]
  IMPORTS
    CoreSwapDefs, DirectoryDefs, DiskDefs, ForgotOps, FrameOps, ImageDefs, LoadStateOps,
    SwapperOps, BcplOps, NucleusOps, ProcessDefs, ProcessOps, SDOps, SegmentDefs,
    StringDefs, TrapOps, InlineDefs
  EXPORTS NucleusOps
  SHARES ControlDefs, DiskDefs, SegmentDefs =
  BEGIN OPEN WartDefs, ControlDefs, SegmentDefs;

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

  Nub: TYPE = PROGRAM [GlobalFrameHandle];

  InitSD: PROCEDURE =
    BEGIN OPEN SDDefs, SDOps;
    sd: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD;
    sd[sStart] ← Start;
    sd[sRestart] ← Restart;
    sd[sBLTE] ← BlockEqual;
    sd[sBLTEC] ← BlockEqualCode;
    sd[sBLTEL] ← BlockEqualLong;
    sd[sBLTECL] ← BlockEqualCodeLong;
    sd[sBYTBLTE] ← ByteBlockEqual;
    sd[sBYTBLTEC] ← ByteBlockEqualCode;
    sd[sBYTBLTEL] ← ByteBlockEqualLong;
    sd[sBYTBLTECL] ← ByteBlockEqualCodeLong;
    sd[sStringInit] ← StringInit;
    sd[sSignedDiv] ← SignDivide;
    sd[sLongDivMod] ← DDivMod;
    sd[sLongMod] ← DMod;
    sd[sLongDiv] ← DDiv;
    sd[sLongMul] ← DMultiply;
    sd[sULongDivMod] ← DUnsignedDivMod;
    sd[sULongMod] ← DUnsignedMod;
    sd[sULongDiv] ← DUnsignedDiv;
    sd[sStackError] ← StackErrorTrap;
    sd[sControlFault] ← ControlFaultTrap;
    sd[sBoundsFault] ← BoundsFaultTrap;
    sd[sPointerFault] ← PointerFaultTrap;
    sd[sWakeupError] ← WakeupErrorTrap;
    sd[sZeroDivisor] ← ZeroDivisorTrap;
    sd[sDivideCheck] ← DivideCheckTrap;
    sd[sUnimplemented] ← UnimplementedInstTrap;
    sd[sPageFault] ← PageFaultTrap;
    sd[sWriteProtect] ← WriteProtectFaultTrap;
    sd[sHardwareError] ← HardwareErrorTrap;
    sd[sAllocTrap] ← AllocTrap[AllocTrap[NullFrame]];
    sd[sSwapTrap] ← CodeTrap;
    sd[sUnbound] ← UnboundProcedureTrap;
    sd[sBreak] ← Break;
    sd[sAlternateBreak] ← WorryBreaker[];
    sd[sWorryCallDebugger] ← WorryCallDebugger[];
    sd[sIOResetBits] ← 3;
    sd[sSignalList] ← SignalList;
    sd[sSignal] ← Signal;
    sd[sErrorList] ← ErrorList;
    sd[sError] ← Error;
    sd[sReturnErrorList] ← ReturnErrorList;
    sd[sReturnError] ← ReturnError;
    sd[sUnnamedError] ← UnnamedError;
    END;

  InitInterrupts: PUBLIC PROCEDURE =
    BEGIN OPEN ProcessDefs;
    save: Priority = GetPriority[];
    ForgotOps.disableInterrupt ← FALSE;
    SetTimeout[@NucleusOps.interruptWakeup, 1];
    SetPriority[NucleusOps.InterruptPriority];
    Detach[FORK NucleusOps.InterruptProcess];
    SetPriority[save];
    RETURN
    END;

  InitParity: PUBLIC PROCEDURE =
    BEGIN OPEN ProcessDefs;
    p: PROCESS;
    save: Priority ← GetPriority[];
    DisableTimeout[@NucleusOps.parityWakeup];
    CV[ParityLevel] ← @NucleusOps.parityWakeup;
    SetPriority[LAST[Priority]];
    p ← FORK NucleusOps.ParityProcess;
    SetPriority[save];
    RETURN
    END;

  InitLoadState: PROCEDURE [ls, initls, bcdseg: FileSegmentHandle] =
    BEGIN OPEN SegmentDefs, LoadStateOps;
    initloadstate: LoadStateFormat.LoadState ← FileSegmentAddress[initls];
    initstate ← initls;
    loadstate ← FileSegmentAddress[state ← ls];
    gft ← DESCRIPTOR[@loadstate.gft, SDDefs.SD[SDDefs.sGFTLength]];
    InlineDefs.COPY[
      from: initloadstate, to: loadstate,
      nwords: LENGTH[gft] + SIZE[LoadStateFormat.LoadStateObject]];
    WITH loadstate.bcds[0] SELECT FROM
      alto => {
	base ← bcdseg.base;
	WITH s: bcdseg SELECT FROM disk => da ← s.hint.da; ENDCASE};
      ENDCASE;
    dirty ← TRUE;
    ReleaseLoadState[];
    Unlock[initls];
    initls.write ← FALSE;
    SwapOut[initls];
    IF bcdseg.lock = 1 THEN Unlock[bcdseg];
    DeleteFileSegment[bcdseg];
    END;

  ProcessWartList: PROCEDURE RETURNS [PROGRAM] =
    BEGIN
    segBase: TableBase = h.tablebase + h.segOffset;
    linkBase: TableBase = h.tablebase + h.linkOffset;
    imagefile: SegmentDefs.FileHandle;
    link: LinkIndex;
    seg: SegIndex;
    access: SegmentDefs.AccessOptions;
    s: SegHandle;
    frame: ControlDefs.GlobalFrameHandle;
    vmaddr, nub: POINTER;
    RequestHead: POINTER TO ImageDefs.FileRequest ← NIL;
    useHyperSpace: BOOLEAN ← h.useHyperSpace;

    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
	r: POINTER TO ImageDefs.FileRequest;
	prev: POINTER TO ImageDefs.FileRequest ← NIL;
	FOR r ← RequestHead, r.link UNTIL r = NIL DO
	  IF StringDefs.EquivalentString[dname, r.name] THEN
	    BEGIN
	    IF r.file = NIL THEN LockFile[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;
    SDDefs.SD[SDDefs.sBreak] ← WartBreak;
    SDDefs.SD[SDDefs.sAddFileRequest] ← AddFileRequest;
    FrameOps.Start[LOOPHOLE[NucleusOps.Resident]];
    FrameOps.Start[LOOPHOLE[NucleusOps.NonResident]];
    FrameOps.Start[LOOPHOLE[NucleusOps.Faults]];
    InitSD[];
    SDDefs.SD[SDDefs.sBreak] ← WartBreak;
    NucleusOps.InitSwapPorts[];
    CoreSwapDefs.level ← -1;
    START NucleusOps.DiskIO;
    START NucleusOps.Miscellaneous;
    START NucleusOps.MesaInit;
    IF h.version # WartDefs.VersionID THEN ImageDefs.PuntMesa[];
    SwapperOps.InitMemory[h.ffvmp, h.lfvmp];
    START NucleusOps.OurProcess;
    ProcessDefs.EnableInterrupts[];
    START NucleusOps.Signaller;
    START NucleusOps.SegmentsA;
    START NucleusOps.SegmentsB;
    START NucleusOps.Files;
    START NucleusOps.Modules;
    imagefile ← SwapperOps.BootFile[Read];
    FOR seg ← LOOPHOLE[SIZE[Header]], seg + SIZE[SegEntry] UNTIL seg = h.segLength
      DO
      s ← @segBase[seg];
      access ← IF s.write THEN Read + Write ELSE Read;
      vmaddr ← IF s.in THEN AddressFromPage[s.vmPage] ELSE NIL;
      IF s.data THEN s.handle ← SwapperOps.BootDataSegment[s.vmPage, s.pages]
      ELSE
	s.handle ← SwapperOps.BootFileSegment[
	  file: imagefile, base: s.base, pages: s.pages, access: access,
	  addr: vmaddr];
      IF ~s.locked AND vmaddr # NIL THEN Unlock[s.handle];
      ENDLOOP;
    FOR link ← FIRST[LinkIndex], link + SIZE[LinkEntry] UNTIL link = h.linkLength
      DO
      frame ← linkBase[link].frame;
      s ← @segBase[linkBase[link].codeseg];
      frame.code.handle ← s.handle;
      LOOPHOLE[frame.code.handle, FileSegmentHandle].class ← code;
      ENDLOOP;
    VMtoDataSegment[FrameOps.MyGlobalFrame[]].type ← FrameDS;
    VMtoDataSegment[ControlDefs.AV].type ← SystemDS;
    VMtoDataSegment[ControlDefs.GFT].type ← SystemDS;
    VMtoDataSegment[ProcessOps.FirstProcess↑].type ← SystemDS;
    InitInterrupts[];
    START NucleusOps.DiskKD;
    BootPageTable[imagefile, h.diskAddresses]; -- no swapping before here
    DeleteDataSegment[VMtoDataSegment[h.diskAddresses]];
    START NucleusOps.LoadState;
    InitLoadState[
      ls: segBase[h.loadState].handle, initls: segBase[h.initLoadState].handle,
      bcdseg: segBase[h.bcd].handle];
    START LOOPHOLE[nub ← h.nub, Nub][h.user];
    ProcessFileRequests[];
    InitParity[];
    DeleteDataSegment[VMtoDataSegment[segBase]];
    SwapperOps.EnableHyperspace[];
    IF useHyperSpace THEN SwapperOps.MoveCode[direction: outofMDS];
    SDDefs.SD[SDDefs.sAddFileRequest] ← 0;
    SDDefs.SD[SDDefs.sBreak] ← SDOps.Break;
    FrameOps.GetReturnFrame[].returnlink ← LOOPHOLE[FrameOps.Restart];
    RETURN[LOOPHOLE[nub]];
    END;

  -- page table

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

  BootPageTable: PROCEDURE [file: FileHandle, pt: POINTER TO PageTable] =
    BEGIN OPEN AltoFileDefs, DiskDefs;
    lastpage: PageNumber;
    pageInc: PageNumber = pt.firstpage - ImageFormat.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;

  ProcessOps.WriteWDC[1]; -- interrupts off
  TrapOps.WriteXTS[ControlDefs.TraceOff];
  RETURN[ProcessWartList[]];

  END..