DIRECTORY
BootFile USING [Location, nullLink],
BootStartList USING [Base],
DebuggerFormat USING [ DebugParameter, ExternalStateVector, SwapInfo, SwapReason, VersionID],
DebuggerSwap USING [Frozen, VolumeID],
DeviceCleanup USING [InitializeDeviceCleanup, Perform],
GermSwap USING [GetPStartListHeader, Initialize, InLoad, mdsiGerm, OutLoad, switches--.h, .i, .t--, Teledebug],
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],
TerminalDefs USING [DownUp, KeyBits],
TerminalFace USING [keyboard];
******** Uncaught signals ********
Catcher:
PUBLIC RuntimeError.UCSProc =
{
signallerGF: PrincOps.GlobalFrameHandle;
state: StateVector;
f: PrincOps.FrameHandle;
state.stk[0] ← msg;
state.stk[1] ← LOOPHOLE[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;
};
BackStop:
PROC [root: PrincOps.FrameHandle] =
{
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];
};
StubSignalHandler:
PROC =
-- handles signals before SignalsImpl is available
{
state: RECORD [padding: ARRAY [0..2) OF WORD, v: StateVector];
state.v ← STATE;
DO WorryCallDebugger["Signal too early"L] ENDLOOP;
};
******** 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 ] =
{
Caller: PROC[PrincOps.FrameHandle] = LOOPHOLE[PrincOpsUtils.GetReturnFrame[]];
DummyReturnLink: PROC = {ERROR}; -- PrincOps.NullLink breaks ValidateFrame
PrincOpsUtils.SetReturnLink[LOOPHOLE[DummyReturnLink]];
Caller[FreezingPoint[]];
ERROR
};
FreezingPoint:
PROC
RETURNS[
POINTER
TO local PrincOps.Frame ] =
{
freezeQueue: PrincOps.QueueHandle = @PrincOps.PDA.fault[qFreeze].queue;
state: RECORD[a, b: WORD, v: 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;
};
FreezeTrapFrame:
PROC[sv:
POINTER
TO StateVector] =
{
-- executed with interrupts disabled --
state: RECORD[a, b: WORD, v: 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;
};
******** Initialization ********
Initialize:
PUBLIC
PROC = {
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[];
{
sd: POINTER TO ARRAY NAT OF PROC ANY RETURNS ANY = LOOPHOLE[PrincOps.SD];
sd[PrincOps.sSignalList] ← StubSignalHandler;
sd[PrincOps.sSignal] ← StubSignalHandler;
sd[PrincOps.sErrorList] ← StubSignalHandler;
sd[PrincOps.sError] ← StubSignalHandler;
sd[PrincOps.sReturnErrorList] ← StubSignalHandler;
sd[PrincOps.sReturnError] ← StubSignalHandler;
sd[PrincOps.sUnnamedError] ← StubSignalHandler;
sd[PrincOps.sBreak] ← Break;
sd[PrincOps.sAlternateBreak] ← LOOPHOLE[WorryBreaker[]];
sd[205B] ← LOOPHOLE[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 ←
LOOPHOLE[@FromPilot];
connect ToDebugger to FromPilot
LOOPHOLE[FromPilot, PrincOps.Port].out ←
LOOPHOLE[@ToDebugger];
connect FromPilot to ToDebugger
LOOPHOLE[FromPilot, PrincOps.Port].in ← LOOPHOLE[MemorySwap];
ToDebugger[NIL]; -- allocate frame for MemorySwap
};
NoteDiskDebugger:
PUBLIC
PROC[debugger, debuggee: BootFile.Location] = {
locDebuggee ← debuggee;
locDebugger ← debugger;
IF locDebuggee.diskFileID.firstLink ~= BootFile.nullLink THEN diskDebugger ← TRUE;
};
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: DebuggerSwap.VolumeID] = {
swapInfo.systemVolume ← LOOPHOLE[id];
};
NoteDisplay:
PUBLIC
PROC[bitmap:
LONG
POINTER, w, h:
CARDINAL] = {
swapInfo.display ← bitmap; swapInfo.displayW ← w; swapInfo.displayH ← h;
};