-- 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..