-- Copyright (C) 1983, 1987  by Xerox Corporation. All rights reserved. 
-- Germ>GermOpsLinkageImpl.mesa     16-Jan-87 12:08:48 by CAJ      

-- This module implements the coroutine which actually performs the cross-mds invokation of Pilot from the Germ, and of the Germ from Pilot.  Other code involved is in INLINEs defined in GermOps.  Please see the comments in GermOps.mesa.

-- The way the cross-mds call is implemented is as follows:  The Germ calls GermOps.InitializeLinkage.  The coroutine InitializeMdsSwitcher is initialized, thus allocating a frame and having its pc be pending on pCrossMdsData.linkage.invokeSystemInMds.  Then a relocated copy of its local and global frame are constructed in a reserved spot in the System Dispatch area in the Germ's mds, and an identical copy built at the same address in Pilot's mds.  Thus when the coroutine switches the mds it is running in, its local frame and global frame still make sense in the destination mds.

DIRECTORY
  Boot USING [pInitialLink],
  BootFile USING [MDSIndex],
  Environment USING [Long],
  Frame USING [
    Free, MyLocalFrame, ReadLocalWord, ReadPC, WritePC, WriteReturnLink],
  FrameExtras USING [MyGlobalFrame, WriteGlobalLink, ReadGlobalLink],
  GermOps USING [
    CrossMdsFrames, fsiMdsSwitcherLocals, GermOpsImplGlobals, 
    GermWorldError, MdsSwitcherLocals, pCrossMdsData, pCrossMdsFrames],
  Inline USING [LongCOPY, LowHalf],
  PilotMP USING [cGermERROR],
  PrincOps USING [LocalFrameHandle, TrapLink],
  PrincOpsExtras2 USING [
    CrossMDSSlot, GFT, GFTHandle, GFTIndexToHandle, GlobalOverhead,
    LongGlobalFrameHandle],
  ProcessOperations USING [ReadMDS, WriteMDS];

GermOpsLinkageImpl: PROGRAM
  IMPORTS Frame, FrameExtras, GermOps, Inline, PrincOpsExtras2, ProcessOperations
  EXPORTS GermOps SHARES GermOps =
  BEGIN
  
  OPEN GermOps;

  -- Check on the validity of things defined in GermOps:
  -- (compiler won't do it there)
  
  -- Check that PORT is properly aligned:
  
  assert1: CARDINAL[2..2] =
    LOOPHOLE[@pCrossMdsData.linkage.portRep, CARDINAL] MOD 4;

  -- Check that local frame is properly aligned:
  assert2: CARDINAL[0..0] =
    LOOPHOLE[@pCrossMdsFrames.localVariables, CARDINAL] MOD 4;

  -- Check that global frame is properly aligned:
  assert3: CARDINAL[0..0] =
    LOOPHOLE[@pCrossMdsFrames.globalVariables, CARDINAL] MOD 4;
  


  -- For simplicity's sake, it is best if this routine has NO GLOBAL VARIABLES.   (Constants are ok.)  This is because InitializeMdsSwitcher uses a relocated copy of our global frame, and, if there are no variables in it, there will be no confusion about which of the copies are being used by which code.  If you need a global, put it in GermOps.pCrossMdsData↑.


  InitializeLinkage: PUBLIC PROCEDURE [mdsOther: BootFile.MDSIndex] =
    -- Sets up GermOps.pCrossMdsData↑ and GermOps.pCrossMdsFrames↑ which are used for Pilot<=>Germ linkage.
    BEGIN
    frameMdsSwitcher: PrincOps.LocalFrameHandle;
      -- original frame of InitializeMdsSwitcher.
    globalFrameCopy: PrincOpsExtras2.LongGlobalFrameHandle =
      LONG[LOOPHOLE[@pCrossMdsFrames.globalVariables]];
      -- copy of local frame of InitializeMdsSwitcher.
    localFrameCopy: PrincOps.LocalFrameHandle =
      LOOPHOLE[@pCrossMdsFrames.localVariables];
      -- copy of global frame of GermOpsImpl.
    -- Set up frame for InitializeMdsSwitcher and make it pending on
    -- awaitSwitchMdsRequest:
    pCrossMdsData.linkage.portRep.dest ←
      [frame[Frame.MyLocalFrame[]]];
        -- temporarily connect awaitSwitchMdsRequest to return to self.
    InitializeMdsSwitcher[];
      -- allocates frame, leaves it pending on awaitSwitchMdsRequest,
      -- and returns here.
    -- Now set up copies of local and global frames in reserved area in our
    -- mds with additional copies copy in other mds:
    frameMdsSwitcher ← pCrossMdsData.linkage.portRep.frame;
    IF Frame.ReadLocalWord[frameMdsSwitcher].fsi ~=
      fsiMdsSwitcherLocals THEN GermOps.GermWorldError[PilotMP.cGermERROR];
    FrameExtras.WriteGlobalLink[
      FrameExtras.ReadGlobalLink[frameMdsSwitcher], localFrameCopy];
    Frame.WritePC[Frame.ReadPC[frameMdsSwitcher], localFrameCopy];
    Frame.WriteReturnLink[
      Inline.LowHalf[LOOPHOLE[PrincOps.TrapLink, LONG UNSPECIFIED]],
      localFrameCopy];
    Frame.Free[frameMdsSwitcher];  -- discard original frame.
    -- Connect awaitSwitchMdsRequest to relocated frame of InitializeMdsSwitcher:
    pCrossMdsData.linkage.portRep.frame ← localFrameCopy;
    -- We don't copy the local variables of InitializeMdsSwitcher since we have
    -- legislated that there are none of any lasting value..
    Inline.LongCOPY[  -- copy global frame..
      from: FrameExtras.MyGlobalFrame[]-SIZE[PrincOpsExtras2.GlobalOverhead],
      nwords: SIZE[PrincOpsExtras2.GlobalOverhead]+SIZE[GermOpsImplGlobals],
      to: globalFrameCopy-SIZE[PrincOpsExtras2.GlobalOverhead]];
    -- Must not set global variables past this point!
    Inline.LongCOPY[
      -- replicate the copies of both local and global frames into other mds..
      from: pCrossMdsFrames, nwords: SIZE[CrossMdsFrames],
      to: LOOPHOLE[Environment.Long[any[high: mdsOther, low: pCrossMdsFrames]]]];
    END;


  InitializeMdsSwitcher: PROCEDURE [] =
    BEGIN
    -- The actual implementation of the mds switching.
    -- The address of this frame must be same in both MDS's; global frames
    -- must be "similar".
    -- Local variables in this procedure have exceedingly transitory scope.
    -- Their values should be irrelevant whenever awaitSwitchMdsRequest is called.
    -- At present there are no local variables (that's good).
    -- The local variables of this procedure must not occupy more space than
    -- SIZE[MdsSwitcherLocals].
    --FOREVER-- DO
      -- Await request to switch mds's.. (implicit argument and result is
      -- pCrossMdsData.mdsOther)
      [] ← pCrossMdsData.linkage.awaitSwitchMdsRequest[];
      -- Remember context of caller in caller's system's entry point
      -- (in caller's mds):
      Boot.pInitialLink.link↑ ← pCrossMdsData.linkage.portRep.dest;
      -- In chronological order, we now:
      --    Read our current mds and put it on the stack;
      --    Copy all other local variables onto the stack (there are none).
      --    Write the mds register with the destination mds.  Notice that we
      --   are now looking at a different copy of pCrossMdsData, our local
      --   variables, and our global variables.
      --    Fix up GFT entry for pCrossMdsFrames.globalVariables. It's a long
      --   pointer and we need to change the high half of it.
      --    Get all other local variables off the stack (there are none).
      --    Get the source mds off the stack and save it in pCrossMdsData.mdsOther
      --   in the destination mds.
      pCrossMdsData.mdsOther ← Save1AndWriteMDS[
        ProcessOperations.ReadMDS[], pCrossMdsData.mdsOther];
      PrincOpsExtras2.GFT[PrincOpsExtras2.GFTIndexToHandle[
        PrincOpsExtras2.CrossMDSSlot]].globalFrame ← 
         LOOPHOLE[LONG[@pCrossMdsFrames.globalVariables]];
      -- Set the destination of awaitSwitchMdsRequest (in the destination mds)
      -- to the destination system's entry point (in destination's mds):
      pCrossMdsData.linkage.portRep.dest ← Boot.pInitialLink.link↑;
      -- Loop back and xfer off to the destination system's entry point..
      ENDLOOP;
    END;

  Save1AndWriteMDS: PROCEDURE [arg1: UNSPECIFIED, mdsi: BootFile.MDSIndex]
    RETURNS [result1: UNSPECIFIED] = LOOPHOLE[ProcessOperations.WriteMDS];
      -- Switches to specified mds while preserving one value on the stack.
      -- The value of result1 is arg1.

  --ShowCodeInMP[111];
  END.


LOG

Dec 18, 1978  9:30 AM   PXM       Created file.
May 3, 1980  10:32 AM   FXH       FrameOps=> Frame, ControlDefs => PrincOps
May 16, 1980  2:20 PM   FXH       Delete Import of BootSwap.
 2-Nov-81 10:44:31   WDK    
   New instruction set.  Make compatible with new Boot, GermOps.  General cleanup.  Module name renamed from BootSwapCross to GermOpsImpl.
 7-Apr-83  9:46:08   WDK        Get rid of implicit system call.
20-Jul-83  9:53:12   AWL         Get rid of implicit system call.
23-Jun-86  9:46:26   MEW	Updated to get global frames out of MDS.
24-Jun-86  8:45:02   MEW	Added update to GFT entry in InitializeMdsSwitcher.
16-Jan-87 12:08:13   CAJ	Incorporate MDS relief changes of previous 2 log entries..