DIRECTORY
BootFile USING [Location, nullLink],
BootStartList USING [Base],
DebuggerFormat USING [ DebugParameter, ExternalStateVector, SwapInfo, SwapReason, VersionID],
DebuggerSwap USING [Frozen],
DebuggerSwapExtra USING [VolumeID],
DeviceCleanup USING [InitializeDeviceCleanup, Perform],
GermSwap USING [GetPStartListHeader, Initialize, InLoad, mdsiGerm, OutLoad, switches--.h, .i, .t--, Teledebug],
KeyboardFace USING [DownUp, keyboard],
Keys USING [KeyBits],
MPCodes USING [cantWorldSwap, emptyMP, hanging],
PrincOps USING [ControlLink, Frame, FrameHandle, FaultIndex, GlobalFrameHandle, NullFrame, NullLink, PageNumber, PDA, Port, Priority, PsbIndex, QueueHandle, sAlternateBreak, sBreak, sBreakBlock, sBreakBlockSize, SD, sError, sErrorList, sReturnError, sReturnErrorList, sSignal, sSignalList, StateVector, sUnnamedError, SVPointer, sXferTrap, XferTrapStatus, zDUP],
PrincOpsUtils USING [ DisableInterrupts, EnableAndRequeue, EnableInterrupts, GetReturnFrame, GetReturnLink, HighHalf, MyLocalFrame, PsbHandleToIndex, PsbIndexToHandle, ReadPSB, ReadPTC, ReadWDC, ReadXTS, SetReturnFrame, SetReturnLink, WritePSB, WritePTC, WriteWDC, WriteXTS],
Process USING [Detach, DisableTimeout, GetPriority, InitializeCondition, InitializeMonitor, Priority, priorityClient3, prioritySwatWatcher, SetPriority],
ProcessorFace USING [BootButton, GetClockPulses, microsecondsPerHundredPulses, SetMP],
RuntimeError USING [UCSProc];
******** Uncaught signals ********
Catcher:
PUBLIC RuntimeError.UCSProc =
BEGIN
signallerGF: PrincOps.GlobalFrameHandle;
state: PrincOps.StateVector;
f: PrincOps.FrameHandle;
state.stk[0] ← msg;
state.stk[1] ← signal;
state.stkptr ← 0;
The call stack below here is: Signaller, [Signaller,] offender
f ← PrincOpsUtils.GetReturnFrame[];
signallerGF ← f.accesslink;
f ← (state.dest ← f.returnlink).frame;
IF f.accesslink = signallerGF THEN state.dest ← f.returnlink;
CoreSwap[uncaughtsignal, @state ! CAbort => GOTO abort];
EXITS
abort =>
IF signal = LOOPHOLE[ABORTED] THEN {BackStop[frame]; ERROR KillThisTurkey}
ELSE ERROR ABORTED;
END;
BackStop:
PROC [root: PrincOps.FrameHandle] =
BEGIN
endProcess: PrincOps.ControlLink = root.returnlink;
Caller: PROC = LOOPHOLE[PrincOpsUtils.GetReturnLink[]];
root.returnlink ← [frame[PrincOpsUtils.MyLocalFrame[]]];
PrincOpsUtils.SetReturnFrame[PrincOps.NullFrame];
Caller[ ! KillThisTurkey => CONTINUE];
PrincOpsUtils.SetReturnLink[endProcess];
END;
StubSignalHandler:
PROC =
-- handles signals before SignalsImpl is available
BEGIN
state: RECORD [padding: ARRAY [0..2) OF UNSPECIFIED, v: PrincOps.StateVector];
state.v ← STATE;
DO WorryCallDebugger["Signal too early"L] ENDLOOP;
END;
******** Data structures for process freezing ********
freezeesTable: PUBLIC DebuggerSwap.Frozen;
freezer: PUBLIC POINTER TO local PrincOps.Frame;
qFreeze: PrincOps.FaultIndex = 3;
AllocFreezer:
PROC
RETURNS[
POINTER
TO local PrincOps.Frame ] =
BEGIN
Caller: PROC[PrincOps.FrameHandle] = LOOPHOLE[PrincOpsUtils.GetReturnFrame[]];
DummyReturnLink: PROC = {ERROR}; -- PrincOps.NullLink breaks ValidateFrame
PrincOpsUtils.SetReturnLink[LOOPHOLE[DummyReturnLink]];
Caller[FreezingPoint[]];
ERROR
END;
FreezingPoint:
PROC
RETURNS[
POINTER
TO local PrincOps.Frame ] =
BEGIN
freezeQueue: PrincOps.QueueHandle = @PrincOps.PDA.fault[qFreeze].queue;
state: RECORD[a, b: UNSPECIFIED, v: PrincOps.StateVector];
Caller: PROC[PrincOps.FrameHandle] = LOOPHOLE[PrincOpsUtils.GetReturnFrame[]];
Caller[PrincOpsUtils.MyLocalFrame[]];
The rest of this procedure is magic. It is simultaneously on the stack of several processes.
PrincOpsUtils.DisableInterrupts[];
DO
state.v ← STATE;
FreezeTrapFrame[@state.v];
PrincOpsUtils.EnableAndRequeue[@PrincOps.PDA.ready, freezeQueue, PrincOpsUtils.ReadPSB[]];
PrincOpsUtils.DisableInterrupts[];
ENDLOOP;
END;
FreezeTrapFrame:
PROC[sv:
POINTER
TO PrincOps.StateVector] =
BEGIN
-- executed with interrupts disabled --
state: RECORD[a, b: UNSPECIFIED, v: PrincOps.StateVector];
Caller: PROC = LOOPHOLE[PrincOpsUtils.GetReturnFrame[]];
psbi: PrincOps.PsbIndex = PrincOpsUtils.PsbHandleToIndex[PrincOpsUtils.ReadPSB[]];
state.v ← sv^;
PrincOpsUtils.SetReturnLink[freezeesTable[psbi]];
freezeesTable[psbi] ← [frame[PrincOpsUtils.MyLocalFrame[]]];
Caller[];
state.v.dest.frame ← PrincOpsUtils.GetReturnFrame[];
state.v.source ← PrincOps.NullLink;
RETURN WITH state.v;
END;
******** Initialization ********
Initialize:
PUBLIC
PROC =
BEGIN
Remember: this module has NOTRAP in its bootmesa description, so the main program is never executed. Therefore, this procedure is responsible for any required initialisation of global variables (like the monitor lock!). In addition, this procedure is called before the mesa runtime has been initialised, so beware of KFCB's or instructions that trap to software.
h: BootStartList.Base;
teledebug ← FALSE;
diskDebugger ← FALSE;
swatWatcherStarted ← FALSE;
swatWatcherEnabled ← FALSE;
level ← -1;
GermSwap.Initialize[GermSwap.mdsiGerm];
Process.InitializeMonitor[@LOCK]; -- because our main program is never executed
DeviceCleanup.InitializeDeviceCleanup[];
h ← GermSwap.GetPStartListHeader[];
pMicrocodeCopy ← pGermCopy ← NIL; -- until microcode swapping installed
NoteDiskDebugger[debugger: h.locDebugger, debuggee: h.locDebuggee];
NoteLoadstate[h[h.initLoadState].base + h[h[h.initLoadState].parent].vmPage];
swapInfo.state set in caller of MemorySwap
(e.g. CoreSwap, WorryBreaker, WorryCallDebugger)
swapInfo.reason set in caller of MemorySwap
(e.g. CoreSwap, WorryBreaker, WorryCallDebugger)
swapInfo.level set in MemorySwap
swapInfo.parameter set by debugger and obeyed by CoreSwap
swapInfo.versionident ← DebuggerFormat.VersionID;
swapInfo.vmRunTable ← NIL;
swapInfo.mds set in MemorySwap
swapInfo.loadState ← NIL;
swapInfo.display ← NIL;
swapInfo.systemVolumeKnown ← FALSE;
LOOPHOLE[PrincOps.
PDA.available, DebuggerFormat.SwapInfo].externalStateVector
← @swapInfo;
InitBreakBlocks[];
PrincOps.SD[PrincOps.sSignalList] ← StubSignalHandler;
PrincOps.SD[PrincOps.sSignal] ← StubSignalHandler;
PrincOps.SD[PrincOps.sErrorList] ← StubSignalHandler;
PrincOps.SD[PrincOps.sError] ← StubSignalHandler;
PrincOps.SD[PrincOps.sReturnErrorList] ← StubSignalHandler;
PrincOps.SD[PrincOps.sReturnError] ← StubSignalHandler;
PrincOps.SD[PrincOps.sUnnamedError] ← StubSignalHandler;
PrincOps.SD[PrincOps.sBreak] ← Break;
PrincOps.SD[PrincOps.sAlternateBreak] ← WorryBreaker[];
PrincOps.SD[205B] ← freezer ← AllocFreezer[];
LOOPHOLE[@(PrincOps.SD[206B]), POINTER TO LONG POINTER TO DebuggerSwap.Frozen]^ ←
LONG[@freezeesTable];
FOR p: PrincOps.PsbIndex IN PrincOps.PsbIndex
DO freezeesTable[p] ← PrincOps.NullLink ENDLOOP;
WorryCallDebugger ← DoWorryCallDebugger[];
LOOPHOLE[ToDebugger, PrincOps.Port].out ← @FromPilot;
connect ToDebugger to FromPilot
LOOPHOLE[FromPilot, PrincOps.Port].out ← @ToDebugger;
connect FromPilot to ToDebugger
LOOPHOLE[FromPilot, PrincOps.Port].in ← MemorySwap;
ToDebugger[NIL]; -- allocate frame for MemorySwap
END;
NoteDiskDebugger:
PUBLIC
PROC[debugger, debuggee: BootFile.Location] =
BEGIN
locDebuggee ← debuggee;
locDebugger ← debugger;
IF locDebuggee.diskFileID.firstLink ~= BootFile.nullLink THEN diskDebugger ← TRUE;
END;
NoteLoadstate:
PUBLIC
PROC[page: PrincOps.PageNumber] =
{ swapInfo.loadstatepage ← page };
NoteVMRunTable:
PUBLIC
PROC[table:
LONG
POINTER] =
{ swapInfo.vmRunTable ← table };
NoteRealLoadState:
PUBLIC
PROC[loadState:
LONG
POINTER] =
{ swapInfo.loadState ← loadState };
NoteSystemVolume:
PUBLIC
PROC[id: DebuggerSwapExtra.VolumeID] =
{ swapInfo.systemVolume ← LOOPHOLE[id] };
NoteDisplay:
PUBLIC
PROC[bitmap:
LONG
POINTER, w, h:
CARDINAL] =
{ swapInfo.display ← bitmap; swapInfo.displayW ← w; swapInfo.displayH ← h };