-- CheckPoint.Mesa Edited by Sandman on September 24, 1980  10:44 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AllocDefs USING [
    AddSwapStrategy, RemoveSwapStrategy, SwappingProcedure, SwapStrategy],
  AltoDefs USING [BytesPerPage, PageCount, PageNumber, PageSize],
  AltoFileDefs USING [CFA, FA, fillinDA, FP, NullFP, vDA],
  BcdDefs USING [VersionStamp],
  BFSDefs USING [ActOnPages, GetNextDA],
  ControlDefs USING [
    AllocationVector, AllocationVectorSize, AV, ControlLink, EntryVectorItem,
    FrameHandle, FrameVec, GFT, GFTIndex, GlobalFrameHandle, LargeReturnSlot,
    LastAVSlot, PrefixHandle, ProcDesc, SpecialReturnSlot, StateVector,
    SVPointer],
  CoreSwapDefs USING [PuntInfo, level],
  DiskDefs USING [DA, DiskRequest, RealDA],
  DiskKDDefs USING [CloseDiskKD],
  FrameDefs USING [GlobalFrame, MakeCodeResident, SwapInCode],
  FrameOps USING [CodeHandle, Free, FlushLargeFrames, MyLocalFrame],
  ImageDefs USING [ImageVersion, PuntMesa, UserCleanupProc],
  ImageFormat USING [
    FirstImageDataPage, HeaderPages, ImageHeader, ImagePrefix, MapItem,
    VersionID],
  InlineDefs USING [BITAND, COPY],
  LoadStateFormat USING [LoadState],
  LoadStateOps USING [initstate, InputLoadState, ReleaseLoadState, state],
  MiscDefs USING [CurrentTime, GetNetworkNumber, SetBlock, Zero],
  NucleusOps USING [
    BFS, Directory, DiskKD, Faults, Files, FSP, HyperRegion, LoadState, MesaInit,
    Miscellaneous, Modules, NonResident, OurProcess, SegmentsA, SegmentsB,
    StreamsA, StreamsB, StreamsC, StringsA, StringsB],
  OsStaticDefs USING [OsStatics],
  ProcessDefs USING [
    CV, DisableInterrupts, DIW, EnableInterrupts, Priority, SetPriority],
  ProcessOps USING [
    ActiveWord, CurrentPSB, CurrentState, FirstProcess, LastProcess,
    NullQueueHandle, Queue, ReadWDC, ReadyList, Requeue, WakeupsWaiting,
    WriteWDC],
  PSBDefs USING [ProcessHandle, PSB],
  Region USING [Node, NodeObject],
  SDDefs USING [sAllocTrap, SD, sSwapTrap, sXferTrap],
  SegmentDefs USING [
    AddressFromPage, Append, CloseFile, DataSegmentAddress, DataSegmentHandle,
    DefaultBase, DefaultVersion, DeleteDataSegment, EnumerateDataSegments,
    EnumerateFiles, EnumerateFileSegments, FileError, FileHandle,
    FileSegmentAddress, FileSegmentHandle, GetFileSegmentDA, JumpToPage,
    MapFileSegment, NewDataSegment, NewFile, Object, ObjectHandle, Read, SetEndOfFile,
    SwapIn, SwapOut, Unlock, Write],
  Storage USING [Pages, FreePages, Prune],
  SwapperOps USING [
    AllocateObject, LiberateObject, mdsNodes, MoveCode, DisableHyperspace,
    EnableHyperspace, InitMemoryConfig],
  TrapOps USING [ReadATP, ReadOTP, ReadXTS, WriteXTS];

CheckPoint: PROGRAM
  IMPORTS
    BFSDefs, CoreSwapDefs, AllocDefs, SwapperOps, DiskDefs, DiskKDDefs, FrameDefs,
    FrameOps, ImageDefs, InlineDefs, LoadStateOps, MiscDefs, NucleusOps,
    ProcessDefs, ProcessOps, SegmentDefs, Storage, TrapOps
  EXPORTS ImageDefs
  SHARES DiskDefs, SegmentDefs =
  BEGIN OPEN ImageFormat, ControlDefs;

  CFA: TYPE = AltoFileDefs.CFA;
  DataSegmentHandle: TYPE = SegmentDefs.DataSegmentHandle;
  FP: TYPE = AltoFileDefs.FP;
  FileHandle: TYPE = SegmentDefs.FileHandle;
  FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle;
  PageSize: CARDINAL = AltoDefs.PageSize;
  PageCount: TYPE = AltoDefs.PageCount;
  PageNumber: TYPE = AltoDefs.PageNumber;
  vDA: TYPE = AltoFileDefs.vDA;

  SwapTrapDuringMakeCheck: PUBLIC SIGNAL = CODE;
  SwapErrorDuringMakeCheck: PUBLIC SIGNAL = CODE;
  SwapOutDuringMakeCheck: PUBLIC SIGNAL = CODE;
  NoRoomInCheckMap: PUBLIC SIGNAL = CODE;

  SwapTrapError: PROCEDURE =
    BEGIN
    dest: ControlLink;
    s: StateVector;
    ProcessDefs.DisableInterrupts[];
    s ← STATE;
    dest ← TrapOps.ReadOTP[];
    ProcessDefs.EnableInterrupts[];
    SIGNAL SwapTrapDuringMakeCheck;
    RETURN WITH s;
    END;

  SwapOutError: AllocDefs.SwappingProcedure =
    BEGIN SIGNAL SwapOutDuringMakeCheck; RETURN[TRUE]; END;

  -- File Segment Transfer Routines


  LockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] =
    BEGIN
    FrameDefs.MakeCodeResident[frame];
    FrameDefs.SwapInCode[frame];
    SegmentDefs.Unlock[FrameOps.CodeHandle[frame]];
    END;

  UnlockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] =
    BEGIN SegmentDefs.Unlock[FrameOps.CodeHandle[frame]]; END;

  DAofPage: PROCEDURE [file: FileHandle, page: PageNumber] RETURNS [next: vDA] =
    BEGIN
    cfa: CFA;
    buf: POINTER = Storage.Pages[1];
    cfa.fp ← file.fp;
    cfa.fa ← AltoFileDefs.FA[file.fp.leaderDA, 0, 0];
    next ← SegmentDefs.JumpToPage[@cfa, page - 1, buf].next;
    Storage.FreePages[buf];
    RETURN
    END;

  FillInCAs: PROCEDURE [
    Image: POINTER TO ImageHeader, mapindex: CARDINAL, ca: POINTER] =
    BEGIN
    i: CARDINAL;
    map: POINTER TO ARRAY [0..0) OF normal MapItem = LOOPHOLE[@Image.map];
    addr: POINTER;
    FOR i IN [0..mapindex) DO
      addr ← SegmentDefs.AddressFromPage[map[i].page];
      THROUGH [0..map[i].count) DO
	ca↑ ← addr; ca ← ca + 1; addr ← addr + AltoDefs.PageSize; ENDLOOP;
      ENDLOOP;
    END;

  EnumerateNeededModules: PROCEDURE [proc: PROCEDURE [GlobalFrameHandle]] =
    BEGIN
    proc[FrameDefs.GlobalFrame[EnumerateNeededModules]];
    proc[LOOPHOLE[NucleusOps.BFS]];
    proc[LOOPHOLE[NucleusOps.SegmentsA]];
    proc[LOOPHOLE[NucleusOps.SegmentsB]];
    proc[LOOPHOLE[NucleusOps.Files]];
    proc[LOOPHOLE[NucleusOps.Faults]];
    proc[LOOPHOLE[NucleusOps.DiskKD]];
    proc[LOOPHOLE[NucleusOps.Miscellaneous]];
    proc[LOOPHOLE[NucleusOps.Directory]];
    proc[LOOPHOLE[NucleusOps.StreamsA]];
    proc[LOOPHOLE[NucleusOps.StreamsB]];
    proc[LOOPHOLE[NucleusOps.StreamsC]];
    proc[LOOPHOLE[NucleusOps.FSP]];
    proc[LOOPHOLE[NucleusOps.StringsA]];
    proc[LOOPHOLE[NucleusOps.StringsB]];
    proc[LOOPHOLE[NucleusOps.LoadState]];
    proc[LOOPHOLE[NucleusOps.MesaInit]];
    proc[LOOPHOLE[NucleusOps.NonResident]];
    proc[LOOPHOLE[NucleusOps.OurProcess]];
    proc[LOOPHOLE[NucleusOps.HyperRegion]];
    proc[LOOPHOLE[NucleusOps.Modules]];
    END;

  AdjustLoadState: PROCEDURE [state: FileSegmentHandle] =
    BEGIN OPEN SegmentDefs;
    imageFile: FileHandle = FrameOps.CodeHandle[
      LOOPHOLE[NucleusOps.MesaInit]].file;
    loadstate: LoadStateFormat.LoadState = FileSegmentAddress[state];
    i: CARDINAL;
    FOR i IN [0..loadstate.nBcds) DO
      WITH b: loadstate.bcds[i] SELECT FROM
	alto => IF b.fp = AltoFileDefs.NullFP THEN b.fp ← imageFile.fp;
	ENDCASE;
      ENDLOOP;
    RETURN
    END;

  AssureObjects: PROCEDURE = {
    OPEN SwapperOps, SegmentDefs;
    a: FileHandle;
    b: DataSegmentHandle;
    c: FileSegmentHandle;
    a ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file Object]]];
    a↑ ← [,file[,,,,,,,,,,,]];
    b ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[data segment Object]]];
    b↑ ← [,segment[,data[,]]];
    c ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file segment Object]]];
    c↑ ← [,segment[,file[,,,,,,,,]]];
    SwapperOps.LiberateObject[a];
    SwapperOps.LiberateObject[b];
    SwapperOps.LiberateObject[c]};

  MakeCheckPoint: PUBLIC PROCEDURE [name: STRING] RETURNS [restart: BOOLEAN] =
    BEGIN OPEN SegmentDefs, DiskDefs, AltoFileDefs;
    wdc: CARDINAL;
    diskrequest: DiskRequest;
    savealloctrap, saveswaptrap: ControlLink;
    auxtrapFrame: FrameHandle;
    saveAllocationVector: AllocationVector;
    saveXferTrap, saveXferTrapStatus: UNSPECIFIED;
    savePuntData: POINTER;
    datapages: PageCount ← 0;
    SwapOutErrorStrategy: AllocDefs.SwapStrategy ← AllocDefs.SwapStrategy[
      link:, proc: SwapOutError];
    mapindex: CARDINAL ← 0;
    maxFileSegPages: CARDINAL ← 0;
    endofdatamapindex: CARDINAL;
    HeaderSeg, daMapSeg: DataSegmentHandle;
    Image: POINTER TO ImageHeader;
    HeaderDA: vDA;
    checkFile: FileHandle;
    saveDIW: WORD;
    savePV: ARRAY [0..15] OF UNSPECIFIED;
    saveReadyList: ProcessOps.Queue;
    savePriority: ProcessDefs.Priority;
    saveCurrentPSB: PSBDefs.ProcessHandle;
    saveCurrentState: SVPointer;
    initstateseg: FileSegmentHandle ← LoadStateOps.initstate;
    stateseg: FileSegmentHandle ← LoadStateOps.state;
    net: CARDINAL ← MiscDefs.GetNetworkNumber[];
    segs: DESCRIPTOR FOR ARRAY OF FileSegmentHandle;
    maxnumbersegments: CARDINAL ← 0;
    nextpage: PageNumber;
    level: CARDINAL ← 0;
    wordsForDAMap: CARDINAL ← 0;
    mdsFreeList: DESCRIPTOR FOR ARRAY OF Region.NodeObject;
    SaveMDSFreeList: PROCEDURE =
      BEGIN OPEN SwapperOps;
      nNodes, i: CARDINAL;
      node: Region.Node;
      nNodes ← 0;
      FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO
	nNodes ← nNodes + 1; ENDLOOP;
      IF nNodes = 0 THEN BEGIN mdsFreeList ← DESCRIPTOR[NIL, 0]; RETURN END;
      mdsFreeList ← DESCRIPTOR[auxalloc[nNodes*SIZE[Region.NodeObject]], nNodes];
      i ← 0;
      FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO
	mdsFreeList[i] ← node↑; i ← i + 1; ENDLOOP;
      END;
    RestoreMDSFreeList: PROCEDURE =
      BEGIN OPEN SwapperOps;
      i: CARDINAL ← 0;
      node: Region.Node;
      IF LENGTH[mdsFreeList] = 0 THEN RETURN;
      FOR i IN [0..LENGTH[mdsFreeList]) DO
	node ← AddressFromPage[mdsFreeList[i].base];
	node↑ ← mdsFreeList[i];
	ENDLOOP;
      END;
    SaveProcesses: PROCEDURE =
      BEGIN OPEN ProcessOps;
      saveDIW ← ProcessDefs.DIW↑;
      savePV ← ProcessDefs.CV↑;
      ProcessDefs.DIW↑ ← 0;
      WakeupsWaiting↑ ← 0;
      saveReadyList ← ReadyList↑;
      saveCurrentPSB ← CurrentPSB↑;
      savePriority ← CurrentPSB.priority;
      saveCurrentState ← CurrentState↑;
      END;
    RestoreProcesses: PROCEDURE =
      BEGIN OPEN ProcessDefs, ProcessOps;
      p: PSBDefs.ProcessHandle;
      ActiveWord↑ ← 77777B;
      ProcessDefs.DIW↑ ← saveDIW;
      ProcessDefs.CV↑ ← savePV;
      ReadyList↑ ← saveReadyList;
      CurrentPSB↑ ← saveCurrentPSB;
      CurrentPSB.priority ← LAST[Priority];
      CurrentState↑ ← saveCurrentState;
      FOR p ← FirstProcess↑, p + SIZE[PSBDefs.PSB] UNTIL p = LastProcess↑ DO
	IF p.state = alive AND p.timeout # 0 AND p.waitingOnCV THEN
	  BEGIN
	  p.waitingOnCV ← FALSE;
	  Requeue[from: NullQueueHandle, to: ReadyList, p: p];
	  END;
	ENDLOOP;
      SetPriority[savePriority];
      RETURN
      END;
    EnterNormalMapItem: PROCEDURE [vmpage: PageNumber, pages: PageCount] =
      BEGIN
      map: POINTER TO normal MapItem = LOOPHOLE[@Image.map];
      IF pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck;
      IF mapindex >=
	PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[normal MapItem] THEN
	SIGNAL NoRoomInCheckMap;
      (map + mapindex)↑ ← MapItem[vmpage, pages, normal[]];
      mapindex ← mapindex + SIZE[normal MapItem];
      END;
    CountDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      IF s # HeaderSeg AND s # daMapSeg THEN datapages ← datapages + s.pages;
      RETURN[FALSE];
      END;
    MapDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      IF s # HeaderSeg AND s # daMapSeg THEN
	BEGIN
	EnterNormalMapItem[s.VMpage, s.pages];
	nextpage ← nextpage + s.pages;
	END;
      RETURN[FALSE];
      END;
    CountMaxSegmentsPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] =
      BEGIN
      maxnumbersegments ← MAX[maxnumbersegments, f.swapcount];
      RETURN[FALSE];
      END;
    EnterSwappedInPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] =
      BEGIN
      nsegs: CARDINAL ← 0;
      next: PageNumber ← DefaultBase;
      i: CARDINAL;
      OrganizeSegments: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] =
	BEGIN
	i, j: CARDINAL;
	IF ~s.swappedin OR s.file # f THEN RETURN[FALSE];
	FOR i IN [0..nsegs) DO
	  IF segs[i].base > s.base THEN GOTO insert;
	  REPEAT
	    insert =>
	      BEGIN
	      FOR j DECREASING IN [i..nsegs) DO segs[j + 1] ← segs[j]; ENDLOOP;
	      segs[i] ← s;
	      END;
	    FINISHED => segs[nsegs] ← s;
	  ENDLOOP;
	RETURN[(nsegs ← nsegs + 1) = f.swapcount];
	END;
	IF f = checkFile OR f.swapcount = 0 THEN RETURN[FALSE];
      [] ← EnumerateFileSegments[OrganizeSegments];
      FOR i IN [0..nsegs) DO
	IF segs[i].base # next THEN EnterChangeMapItem[segs[i]]
	ELSE EnterNormalMapItem[segs[i].VMpage, segs[i].pages];
	next ← segs[i].base + segs[i].pages;
	ENDLOOP;
      RETURN[FALSE];
      END;
    EnterChangeMapItem: PROCEDURE [s: FileSegmentHandle] =
      BEGIN
      map: POINTER TO change MapItem = LOOPHOLE[@Image.map];
      da: DiskDefs.DA ← DiskDefs.RealDA[GetFileSegmentDA[s]];
      IF s.pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck;
      IF mapindex >=
	PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[change MapItem] THEN
	SIGNAL NoRoomInCheckMap;
      (map + mapindex)↑ ← MapItem[s.VMpage, s.pages, change[da, s.base]];
      mapindex ← mapindex + SIZE[change MapItem];
      END;
    checkFile ← NewFile[name, Read + Write + Append, DefaultVersion];
    ProcessDefs.DisableInterrupts[];
    wdc ← ProcessOps.ReadWDC[];
    level ← CoreSwapDefs.level;
    CoreSwapDefs.level ← -1;
    SaveProcesses[];
    ImageDefs.UserCleanupProc[Checkpoint];
    SwapperOps.MoveCode[direction: intoMDS];
    SwapperOps.DisableHyperspace[];
    SwapIn[initstateseg];
    [] ← LoadStateOps.InputLoadState[]; -- bring it in for first time
    AdjustLoadState[stateseg];
    [] ← Storage.Prune[];
    SetupAuxStorage[];
    EnumerateNeededModules[LockCodeSegment];
    HeaderDA ← DAofPage[checkFile, 1]; -- set up private frame allocation trap
    FrameOps.FlushLargeFrames[];
    savealloctrap ← SDDefs.SD[SDDefs.sAllocTrap];
    SDDefs.SD[SDDefs.sAllocTrap] ← auxtrapFrame ← auxtrap[];
    saveAllocationVector ← AV↑;
    AV↑ ← LOOPHOLE[DataSegmentAddress[AuxSeg], POINTER TO AllocationVector]↑;
    HeaderSeg ← NewDataSegment[DefaultBase, 1];
    daMapSeg ← NewDataSegment[DefaultBase, 3];
    AssureObjects[];
    [] ← EnumerateDataSegments[CountDataSegments];
    SetEndOfFile[
      checkFile, datapages + stateseg.pages*2 + FirstImageDataPage - 1,
      AltoDefs.BytesPerPage];
    [] ← DiskKDDefs.CloseDiskKD[];
    Image ← DataSegmentAddress[HeaderSeg];
    MiscDefs.Zero[Image, AltoDefs.PageSize*HeaderPages];
    Image.prefix.versionident ← ImageFormat.VersionID; --Image.prefix.options ← 0;
    --Image.prefix.state.stk[0] ← Image.prefix.state.stk[1] ← 0;
    Image.prefix.state.stkptr ← 2;
    Image.prefix.state.dest ← FrameOps.MyLocalFrame[];
    Image.prefix.type ← checkfile;
    Image.prefix.leaderDA ← checkFile.fp.leaderDA;
    Image.prefix.diskAddresses ← DataSegmentAddress[daMapSeg];
    Image.prefix.version ← BcdDefs.VersionStamp[
      time: MiscDefs.CurrentTime[], net: net,
      host: OsStaticDefs.OsStatics.SerialNumber];
    Image.prefix.creator ← ImageDefs.ImageVersion[];
    -- version stamp of currently running image
    nextpage ← FirstImageDataPage;
    [] ← EnumerateDataSegments[MapDataSegments];
    IF nextpage # FirstImageDataPage + datapages THEN ERROR;
    endofdatamapindex ← mapindex; -- Move LoadStates
    InlineDefs.COPY[
      from: FileSegmentAddress[stateseg], to: FileSegmentAddress[initstateseg],
      nwords: initstateseg.pages*PageSize];
    MapFileSegment[stateseg, checkFile, datapages + FirstImageDataPage];
    EnterNormalMapItem[stateseg.VMpage, stateseg.pages];
    MapFileSegment[
      initstateseg, checkFile, datapages + FirstImageDataPage + stateseg.pages];
    EnterNormalMapItem[initstateseg.VMpage, stateseg.pages];
    Image.prefix.loadStateBase ← stateseg.base;
    Image.prefix.initialLoadStateBase ← initstateseg.base;
    Image.prefix.loadStatePages ← initstateseg.pages; -- now disable swapping
    savePuntData ← CoreSwapDefs.PuntInfo↑;
    saveswaptrap ← SDDefs.SD[SDDefs.sSwapTrap];
    SDDefs.SD[SDDefs.sSwapTrap] ← SwapTrapError;
    AllocDefs.AddSwapStrategy[@SwapOutErrorStrategy];
    [] ← EnumerateFiles[CountMaxSegmentsPerFile];
    segs ← DESCRIPTOR[auxalloc[maxnumbersegments], maxnumbersegments];
    [] ← EnumerateFiles[EnterSwappedInPerFile];
    SegmentDefs.CloseFile[checkFile ! SegmentDefs.FileError => RESUME ];
    checkFile.write ← checkFile.append ← FALSE;
    diskrequest ← DiskRequest[
      ca: auxalloc[datapages + 3], da: auxalloc[datapages + 3], fixedCA: FALSE,
      fp: auxalloc[SIZE[FP]], firstPage: FirstImageDataPage - 1,
      lastPage: FirstImageDataPage + datapages - 1, action: WriteD,
      lastAction: WriteD, signalCheckError: FALSE,
      option: update[BFSDefs.GetNextDA]];
    diskrequest.fp↑ ← checkFile.fp;
    (diskrequest.ca + 1)↑ ← Image;
    FillInCAs[Image, endofdatamapindex, diskrequest.ca + 2];
    MiscDefs.SetBlock[diskrequest.da, fillinDA, datapages + 3];
    (diskrequest.da + 1)↑ ← HeaderDA;
    SaveMDSFreeList[];
    saveXferTrap ← SDDefs.SD[SDDefs.sXferTrap];
    SDDefs.SD[SDDefs.sXferTrap] ← FrameOps.MyLocalFrame[];
    saveXferTrapStatus ← TrapOps.ReadXTS[];
    restart ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]].page = 0;
    ProcessOps.WriteWDC[wdc];
    AV↑ ← saveAllocationVector;
    SDDefs.SD[SDDefs.sAllocTrap] ← savealloctrap;
    SDDefs.SD[SDDefs.sXferTrap] ← saveXferTrap;
    TrapOps.WriteXTS[saveXferTrapStatus];
    FrameOps.Free[auxtrapFrame];
    RestoreMDSFreeList[];
    SwapperOps.InitMemoryConfig[];
    DeleteDataSegment[daMapSeg];
    DeleteDataSegment[HeaderSeg]; -- turn swapping back on
    AllocDefs.RemoveSwapStrategy[@SwapOutErrorStrategy];
    SDDefs.SD[SDDefs.sSwapTrap] ← saveswaptrap;
    SwapperOps.EnableHyperspace[];
    RestoreProcesses[];
    CoreSwapDefs.PuntInfo↑ ← savePuntData;
    ProcessDefs.EnableInterrupts[];
    InlineDefs.COPY[
      to: FileSegmentAddress[stateseg], from: FileSegmentAddress[initstateseg],
      nwords: initstateseg.pages*PageSize];
    LoadStateOps.ReleaseLoadState[];
    Unlock[initstateseg];
    SwapOut[initstateseg];
    DeleteDataSegment[AuxSeg];
    EnumerateNeededModules[UnlockCodeSegment];
    SwapperOps.MoveCode[direction: outofMDS];
    ImageDefs.UserCleanupProc[IF restart THEN Restart ELSE Continue];
    RETURN
    END;

  -- auxillary storage for frames and non-saved items

  AuxSeg: DataSegmentHandle;
  freepointer: POINTER;
  wordsleft: CARDINAL;

  SetupAuxStorage: PROCEDURE =
    BEGIN OPEN SegmentDefs;
    av: POINTER;
    i: CARDINAL;
    AuxSeg ← NewDataSegment[DefaultBase, 5];
    av ← freepointer ← DataSegmentAddress[AuxSeg];
    wordsleft ← 10*PageSize;
    [] ← auxalloc[AllocationVectorSize];
    freepointer ← freepointer + 3;
    wordsleft ← wordsleft - 3;
    FOR i IN [0..LastAVSlot] DO (av + i)↑ ← (i + 1)*4 + 2; ENDLOOP;
    (av + 6)↑ ← (av + LargeReturnSlot)↑ ← (av + SpecialReturnSlot + 1)↑ ← 1;
    END;

  auxalloc: PROCEDURE [n: CARDINAL] RETURNS [p: POINTER] =
    BEGIN -- allocate in multiples of 4 words
    p ← freepointer;
    n ← InlineDefs.BITAND[n + 3, 177774B];
    freepointer ← freepointer + n;
    IF wordsleft < n THEN ImageDefs.PuntMesa[];
    wordsleft ← wordsleft - n;
    RETURN
    END;

  auxtrap: PROCEDURE RETURNS [myframe: FrameHandle] =
    BEGIN
    state: StateVector;
    newframe: FrameHandle;
    eventry: POINTER TO EntryVectorItem;
    fsize, findex: CARDINAL;
    newG: GlobalFrameHandle;
    dest, tempdest: ControlLink;
    alloc: BOOLEAN;
    gfi: GFTIndex;
    ep: CARDINAL;
    myframe ← LOOPHOLE[FrameOps.MyLocalFrame[]];
    state.dest ← myframe.returnlink;
    state.source ← 0;
    state.instbyte ← 0;
    state.stk[0] ← myframe;
    state.stkptr ← 1;
    ProcessDefs.DisableInterrupts[];
    DO
      ProcessDefs.EnableInterrupts[];
      TRANSFER WITH state;
      ProcessDefs.DisableInterrupts[];
      state ← STATE;
      dest ← TrapOps.ReadATP[];
      myframe.returnlink ← state.source;
      tempdest ← dest;
      DO
	SELECT tempdest.tag FROM
	  frame =>
	    BEGIN alloc ← TRUE; findex ← LOOPHOLE[tempdest, CARDINAL]/4; EXIT END;
	  procedure =>
	    BEGIN OPEN proc: LOOPHOLE[tempdest, ProcDesc];
	    gfi ← proc.gfi;
	    ep ← proc.ep;
	    [frame: newG, epbase: findex] ← GFT[gfi];
	    eventry ← @LOOPHOLE[newG.code.shortbase, PrefixHandle].entry[
	      findex + ep];
	    findex ← eventry.info.framesize;
	    alloc ← FALSE;
	    EXIT
	    END;
	  indirect => tempdest ← tempdest.link↑;
	  ENDCASE => ImageDefs.PuntMesa[];
	ENDLOOP;
      IF findex > LastAVSlot THEN ImageDefs.PuntMesa[];
      fsize ← FrameVec[findex];
      IF fsize MOD 4 # 0 THEN fsize ← fsize + 1;
      newframe ← LOOPHOLE[freepointer + 1];
      freepointer↑ ← findex;
      freepointer ← freepointer + fsize;
      IF wordsleft < fsize THEN ImageDefs.PuntMesa[]
      ELSE wordsleft ← wordsleft - fsize;
      IF alloc THEN
	BEGIN
	state.dest ← myframe.returnlink;
	state.stk[state.stkptr] ← newframe;
	state.stkptr ← state.stkptr + 1;
	END
      ELSE
	BEGIN
	state.dest ← dest;
	newframe.accesslink ← LOOPHOLE[AV[findex].frame];
	AV[findex].frame ← newframe;
	state.source ← myframe.returnlink;
	END;
      ENDLOOP;
    END;


  END.