All:
PROC = {
area: Area = GetCurrentArea[];
These labels are for trap procedures.
IFUStackOverflow: Label = GenLabel[];
Overflow: Label = GenLabel[];
BoundsCheck: Label = GenLabel[];
LispNaN: Label = GenLabel[];
UserModeViolation: Label = GenLabel[];
EUPageFlt: Label = GenLabel[];
EUPageFaultBad: Label = GenLabel[];
EUWPFlt: Label = GenLabel[];
EUWPFaultBad: Label = GenLabel[];
IFUPageFault: Label = GenLabel[];
IFUPageFaultBad: Label = GenLabel[];
IFUPageFaultPC: LONG CARDINAL = 300000000B;
EUPageFaultAddress: LONG CARDINAL = IFUPageFaultPC/4;
EUStackOverflow: Label = GenLabel[];
Reschedule: Label = GenLabel[];
RescheduleBad: Label = GenLabel[];
KFCTrap: Label = GenLabel[];
KFCBad: Label = GenLabel[];
Xop1Trap: Label = GenLabel[];
Xop1Bad: Label = GenLabel[];
Xop2Trap: Label = GenLabel[];
Xop2Bug: Label = GenLabel[];
Xop3Trap: Label = GenLabel[];
Xop3Bug: Label = GenLabel[];
Xop5Trap: Label = GenLabel[];
Xop5Bug: Label = GenLabel[];
ErrorXop1Trap: Label = GenLabel[];
AlreadyInKernel: Label = GenLabel[];
TurnOnTraps: Label = GenLabel[];
TurnOffTraps: Label = GenLabel[];
TurnOnUserMode: Label = GenLabel[];
enterIFUStatusTest: Label = GenLabel[];
enterIFUStackOverflowTest: Label = GenLabel[];
enterSLimitTest: Label = GenLabel[];
enterIFUPageFaultTest: Label = GenLabel[];
enterEUPageFaultTest: Label = GenLabel[];
enterModeFaultPriorityTest: Label = GenLabel[];
Lizard only permits addresses >= DragOpsCross.KernelLimit = 100000000B to be written in user mode; the Softcard only permits addresses in [1,000,000B..2,000,000B) to be referenced.
userMemAddr: LONG CARDINAL = IF withSoftCard THEN 1770000B ELSE 100000000B;
kernelMemAddr: LONG CARDINAL = IF withSoftCard THEN 17760000B ELSE 77777777B;
All traps enter kernel mode and disable traps; disabling affects only Reschedule, EU stack overflow, and IFU stack overflow.
When traps are enabled, the IFU stack allows 11 normal calls but converts the 12th call into an IFU stack overflow trap; when traps are disabled, all 15 levels of the IFU stack are usable. Note, however, that when a trap or KFC is the 12th call, it will complete and disable traps without causing an IFU stack overflow trap. There is no IFU stack underflow trap; the first location in the IFU stack must be made to contain a return link to an appropriate trap procedure (or use the trick of causing a page fault).
When traps are enabled, any opcode causing S to wind up in the range [SLimit..SLimit+16) causes an EU stack overflow trap; this detects both underflows and overflows, though underflow can only happen due to a programming error.
Xops and KFC trap at opcode*TrapWidthBytes + xopBase*bytesPerWord = 4,000,000B + 20B * opcode.
FillXop:
PROC [inst:
CARDINAL, dest: Label] = {
SetOutputPC[inst * DragOpsCross.TrapWidthBytes + DragOpsCross.XopBase * bytesPerWord];
drJDB[UseLabel16[dest]];
};
A trap's location is TrapIndex*TrapWidthBytes + TrapBase*bytesPerWord =
4,002,000B + 20B * TrapIndex. TrapIndex definitions are in DragOpsCross.
FillTrap:
PROC [tx: DragOpsCross.TrapIndex, dest: Label] = {
SetOutputPC[LOOPHOLE[tx, CARDINAL] * DragOpsCross.TrapWidthBytes + DragOpsCross.TrapBase * bytesPerWord];
drJDB[UseLabel16[dest]];
};
Procedures to enable and disable traps in the caller's context; must be in Kernel mode.
EnableTraps: PROC [] = { drDFC[UseLabel32[TurnOnTraps]]; };
DisableTraps: PROC [] = { drDFC[UseLabel32[TurnOffTraps]]; };
EnterUser: PROC [] = { drDFC[UseLabel32[TurnOnUserMode]]; };
Indicate KFC trap expected by loading 12 into aux8
EnterKernel: PROC [] = { drLIB[12]; drROR[aux8, popSrc, topSrc]; drKFC[]; drROR[aux8, const0, const0]; };
16 bytes between consecutive trap instructions is insufficient for StandardTrap, so the trap instruction must be filled separately with FillTrap[TrapName, dest]. aux8 has previously been loaded with a code for the trap presently expected (or 0 if none), and an opcode which is supposed to trap is followed by enough XPause[] opcodes to fill out 6 bytes (i.e., enough for a 5-byte trapping opcode and a 1-byte XPause[] after it); then if no trap occurs, the first XPause[] after the opcode will stop simulation; or if the wrong trap occurs, the mismatch on aux8 will cause XPause[] to occur. Otherwise, the trap procedure will return to the 6th byte after the location that trapped.
StandardTrap:
PROC [dest: Label, code:
CARDINAL] = {
TrapUnexpected: Label = GenLabel[];
SetLabel[dest];
drLIB[code];
drRJNEB[popSrc, aux8, UseLabel8B[TrapUnexpected]];
Advance return PC by 6
GetYoungestPC[]; drRVADD[topDst, const4, topSrc]; SetYoungestPC[];
drRETN[];
SetLabel[TrapUnexpected]; Pause[];
};
Write 0 into storage at the address addr.
WriteAtAddress:
PROC [addr:
LONG
CARDINAL] ~ {
Make the location addr known to Lizard.
oldPC: LONG CARDINAL = GetOutputPC[area];
bytePC: LONG CARDINAL ← Basics.DoubleShiftLeft[[lc[addr]], 2].lc;
SetOutputPC[bytePC]; --pc is a byte address
OutputWord[area, IntToWord[-1], FALSE];
SetOutputPC[oldPC];
drLC0[]; drLIQB[CardToWord[addr]]; drWB[0];
};
Write 0 into storage at the address addr which should cause an Address Check trap.
WriteTrapAtAddress:
PROC [addr:
LONG
CARDINAL] ~ {
WriteAtAddress[addr];
XPause[]; XPause[]; XPause[]; XPause[];
};
StackedStatusWord: TYPE = MACHINE DEPENDENT RECORD [
version (0:00..07): [0..255] ← 0,
pad (0:08..13) [0..63] ← 0,
userMode (0:14..14) BOOL ← FALSE (True = kernel mode),
trapsEnabled (0:15..15): BOOL ← FALSE,
pad (1:00..07) [0..255] ← 0,
lBase (1:08..15) [0..255] ← 0 ];
User mode can be enabled by changing the user mode bit in the stacked status word and then doing a RET. In user mode, the following actions are illegal:
1) Any write of a constant or aux0 to aux7 causes a mode fault trap.
2) All SIPs, and LIP[IFUEldestPC] (an active operation) cause a mode fault trap.
3) IODA, IOD, and ION pass a device number in Beta for which the low-order bit is 0 (PRead) or 1 (PWrite) and for which the next two low-order bits serve both as a device number and for user mode checking purposes as follows:
Beta[4B] = 1 means "kernel mode required"; the IO operation will get
a ModeFault trap if it is executed in user mode.
Beta[2B] = 1 means "address check"; the instruction will cause an
AddressCheck trap on a Kernel address.
Once in user mode, kernel mode can be reentered only by executing a KFC or trapping.
GenIFUStatus:
PROC [] ~ {
UCall1: Label = GenLabel[];
UCall2: Label = GenLabel[];
UJump1: Label = GenLabel[];
JQBNop0: Label = GenLabel[];
JSDNop0: Label = GenLabel[];
BeginUserTest: Label = GenLabel[];
CheckTrapEnable: Label = GenLabel[];
CheckTrapDisable: Label = GenLabel[];
CheckUserMode: Label = GenLabel[];
BadEnable: Label = GenLabel[];
SetLabel[enterIFUStatusTest];
Initialize aux0 here before entering user mode because it cannot be written in user mode and must point at a valid memory address when the LGF opcode is tested in user mode.
drLIQB[CardToWord[userMemAddr]]; drROR[aux0, topSrc, popSrc];
drJDB[UseLabel16[BeginUserTest]]; --inst 50
SetLabel[CheckTrapEnable];
GetYoungestStatus[]; drLIQB[CardToWord[200000B]]; drOR[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[BadEnable]; XPause[];
SetLabel[CheckTrapDisable];
GetYoungestStatus[]; drLIQB[CardToWord[37777577777B]]; drAND[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[CheckUserMode];
GetYoungestStatus[]; drLIQB[CardToWord[400000B]]; drOR[];
drDUP[]; SetYoungestStatus[]; --Set trapsEnabled
drLIP[ifuYoungestL]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadEnable]];
drRETN[];
SetLabel[BeginUserTest];
Check trap enabling and disabling and user mode enabling (must call a subroutine).
drLFC[UseLabel16[CheckTrapEnable]];
drLFC[UseLabel16[CheckTrapDisable]];
drLFC[UseLabel16[CheckUserMode]];
Reference all registers that can legally be read and written in user mode.
drROR[aux9, aux0, aux1];
drROR[aux9, aux2, aux3];
drROR[aux10, aux4, aux5];
drROR[aux11, aux6, aux7];
drROR[aux12, aux8, aux9];
drROR[aux13, aux10, aux11];
drROR[aux14, aux12, aux13];
drROR[aux15, aux14, aux14];
drROR[aux15, aux15, aux15];
drROR[pushDst, const0, const1]; --1st push
drROR[topDst, const2, const3];
drROR[pushDst, const4, const5]; --2nd push
drROR[belowDst, const6, const7];
drROR[topDst, const8, const9];
drROR[topDst, const10, const11];
drLIP[0]; --3rd push
drLIP[127]; --4th push
drLIP[159]; --5th push
The call stack must be at least 1 deep for the ifu LIP operations to yield defined values.
drLFC[3];
drLIP[ifuYoungestL]; --6th push
drLIP[ifuYoungestPC]; --7th push
drLIP[ifuEldestL]; --8th push
drLIP[ifuSLimit]; --9th push
drASL[377B]; --0 pushes on the EU stack, 1 call on the IFU stack
WriteAtAddress[userMemAddr];
***FIXES NEEDED HERE. IODA[2B] does [S] ← PRead[0 + [S], BetaZ].
--drLIQB[CardToWord[userMemAddr]]; drIODA[2B];
drASL[377B]; --0 pushes again
Now execute all instructions legal in user mode (LRn, SRn, LRIn, SRIn, and LCn each treated as a single instruction).
drLC0[]; drDUP[]; drADD[]; --1st push = reg0
drLC1[]; --2 pushes
drLIDB[0]; drLIQB[CardToWord[0]]; --4 pushes
drLRn[reg11]; --5 pushes
drQADD[topAtop, const0];
drRADD[belowDst, topSrc, belowSrcPop]; --4 pushes
drSUB[]; --3 pushes
drQSUB[topAtop, const0];
drRSUB[belowDst, popSrc, belowSrc]; --2 pushes
drQLADD[topAtop, const0];
drRLADD[belowDst, popSrc, const0]; --1 push
drQLSUB[topAtop, const0]; --1 push
drRLSUB[pushDst, popSrc, const0];
drRUADD[belowDst, const0, popSrc]; --0 pushes
drRUSUB[pushDst, const0, const0]; --1 push
drRVADD[pushDst, const0, topSrc]; --2 pushes
drRVSUB[topDst, topSrc, const0];
drAND[]; --1 push
drQAND[pushAtop, const0]; --2 pushes
drRAND[topDst, topSrc, topSrc];
drOR[]; --1 push
drQOR[pushAtop, const0]; --2 pushes
drADDB[0];
drSUBB[0];
drADDDB[0];
drSUBDB[0];
drADDQB[CardToWord[0]];
drSUBQB[CardToWord[0]];
drRXOR[topDst, topSrc, topSrc];
drRAND[topDst, topSrc, const0]; --Zero [S]
drFSDB[FieldDescriptorToCard[[mask: 6, shift: 20]]]; --1 push
drRFU[pushDst, topSrc, topSrc]; --2 pushes
drSHDL[FieldDescriptorToCard[[mask: 32, shift: 0]]]; --1 push
drSHL[FieldDescriptorToCard[[mask: 0, shift: 32]]]; --1 push
drSHR[FieldDescriptorToCard[[mask: 16, shift: 16]]]; --1 push
drJ1[];
drJ2[]; XPause[];
drJ3[]; XPause[]; XPause[];
drJ5[]; XPause[]; XPause[]; XPause[]; XPause[];
drJDB[3];
drJQB[UseLabel32[JQBNop0]]; SetLabel[JQBNop0];
drLIQB[UseLabel32[JSDNop0]]; drJSD[]; SetLabel[JSDNop0];
drEXDIS[]; --0 pushes
drLIDB[0]; --1 push
drASL[377B]; --0 pushes, 0 locals (S ← 0B, L = 1B)
drAL[0];
drLIQB[CardToWord[userMemAddr]]; --legal address already used, 1 push
FOR I: CARDINAL IN [0..17) DO drDUP[]; ENDLOOP;
drSRn[reg0]; --Now have L = 1B, S = 21B (= 16 locals, 1 push)
drLRIn[reg0, 0]; drSRIn[reg0, 0];
drDUP[]; drJEBB[0, 3];
drDUP[]; drJNEBB[0, 3];
drDUP[]; drJNEBBJ[0, 3];
drRJEB[topSrc, topSrc, 3];
drRJEBJ[topSrc, topSrc, 3];
drRJGB[topSrc, topSrc, 3];
drRJGBJ[topSrc, topSrc, 3];
drRJLB[topSrc, topSrc, 3];
drRJLBJ[topSrc, topSrc, 3];
drRJGEB[topSrc, topSrc, 3];
drRJGEBJ[topSrc, topSrc, 3];
drRJLEB[topSrc, topSrc, 3];
drRJLEBJ[topSrc, topSrc, 3];
drRJNEB[topSrc, topSrc, 3];
drRJNEBJ[topSrc, topSrc, 3]; --Still have 1 push (L = 1B, S = 21B)
drLIQB[CardToWord[userMemAddr - 1]]; --2 pushes
drRBC[topDst, topSrc, belowSrc]; --won't trap
drQBC[topAtop, belowSrc]; --won't trap
drDIS[]; drLIQB[CardToWord[userMemAddr + 1]];
drBC[]; --1 push
drDUP[]; --2 pushes
drLC0[]; drRX[]; drDIS[]; --1 push
drQRX[pushAtop, const0]; drDIS[];
drLGF[0]; drDIS[]; --(aux0 was initialized to userMemAddr above)
drRAI[reg1, aux0, 0];
drDUP[]; drRB[0]; drDIS[];
drRRI[reg1, reg13, 0]; --(reg0 .. reg15 were set to userMemAddr above)
drRRX[reg1, reg13, const0];
drRSB[0]; drDIS[];
drWAI[reg1, aux0, 0];
drWRI[reg1, reg13, 0];
drLC0[]; drWSB[0]; --Still have 1 push
IF NOT withSoftCard THEN { drLIB[1]; drLC0[]; drCST[0]; };
drASL[377B]; --0 pushes
drLIB[1]; drJSR[];
drDFC[UseLabel32[UCall1]];
drLFC[UseLabel16[UCall2]];
drLIB[13]; drROR[aux8, topSrc, popSrc]; --Indicate XOP1 trap expected
OutputByte[area, CardToByte[1B]];
drLIB[14]; drROR[aux8, topSrc, popSrc]; --Indicate XOP2 trap expected
OutputAlphaBeta[area, (234B * 400B) + 123B];
drLIB[15]; drROR[aux8, topSrc, popSrc]; --Indicate XOP3 trap expected
OutputByte[area, CardToByte[364B]]; OutputAlphaBeta[area, 234B];
drLIB[16]; drROR[aux8, topSrc, popSrc]; --Indicate XOP5 trap expected
OutputByte[area, CardToByte[40B]]; OutputWord[area, CardToWord[345B]];
EnterKernel[]; --KFC trap returns in Kernel mode with traps disabled.
EnterUser[]; --Enter user mode and enable traps
drLIQB[CardToWord[userMemAddr]]; --1 push
drLIQB[UseLabel32[UCall1]]; --2 pushes
drPSB[0]; --1 push
drAS[1]; --2 pushes
drSFC[]; --1 push
drSFCI[];
drJB[UseLabel8A[UJump1]];
SetLabel[UCall1];
drRETN[];
SetLabel[UCall2];
drALS[377B]; --L ← S-1
drRET[1B]; --S ← L+1
SetLabel[UJump1];
drASL[17B]; --16 local registers, 0 EU pushes, 1 call on the IFU stack
Reference all registers illegal in user mode.
drLIB[8]; --1 push
drROR[aux8, topSrc, topSrc]; --Indicate mode fault trap expected (aux8 = 8)
aux0 to aux7 and const0 to const11 are read-only in user mode.
drROR[aux0, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux2, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux3, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux4, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux5, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux6, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[aux7, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const0, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const2, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const3, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const4, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const5, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const6, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const7, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const8, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const9, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const10, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
drROR[const11, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
Execute all instructions illegal in user mode.
Representative SIP instructions.
drSIP[0]; XPause[]; XPause[]; XPause[]; XPause[];
drSIP[242]; XPause[]; XPause[]; XPause[]; XPause[];
drSIP[246]; XPause[]; XPause[]; XPause[]; XPause[];
LIP[IFUEldestPC] is illegal in user mode because it modifies the call stack.
drLIP[ifuEldestPC]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; --16 locals, 1 push, 2 calls on the IFU stack
IOD, ION, and IODA are legal or illegal in user mode according to the device which is selected.
--drIOD[4B]; XPause[]; XPause[]; XPause[];
--drION[4B]; XPause[]; XPause[]; XPause[];
--drIODA[4B]; XPause[]; XPause[]; XPause[];
Now try a write reference to a Kernel page, which should trap.
--WriteTrapAtAddress[kernelMemAddr];
Remove the 2 calls from the stack
drASL[17B]; --16 locals, 0 pushes on the EU stack, 2 calls on the IFU stack, user mode
EnterKernel[]; --Use KFC to enter kernel mode and return with traps disabled.
FOR I: CARDINAL IN [0..0] DO GetEldestPC[]; ENDLOOP;
};
Test conditions which should and should not cause IFU stack overflow trap. Begin here in Kernel mode with traps disabled, and 0 IFU call stack entries.
GenIFUStackOverflow:
PROC [] ~ {
UCall3: Label = GenLabel[];
JQBNop1: Label = GenLabel[];
JSDNop1: Label = GenLabel[];
exitIFUStackOverflowTest: Label = GenLabel[];
eleventhCall: Label = GenLabel[];
drJB[UseLabel8A[enterIFUStackOverflowTest]];
SetLabel[UCall3];
XPause[]; --DFC, SFC, or SFCI trap was expected but didn't.
SetLabel[enterIFUStackOverflowTest];
drASL[377B]; --0 locals, 0 pushes on the EU stack, 0 calls on the IFU stack
EnableTraps[];
Now in Kernel mode with traps enabled.
drLFC[3]; --1 calls
drLFC[3]; --2 calls
drLFC[3]; --3 calls
drLFC[3]; --4 calls
drLFC[3]; --5 calls
drLFC[3]; --6 calls
drLFC[3]; --7 calls
drLFC[3]; --8 calls
drLFC[3]; --9 calls
drLFC[3]; --10 calls
drLFC[4]; --11 calls
XPause[];
Now in Kernel mode with traps enabled and 11 calls on the stack; the following opcodes shouldn't cause IFU stack overflow trap.
drJ1[];
drJ2[]; XPause[];
drJ3[]; XPause[]; XPause[];
drJ5[]; XPause[]; XPause[]; XPause[]; XPause[];
drJB[2];
drJDB[3];
drJQB[UseLabel32[JQBNop1]]; XPause[]; SetLabel[JQBNop1];
drLIQB[UseLabel32[JSDNop1]]; drJSD[]; XPause[]; SetLabel[JSDNop1];
drLIB[1]; drJSR[];
RBC, QBC, and BC should not cause IFU stack overflow when they don't trap.
drLIB[2]; drLIB[1]; drQBC[pushAtop, belowSrc]; drDIS[];
drRBC[pushDst, reg1, reg0]; drDIS[];
drEXDIS[]; drLIB[2]; drBC[];
drLIB[1]; drROR[aux8, popSrc, topSrc]; --Indicate IFU stack overflow expected
Each of the following instructions does a 12th call which should go through the IFU stack overflow trap and skip the XPause[]'s after the call.
drLFC[3]; XPause[]; XPause[]; XPause[];
drDFC[UseLabel32[UCall3]]; XPause[];
drLIQB[UseLabel32[UCall3]]; drSFC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
1, 2, 3, and 5-byte Xops should cause IFU stack overflow trap
OutputByte[area, CardToByte[1B]];
XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
OutputAlphaBeta[area, (234B * 400B) + 123B];
XPause[]; XPause[]; XPause[]; XPause[];
OutputByte[area, CardToByte[364B]]; OutputAlphaBeta[area, 234B];
XPause[]; XPause[]; XPause[];
OutputByte[area, CardToByte[40B]]; OutputWord[area, CardToWord[345B]];
XPause[];
drKFC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
RBC, QBC, or BC should cause IFU stack overflow when they trap.
drLIB[1]; drLIB[2];
drQBC[pushAtop, belowSrc]; XPause[]; XPause[]; XPause[]; XPause[];
drRBC[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
drEXDIS[]; drLIB[1];
drBC[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
NaN trap causing stack overflow should get IFU stack overflow trap.
drLIQB[CardToWord[10000000000B]]; drDUP[];
drLADD[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
ADD that Overflows should get IFU stack overflow trap.
drADD[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
EU page fault.
drLIQB[CardToWord[EUPageFaultAddress]];
drROR[aux9, topSrc, topSrc];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
Push that gets EU stack overflow
drASL[17B]; --L = 1, S = 20B
drLIB[21B]; drSIP[ifuSLimit];
drDUP[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; drLIB[160B]; drSIP[ifuSLimit];
drROR[aux8, const0, const0]; --Indicate no traps expected
GetEldestPC[]; --Clear 1 call to enter user mode
EnterUser[];
drLFC[UseLabel16[eleventhCall]]; --11 calls again
Return here reducing call stack depth by 1 so KFC can get out of user mode.
drJDB[UseLabel16[exitIFUStackOverflowTest]]; --10 calls
SetLabel[eleventhCall];
drLIB[1]; drROR[aux8, topSrc, popSrc]; --Indicate IFU stack overflow expected
User mode RADD that gets mode fault.
drRADD[const1, const0, const0]; XPause[]; XPause[]; XPause[];
User mode store that gets address check
--****drLC0[]; drWB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drROR[aux8, const0, const0]; --Indicate no traps expected
drRET[377B]; --returns from 11th call and trims stack
SetLabel[exitIFUStackOverflowTest];
EnterKernel[];
Remove the 10 calls from the stack and cleanup
FOR I: CARDINAL IN [0..9] DO GetEldestPC[]; ENDLOOP;
drASL[17B]; --L = 1, S = 20B, traps enabled, Kernel mode, 0 calls on the stack
};
GenSLimit:
PROC [] ~ {
S = L = 0 here and aux15 must contain 9 (the code for EU stack overflow trap expected); SL is the value of SLimit to be tested for ASL[SL-1], ASL[SL + 16], ASL[SL], and ASL[SL + 15]. Note that S is left equal to 0. SLimitTest executes about 15 instructions.
SLimitTest:
PROC [
SL:
CARDINAL] ~ {
drLIB[SL]; drSIP[ifuSLimit];
drROR[aux8, aux15, aux15];
drASL[SL]; XPause[]; XPause[]; XPause[]; XPause[]; --SLimit
drASL[SL + 15]; XPause[]; XPause[]; XPause[]; XPause[]; --SLimit + 15
drROR[aux8, const0, const0];
drASL[SL + 16]; --SLimit + 16
drASL[SL - 1]; --SLimit - 1
drASL[0]; --SLimit
};
For one value of SLimit, verify that EU stack overflow trap occurs when traps are enabled and an instruction would put S in [SLimit .. SLimit + 16) for several opcodes that push and pop the stack and for AS[n], ASL[n], and RET[n]. Also verify that the trap occurs when S is already in the restricted range when traps are reenabled.
SetLabel[enterSLimitTest];
drASL[7B]; --L = 1, S = 10B, traps enabled, Kernel mode, 0 calls on the stack
EnableTraps[];
drLIB[13B]; drSIP[ifuSLimit];
drLIQB[CardToWord[userMemAddr]]; drSRn[reg0]; --Memory address for LRIn below
drLC0[]; --S = 11B
drLIB[9]; drROR[aux8, topSrc, topSrc]; --aux8 ← EU stk ovf trap expected
drROR[aux15, topSrc, popSrc]; --aux15 ← EU stk ovf trap expected for SLimitTests below
drDUP[]; --S = 12B
Create one call stack entry so that RET below has a defined return; perhaps this is not strictly necessary because these instructions trap, but Lizard is picky.
drLFC[4]; XPause[];
Should get EU stack overflow trap on these typical instructions
drDUP[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drLRn[reg2]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drQADD[pushA0, const0]; XPause[]; XPause[]; XPause[]; XPause[];
drRADD[pushDst, const0, const0]; XPause[]; XPause[]; XPause[];
drLRIn[reg0, 0]; XPause[]; XPause[]; XPause[]; XPause[];
Lizard gave a "VERY suspicious S adjustment" crash for alpha >= 40B in this test, so I changed the code to have fewer locals.
FOR I:
CARDINAL
IN [1..16]
DO
drAS[I]; XPause[]; XPause[]; XPause[]; XPause[];
drASL[11B + I]; XPause[]; XPause[]; XPause[]; XPause[];
drRET[11B + I]; XPause[]; XPause[]; XPause[]; XPause[];
ENDLOOP;
Now check for popping that puts S in the restricted range.
drASL[377B]; --S = 0, L = 1 (won't trap)
drLIB[160B]; drSIP[ifuSLimit]; --S in [160B..177B] will trap
drLIP[ifuEldestPC]; drDIS[]; --clear the call stack
drSRn[reg15]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drQAND[topAtop, popSrc]; XPause[]; XPause[]; XPause[]; XPause[];
drRAND[belowDst, topSrc, popSrc]; XPause[]; XPause[]; XPause[];
drSRIn[reg0, 0]; XPause[]; XPause[]; XPause[]; XPause[];
drDIS[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
For SLimit = 4B, 10B, 20B, 1B, 40B, 100B, 2B, and 157B verify that an EU stack overflow trap does not occur when ASL[n] makes S equal to SLimit - 1 or SLimit + 16 and does occur when ASL[n] makes S equal to SLimit or SLimit + 15.
drROR[aux8, const0, const0]; --Indicate no trap expected
drAL[377B]; --L ← 0
L = 0, S = 0, 0 call stack entries, SLimit = 160B, no trap expected. Since S is left 0 by SLimitTest, none of the args to SLimitTest may be in [161B..0B].
SLimitTest[4B];
SLimitTest[10B];
SLimitTest[20B];
SLimitTest[1B];
drASL[377B];
SLimitTest[40B];
SLimitTest[100B];
SLimitTest[2B];
SLimitTest[157B];
Verify that EU stack overflow is lower priority than all other traps.
drLIB[21B]; drSIP[ifuSLimit];
drAL[1B]; --L = 1 again
drASL[15B]; --S = 16B
drLIB[6]; drROR[aux8, topSrc, popSrc]; --Bounds check should prevail
drLIB[1]; drLIB[2]; --S = 20B (1 less than SLimit)
drQBC[pushAtop, belowSrc]; XPause[]; XPause[]; XPause[]; XPause[];
drRBC[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
NaN should prevail; this is a particularly rough test because RLADD would have decremented S if it hadn't trapped and because Overflow is happening as well as NaN.
drAS[376B]; drLIB[7]; drROR[aux8, topSrc, popSrc]; --NaN prevails
drLIQB[CardToWord[10000000000B]]; drDUP[]; --S = 20B (1 less than SLimit)
drRLADD[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
drDIS[]; drLIB[5]; drROR[aux8, topSrc, popSrc]; --Overflow prevails
drDUP[]; --S = 20B (1 less than SLimit)
drRADD[pushDst, topSrc, belowSrc]; XPause[]; XPause[]; XPause[];
****Address check isn't implemented any more.
--drAS[376B]; EnterUser[]; drDUP[];
--drLIB[4]; drROR[aux8, topSrc, popSrc];
--drLC0[]; drWB[0]; XPause[]; XPause[]; XPause[]; XPause[];
****Used to test that Reschedule won out over EUStackOverflow here.
Test that ModeFault prevails over EUStackOVerflow when writing an illegal register occurs at the same time as popping into the restricted range.
drASL[377B]; --S = 0, L = 1 (won't trap)
drLIB[160B]; drSIP[ifuSLimit]; --S in [160B..177B] will trap
drLIB[8]; drROR[aux8, topSrc, topSrc]; --Indicate ModeFault expected
EnterUser[];
drRADD[const1, popSrc, topSrc]; XPause[]; XPause[]; XPause[];
EnterKernel[]; --Enter Kernel mode and disable traps
drASL[17B]; --L = 1, S = 20B, traps disabled, Kernel mode, 0 calls on the stack
};
Verify that IFU page fault occurs in sequence when jumping, calling, returning, conditionally jumping (correctly or incorrectly predicted), or falling through into an undeclared page.
GenIFUPageFault:
PROC [] ~ {
oldPC: LONG CARDINAL;
LFCFaultOK: Label = GenLabel[];
RETNFaultOK: Label = GenLabel[];
CJumpFOK0: Label = GenLabel[];
CJumpFOK1: Label = GenLabel[];
FallThruOK: Label = GenLabel[];
endIFUPFTest: Label = GenLabel[];
nearFaultPagePC0: LONG CARDINAL = 277777600B;
nearFaultPagePC1: LONG CARDINAL = 310007600B;
IFUPageFaultPC1: LONG CARDINAL = 310010000B;
nearFaultPagePC2: LONG CARDINAL = 320007775B; --Must be page boundary - 3
SetLabel[enterIFUPageFaultTest];
drASL[377B]; --L = 1, S = 0
EnableTraps[];
drLIQB[CardToWord[nearFaultPagePC0]]; --location to which page fault trap returns
drLIB[10]; drROR[aux8, popSrc, topSrc]; --IFU page fault expected
drJQB[CardToWord[IFUPageFaultPC]]; --Will cause IFU page fault
oldPC ← GetOutputPC[area];
SetOutputPC[nearFaultPagePC0];
drLIQB[UseLabel32[LFCFaultOK]];
drLFC[IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[LFCFaultOK];
drLIQB[CardToWord[IFUPageFaultPC]];
SetYoungestPC[];
drLIQB[UseLabel32[RETNFaultOK]];
drRETN[]; --Will cause IFU page fault
SetLabel[RETNFaultOK];
drLIQB[UseLabel32[CJumpFOK0]];
drRJEB[const0, const0, IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[CJumpFOK0];
drLIQB[UseLabel32[CJumpFOK1]];
drRJEBJ[const0, const0, IFUPageFaultPC - GetOutputPC[area]]; --IFU page fault next
SetLabel[CJumpFOK1];
drLIQB[UseLabel32[FallThruOK]];
drJB[IFUPageFaultPC - GetOutputPC[area] - 1];
SetOutputPC[IFUPageFaultPC - 1];
drJ1[]; --Next instruction causes IFU page fault
SetOutputPC[nearFaultPagePC1];
SetLabel[FallThruOK];
Verify that IFU page fault does not occur when the untaken path of a conditional jump or conditional trap lies in an undeclared page.
drROR[aux8, const0, const0]; --Indicate no traps expected
predicted non-jump; jump would fault; doesn't jump; test that no fault occurs.
drRJNEB[const0, const0, IFUPageFaultPC1 - GetOutputPC[area]];
predicted jump; jump would fault; doesn't jump; test that no fault occurs.
drRJNEBJ[const0, const0, IFUPageFaultPC1 - GetOutputPC[area]];
drJB[IFUPageFaultPC1 - GetOutputPC[area] - 3]; SetOutputPC[IFUPageFaultPC1 - 3];
predicted non-jump; fall-through would fault; jumps; test that no fault occurs.
drRJEB[const0, const0, 370B];
SetOutputPC[IFUPageFaultPC1 - 3 - 10B];
drJQB[CardToWord[nearFaultPagePC2]]; SetOutputPC[nearFaultPagePC2];
predicted jump; fall-through would fault; jumps; test that no fault occurs.
drRJEBJ[const0, const0, 370B];
SetOutputPC[nearFaultPagePC2 - 10B];
drJQB[CardToWord[oldPC]];
SetOutputPC[oldPC];
**Should test EU stack overflow coincident with IFU page fault.
};
Verify that EU page fault occurs in sequence and that machine state which would have been affected by the faulting instruction is not modified on storage read, storage write, CST read-write, SFCI read, IODA read, and IODA write; verify that euMAR contains the fault address. No current instructions which are storage writes modify any EU registers; only S is modified, so verify that on a storage write S is not changed; reads modify both S and some destination register.
GenEUPageFault:
PROC [] ~ {
OKState: Label = GenLabel[];
BadState: Label = GenLabel[];
SetLabel[enterEUPageFaultTest];
drASL[377B]; --L = 1, S = 0
EnableTraps[];
drLIB[2]; drROR[aux8, popSrc, topSrc]; --EU page fault expected
Verify that EU stack overflow is lower priority than EU page fault.
drLIB[21B]; drSIP[ifuSLimit];
drASL[16B]; --S = 17B
drLIQB[CardToWord[EUPageFaultAddress]];
drROR[aux9, topSrc, topSrc];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drASL[377B]; --L = 1, S = 0
drLIQB[CardToWord[EUPageFaultAddress]];
drRB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drRJEBJ[topSrc, aux9, UseLabel8B[OKState]]; --Make sure RB[0] didn't smash [S]
SetLabel[BadState]; XPause[];
SetLabel[OKState];
drLIB[123B]; drROR[aux10, popSrc, topSrc];
S ← S - 1 if the popSrc isn't a no-op.
drRRX[aux10, popSrc, const0]; XPause[]; XPause[]; XPause[];
Make sure value in aux10 isn't overwritten during the fault.
drLIB[123B]; drRJNEB[popSrc, aux10, UseLabel8B[BadState]];
Make sure S didn't change during the fault.
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
drLIDB[123456B];
drWSB[0]; XPause[]; XPause[]; XPause[]; XPause[];
drLIDB[123456B];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
IF
NOT withSoftCard
THEN {
drLIDB[111111B]; --new value
drLIDB[122222B]; --old value
It is a "don't care" whether or not CST smashes the value in [S+1] on a page fault because that value will be overwritten by the page fault trap procedure.
drCST[0]; XPause[]; XPause[]; XPause[]; XPause[];
};
drLIDB[122222B]; drRJNEB[popSrc, belowSrcPop, UseLabel8B[BadState]];
drDIS[];
drSFCI[]; XPause[]; XPause[]; XPause[]; XPause[]; XPause[];
drRJNEB[topSrc, aux9, UseLabel8B[BadState]];
Lizard doesn't trap the IODA opcode for page faults.
[S] ← PRead[AlphaZ + [S], BetaZ] with address check.
--drIODA[2B]; XPause[]; XPause[]; XPause[];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drLIB[123B]; drROR[pushDst, aux9, const0];
PWrite[AlphaZ + [S], BetaZ with address check, [S-1]]; S ← S-2.
--drIODA[3B];
--drRJNEB[popSrc, aux9, UseLabel8B[BadState]];
--drJNEBB[123B, UseLabel8B[BadState]];
};
Verify that ModeFault prevails over bounds check, overflow, NaN, and EU page fault.
GenModeFaultPriority:
PROC [] ~ {
SetLabel[enterModeFaultPriorityTest];
drASL[377B]; --L = 1, S = 0
drLIB[8]; drROR[aux8, topSrc, popSrc]; --code for ModeFault trap
EnterUser[];
drLIQB[CardToWord[10000000000B]]; drDUP[];
Modefault prevails over NaN.
drRLADD[const2, belowSrc, topSrc]; XPause[]; XPause[]; XPause[];
Modefault prevails over overflow.
drRADD[const2, belowSrc, topSrc]; XPause[]; XPause[]; XPause[];
Modefault prevails over bounds check.
drRBC[const2, belowSrc, popSrc]; XPause[]; XPause[]; XPause[];
drDIS[];
drLC0[]; drLIQB[CardToWord[EUPageFaultAddress]];
Modefault prevails over EU page fault.
drRRX[const2, popSrc, belowSrcPop]; XPause[]; XPause[]; XPause[];
EnterKernel[]; --Indicate KFC trap expected
Return here in Kernel mode
};
XPause[] = Pause[] but uses opcode 2 instead of 0.
XPause:
PROC = {
HandCodingSupport.OutputByte[HandCodingSupport.GetCurrentArea[], LOOPHOLE[2]];
};
spLimit is set with room for 17 overflow words (just in case).
drLIB[128-16-1];
SetSPLimit[];
drROR[aux8, const0, const0]; --Initialize aux8 to 0, meaning no traps expected.
drLIB[6];
drROR[const4, popSrc, topSrc]; --Initialize const4 to 6 for the trap routines.
Now initialize the other constants and auxiliary registers to 1 so that they can be read during the user mode test without confusing the simulators.
drLIB[1];
drROR[const5, topSrc, topSrc];
drROR[const6, topSrc, topSrc];
drROR[const7, topSrc, topSrc];
drROR[const8, topSrc, topSrc];
drROR[const9, topSrc, topSrc];
drROR[const10, topSrc, topSrc];
drROR[const11, topSrc, topSrc];
drROR[aux1, topSrc, topSrc];
drROR[aux2, topSrc, topSrc];
drROR[aux3, topSrc, topSrc];
drROR[aux4, topSrc, topSrc];
drROR[aux5, topSrc, topSrc];
drROR[aux6, topSrc, topSrc];
drROR[aux7, topSrc, topSrc];
To avoid undefined values, write the 3 registers which will be read by LIP in user mode.
drLC0[]; drSIP[0];
drLC0[]; drSIP[127];
drLC0[]; drSIP[159]; --aux 15, inst. 33
Initialize all the locals for one frame
FOR I: CARDINAL IN [0..15) DO drLC0[]; ENDLOOP;
Next instruction is the 49th. All of these work except that in GenIFUStackOverflow ModeFault trap takes priority over IFUStackOverflow, a Lizard bug.
GenIFUStatus[];
GenIFUStackOverflow[];
GenSLimit[];
GenIFUPageFault[];
GenEUPageFault[];
GenModeFaultPriority[];
Halt[177777B]; --Terminate here at the end of the program
StandardTrap[IFUStackOverflow, 1]; --priority 2
EU page fault trap has code 2
EU write protect fault trap has code 3
StandardTrap[Overflow, 5];
StandardTrap[BoundsCheck, 6];
StandardTrap[LispNaN, 7];
StandardTrap[UserModeViolation, 8];
StandardTrap[EUStackOverflow, 9];
IFU page fault trap has code 10
Reschedule trap has code 11
KFC trap has code 12
1-byte Xop (opcode = 1B) has code 13
2-byte Xop (opcode 234B, alpha = 123B) has code 14
3-byte Xop (opcode 364B, alphabeta = 234B) has code 15
5-byte Xop (opcode 40B, alphabetagammadelta = 345B) has code 16
SetLabel[EUPageFlt];
drLIB[2]; drRJNEB[popSrc, aux8, UseLabel8B[EUPageFaultBad]];
All of the EU page fault tests use the address EUPageFaultAddress in aux9.
drLIP[euMAR];
drRJNEB[popSrc, aux9, UseLabel8B[EUPageFaultBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETN[];
SetLabel[EUPageFaultBad]; Pause[];
SetLabel[EUWPFlt];
drLIB[3]; drRJNEB[popSrc, aux8, UseLabel8B[EUWPFaultBad]];
All of the EU page fault tests use the address EUPageFaultAddress.
drLIQB[CardToWord[EUPageFaultAddress]];
drLIP[euMAR];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[EUWPFaultBad]];
GetYoungestPC[]; drRVADD[topDst, topSrc, const4]; SetYoungestPC[];
drRETN[];
SetLabel[EUWPFaultBad]; Pause[];
SetLabel[IFUPageFault];
1 arg = return PC
drLIB[10]; drRJNEB[popSrc, aux8, UseLabel8B[IFUPageFaultBad]];
GetYoungestPC[];
All of the IFU page fault tests try to execute an instruction at IFUPageFaultPC.
drLIQB[CardToWord[IFUPageFaultPC]];
drRJNEB[popSrc, belowSrcPop, UseLabel8B[IFUPageFaultBad]];
SetYoungestPC[];
drRETN[];
SetLabel[IFUPageFaultBad]; Pause[];
****Does Reschedule-waiting have to be cleared here?
SetLabel[Reschedule]; --Arg is the return PC
drLIB[11]; drRJNEB[popSrc, aux8, UseLabel8B[RescheduleBad]];
SetYoungestPC[];
drRETN[];
SetLabel[RescheduleBad]; Pause[];
KFC is used to get back into Kernel mode with traps disabled after testing in User mode
SetLabel[KFCTrap];
drLIB[12]; drRJNEB[popSrc, aux8, UseLabel8B[KFCBad]];
drLIP[ifuYoungestL]; drLIB[377B]; drAND[]; drSIP[ifuYoungestL];
drRETN[]; --Return to caller remaining in Kernel mode with traps disabled.
SetLabel[KFCBad]; Pause[];
SetLabel[Xop1Trap];
drLIB[13]; drRJNEB[popSrc, aux8, UseLabel8B[Xop1Bad]];
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop1Bad]; XPause[];
SetLabel[Xop2Trap];
drLIB[14]; drRJNEB[popSrc, aux8, UseLabel8B[Xop2Bug]];
drJNEBB[123B, UseLabel8B[Xop2Bug]]; --Discard the pushed Alpha
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop2Bug]; XPause[];
SetLabel[Xop3Trap];
drLIB[15]; drRJNEB[popSrc, aux8, UseLabel8B[Xop3Bug]];
drJNEBB[234B, UseLabel8B[Xop3Bug]]; --Discard the pushed AlphaBeta
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop3Bug]; XPause[];
SetLabel[Xop5Trap];
drLIB[16]; drRJNEB[popSrc, aux8, UseLabel8B[Xop5Bug]];
drJNEBB[345B, UseLabel8B[Xop5Bug]]; --Discard the pushed AlphaBetaGammaDelta
drRETN[]; --Return to caller remaining in Kernel mode.
SetLabel[Xop5Bug]; XPause[];
XPause[] (opcode 2) is used instead of Pause[] (opcode 0) to enter the debugger from user mode. This is done by first executing KFC to enter monitor mode and then doing Pause[].
SetLabel[ErrorXop1Trap];
drLIQB[CardToWord[600000B]]; GetYoungestStatus[]; drAND[];
drJEBB[0, UseLabel8B[AlreadyInKernel]];
EnterKernel[];
SetLabel[AlreadyInKernel];
drLIQB[CardToWord[debugBase]];
drLIP[130]; drWSB[euRegBase + 130]; --euMAR
drLIB[2]; --Opcode number of XPause[];
drJQB[CardToWord[debuggerBasePC]];
SetLabel[TurnOnTraps]; --Call here with EnableTraps[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L
drLIQB[CardToWord[200000B]]; drOR[]; SetYoungestStatus[]; --Set trapsEnabled
drRETN[];
SetLabel[TurnOffTraps]; --Call here with DisableTraps[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L, clear trapsEnabled and User
SetYoungestStatus[]; --Set trapsEnabled
drRETN[];
SetLabel[TurnOnUserMode]; --Call here with EnterUser[]
drLIB[377B]; GetYoungestStatus[]; drAND[]; --Preserve L
Set trapsEnabled and user mode
drLIQB[CardToWord[600000B]]; drOR[]; SetYoungestStatus[];
drRETN[];
These calls to FillXop and FillTrap initialize the trap locations with JDB[trap procedure].
FillXop[LOOPHOLE[DragOpsCross.Inst.dKFC, CARDINAL], KFCTrap];
FillXop[1B, Xop1Trap];
FillXop[234B, Xop2Trap];
FillXop[364B, Xop3Trap];
FillXop[40B, Xop5Trap];
FillXop[2B, ErrorXop1Trap];
FillTrap[IFUStackOverflowTrap, IFUStackOverflow];
FillTrap[EUPageFault, EUPageFlt];
FillTrap[EUWriteFault, EUWPFlt];
FillTrap[ALUCondOver, Overflow];
FillTrap[ALUCondBC, BoundsCheck];
FillTrap[ALUCondIL, LispNaN];
FillTrap[ModeFault, UserModeViolation];
FillTrap[EUStackOverflowTrap, EUStackOverflow];
FillTrap[IFUPageFaultTrap, IFUPageFault];
FillTrap[RescheduleTrap, Reschedule];