mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
810 lines
26 KiB
810 lines
26 KiB
// TITLE("Miscellaneous Exception Handling")
|
|
//++
|
|
//
|
|
// Copyright (c) 1990 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// xcptmisc.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements miscellaneous routines that are required
|
|
// to support exception handling. Functions are provided to capture
|
|
// and restore the caller's context, call an exception handler for
|
|
// an exception, call an exception handler for unwinding, call an
|
|
// exception filter, call a termination handler, and get the
|
|
// caller's stack limits.
|
|
//
|
|
// Author:
|
|
//
|
|
// Rick Simpson 10-Sep-1993
|
|
//
|
|
// Based on the MIPS routines xxcaptur.s and xcptmisc.s, by
|
|
// David N. Cutler (davec) 12-Sep-1990
|
|
//
|
|
// Environment:
|
|
//
|
|
// Any mode.
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Tom Wood (twood) 1-Nov-1993
|
|
// Rewrite RtlpExecuteHandlerForException, RtlpExceptionHandler,
|
|
// RtlpExecuteHandlerForUnwind, and RtlpUnwindHandler to be more
|
|
// like the MIPS versions.
|
|
//--
|
|
//list(off)
|
|
#include "ksppc.h"
|
|
//list(on)
|
|
.extern NtContinue
|
|
|
|
.set PCR_SAVE4, PcGprSave + 8
|
|
.set PCR_SAVE5, PcGprSave + 12
|
|
.set PCR_SAVE6, PcGprSave + 16
|
|
.set sprg.1, 1
|
|
|
|
//++
|
|
//
|
|
// VOID
|
|
// RtlCaptureContext (
|
|
// OUT PCONTEXT ContextRecord
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function captures the context of the caller in the specified
|
|
// context record.
|
|
//
|
|
// N.B. The context IS guaranteed to be doubleword (8-byte) aligned,
|
|
// as are all structs in PowerPC containing "double"s.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ContextRecord (r.3) - Supplies the address of a context record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
// Presumed user-mode MSR value -- ILE | EE | PR | FP | ME | FE0 | IR |
|
|
// FE1 | DR | LE
|
|
|
|
.set UserMSR, 0x0001F931
|
|
|
|
LEAF_ENTRY(RtlCaptureContext)
|
|
|
|
//
|
|
// Save the floating-point context
|
|
//
|
|
|
|
stfd f.0, CxFpr0 (r.3)
|
|
mffs f.0 // fetch FPSCR into f.0
|
|
stfd f.1, CxFpr1 (r.3)
|
|
stfd f.2, CxFpr2 (r.3)
|
|
stfd f.3, CxFpr3 (r.3)
|
|
stfd f.4, CxFpr4 (r.3)
|
|
stfd f.5, CxFpr5 (r.3)
|
|
stfd f.6, CxFpr6 (r.3)
|
|
stfd f.7, CxFpr7 (r.3)
|
|
stfd f.8, CxFpr8 (r.3)
|
|
stfd f.9, CxFpr9 (r.3)
|
|
stfd f.10, CxFpr10 (r.3)
|
|
stfd f.11, CxFpr11 (r.3)
|
|
stfd f.12, CxFpr12 (r.3)
|
|
stfd f.13, CxFpr13 (r.3)
|
|
stfd f.14, CxFpr14 (r.3)
|
|
stfd f.15, CxFpr15 (r.3)
|
|
stfd f.16, CxFpr16 (r.3)
|
|
stfd f.17, CxFpr17 (r.3)
|
|
stfd f.18, CxFpr18 (r.3)
|
|
stfd f.19, CxFpr19 (r.3)
|
|
stfd f.20, CxFpr20 (r.3)
|
|
stfd f.21, CxFpr21 (r.3)
|
|
stfd f.22, CxFpr22 (r.3)
|
|
stfd f.23, CxFpr23 (r.3)
|
|
stfd f.24, CxFpr24 (r.3)
|
|
stfd f.25, CxFpr25 (r.3)
|
|
stfd f.26, CxFpr26 (r.3)
|
|
stfd f.27, CxFpr27 (r.3)
|
|
stfd f.28, CxFpr28 (r.3)
|
|
stfd f.29, CxFpr29 (r.3)
|
|
stfd f.30, CxFpr30 (r.3)
|
|
stfd f.31, CxFpr31 (r.3)
|
|
stfd f.0, CxFpscr (r.3) // store FPSCR in context record
|
|
|
|
//
|
|
// Save the integer context
|
|
//
|
|
|
|
stw r.0, CxGpr0 (r.3)
|
|
mfcr r.0
|
|
stw r.1, CxGpr1 (r.3)
|
|
stw r.2, CxGpr2 (r.3)
|
|
stw r.3, CxGpr3 (r.3)
|
|
stw r.4, CxGpr4 (r.3)
|
|
mfxer r.4
|
|
stw r.5, CxGpr5 (r.3)
|
|
mflr r.5
|
|
stw r.6, CxGpr6 (r.3)
|
|
mfctr r.6
|
|
stw r.7, CxGpr7 (r.3)
|
|
stw r.8, CxGpr8 (r.3)
|
|
stw r.9, CxGpr9 (r.3)
|
|
stw r.10, CxGpr10 (r.3)
|
|
stw r.11, CxGpr11 (r.3)
|
|
stw r.12, CxGpr12 (r.3)
|
|
stw r.13, CxGpr13 (r.3)
|
|
stw r.14, CxGpr14 (r.3)
|
|
stw r.15, CxGpr15 (r.3)
|
|
stw r.16, CxGpr16 (r.3)
|
|
stw r.17, CxGpr17 (r.3)
|
|
stw r.18, CxGpr18 (r.3)
|
|
stw r.19, CxGpr19 (r.3)
|
|
stw r.20, CxGpr20 (r.3)
|
|
stw r.21, CxGpr21 (r.3)
|
|
stw r.22, CxGpr22 (r.3)
|
|
stw r.23, CxGpr23 (r.3)
|
|
stw r.24, CxGpr24 (r.3)
|
|
stw r.25, CxGpr25 (r.3)
|
|
stw r.26, CxGpr26 (r.3)
|
|
stw r.27, CxGpr27 (r.3)
|
|
|
|
//
|
|
// Test high-order bit of stack pointer value
|
|
// 0 => caller in user mode (address <= 0x7FFFFFFF)
|
|
// 1 => caller in kernel mode (address >= 0x80000000)
|
|
|
|
cmpwi r.1, 0
|
|
|
|
//
|
|
// Save special registers (some integer, some control)
|
|
//
|
|
|
|
stw r.0, CxCr (r.3) // condition register
|
|
stw r.4, CxXer (r.3) // fixed point exception register
|
|
stw r.5, CxIar (r.3) // instruction address (current PC)
|
|
stw r.5, CxLr (r.3) // link register (return address)
|
|
stw r.6, CxCtr (r.3) // count register
|
|
|
|
//
|
|
// Save actual MSR value if caller is kernel, otherwise save
|
|
// canonical user-mode MSR value
|
|
//
|
|
|
|
lis r.0, UserMSR > 16
|
|
ori r.0, r.0, UserMSR & 0xFFFF
|
|
bnl Cap1 // branch around if user mode
|
|
mfmsr r.0
|
|
Cap1:
|
|
stw r.28, CxGpr28 (r.3)
|
|
stw r.29, CxGpr29 (r.3)
|
|
stw r.30, CxGpr30 (r.3)
|
|
stw r.31, CxGpr31 (r.3)
|
|
|
|
stw r.0, CxMsr (r.3) // save MSR value
|
|
|
|
//
|
|
// Set context record flags, and exit
|
|
//
|
|
|
|
lis r.0, CONTEXT_FULL > 16
|
|
ori r.0, r.0, CONTEXT_FULL & 0xFFFF
|
|
stw r.0, CxContextFlags (r.3)
|
|
|
|
LEAF_EXIT (RtlCaptureContext)
|
|
|
|
//++
|
|
//
|
|
// VOID
|
|
// RtlpRestoreContext (
|
|
// IN PCONTEXT ContextRecord,
|
|
// IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function restores the context of the caller from the specified
|
|
// context record.
|
|
//
|
|
// N.B. The context IS guaranteed to be doubleword (8-byte) aligned,
|
|
// as are all structs in PowerPC containing "double"s.
|
|
//
|
|
// N.B. This is a special routine that is used by RtlUnwind to restore
|
|
// context in the current mode.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ContextRecord (r.3) - Supplies the address of a context record.
|
|
//
|
|
// ExceptionRecord (r.4) - Supplies an optional pointer to an exception
|
|
// record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
// N.B. There is no return from this routine.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpRestoreContext)
|
|
|
|
//
|
|
// If an exception record is specified and the exception status is
|
|
// STATUS_LONGJUMP, then restore the nonvolatile registers to their
|
|
// state at the call to setjmp before restoring the context record.
|
|
//
|
|
|
|
cmplwi cr.1, r.4, 0 // ExceptionRecord supplied?
|
|
cmpwi cr.0, r.1, 0 // test kernel/user mode
|
|
beq cr.1, NoExcpRec // if eq, no exception record
|
|
lwz r.6, ErExceptionCode(r.4) // get exception code
|
|
LWI(r.8,STATUS_LONGJUMP) // get long jump status code
|
|
cmplw cr.1, r.6, r.8 // is long jump status?
|
|
lwz r.5, ErExceptionInformation(r.4)// get address of jump buffer
|
|
bne cr.1, NoExcpRec // if ne, not a long jump
|
|
|
|
// Get non-volatile control context
|
|
|
|
lwz r.7, JbIar(r.5)
|
|
lwz r.8, JbCr(r.5)
|
|
lwz r.9, JbGpr1(r.5)
|
|
lwz r.10,JbGpr2(r.5)
|
|
|
|
// Get non-volatile Floating Point context from jump buffer
|
|
|
|
lfd f.14, JbFpr14(r.5)
|
|
lfd f.15, JbFpr15(r.5)
|
|
lfd f.16, JbFpr16(r.5)
|
|
lfd f.17, JbFpr17(r.5)
|
|
lfd f.18, JbFpr18(r.5)
|
|
lfd f.19, JbFpr19(r.5)
|
|
lfd f.20, JbFpr20(r.5)
|
|
lfd f.21, JbFpr21(r.5)
|
|
lfd f.22, JbFpr22(r.5)
|
|
lfd f.23, JbFpr23(r.5)
|
|
lfd f.24, JbFpr24(r.5)
|
|
lfd f.25, JbFpr25(r.5)
|
|
lfd f.26, JbFpr26(r.5)
|
|
lfd f.27, JbFpr27(r.5)
|
|
lfd f.28, JbFpr28(r.5)
|
|
lfd f.29, JbFpr29(r.5)
|
|
lfd f.30, JbFpr30(r.5)
|
|
lfd f.31, JbFpr31(r.5)
|
|
|
|
// Get non-volatile Integer context from jump buffer
|
|
|
|
lwz r.14, JbGpr14(r.5)
|
|
lwz r.15, JbGpr15(r.5)
|
|
lwz r.16, JbGpr16(r.5)
|
|
lwz r.17, JbGpr17(r.5)
|
|
lwz r.18, JbGpr18(r.5)
|
|
lwz r.19, JbGpr19(r.5)
|
|
lwz r.20, JbGpr20(r.5)
|
|
lwz r.21, JbGpr21(r.5)
|
|
lwz r.22, JbGpr22(r.5)
|
|
lwz r.23, JbGpr23(r.5)
|
|
lwz r.24, JbGpr24(r.5)
|
|
lwz r.25, JbGpr25(r.5)
|
|
lwz r.26, JbGpr26(r.5)
|
|
lwz r.27, JbGpr27(r.5)
|
|
lwz r.28, JbGpr28(r.5)
|
|
lwz r.29, JbGpr29(r.5)
|
|
lwz r.30, JbGpr30(r.3)
|
|
lwz r.31, JbGpr31(r.3)
|
|
|
|
//
|
|
// Save non-volatile control context in context record
|
|
//
|
|
|
|
stw r.7, CxIar(r.3)
|
|
stw r.8, CxCr(r.3)
|
|
stw r.9, CxGpr1(r.3)
|
|
stw r.10,CxGpr2(r.3)
|
|
|
|
//
|
|
// Save non-volatile Floating Point and Integer registers in context record
|
|
// plj note: do we really need to do this if we are in kernel mode?
|
|
//
|
|
|
|
stfd f.14, CxFpr14(r.3)
|
|
stfd f.15, CxFpr15(r.3)
|
|
stfd f.16, CxFpr16(r.3)
|
|
stfd f.17, CxFpr17(r.3)
|
|
stfd f.18, CxFpr18(r.3)
|
|
stfd f.19, CxFpr19(r.3)
|
|
stfd f.20, CxFpr20(r.3)
|
|
stfd f.21, CxFpr21(r.3)
|
|
stfd f.22, CxFpr22(r.3)
|
|
stfd f.23, CxFpr23(r.3)
|
|
stfd f.24, CxFpr24(r.3)
|
|
stfd f.25, CxFpr25(r.3)
|
|
stfd f.26, CxFpr26(r.3)
|
|
stfd f.27, CxFpr27(r.3)
|
|
stfd f.28, CxFpr28(r.3)
|
|
stfd f.29, CxFpr29(r.3)
|
|
stfd f.30, CxFpr30(r.3)
|
|
stfd f.31, CxFpr31(r.3)
|
|
stw r.14, CxGpr14(r.3)
|
|
stw r.15, CxGpr15(r.3)
|
|
stw r.16, CxGpr16(r.3)
|
|
stw r.17, CxGpr17(r.3)
|
|
stw r.18, CxGpr18(r.3)
|
|
stw r.19, CxGpr19(r.3)
|
|
stw r.20, CxGpr20(r.3)
|
|
stw r.21, CxGpr21(r.3)
|
|
stw r.22, CxGpr22(r.3)
|
|
stw r.23, CxGpr23(r.3)
|
|
stw r.24, CxGpr24(r.3)
|
|
stw r.25, CxGpr25(r.3)
|
|
stw r.26, CxGpr26(r.3)
|
|
stw r.27, CxGpr27(r.3)
|
|
stw r.28, CxGpr28(r.3)
|
|
stw r.29, CxGpr29(r.3)
|
|
stw r.30, CxGpr30(r.3)
|
|
stw r.31, CxGpr31(r.3)
|
|
|
|
//
|
|
// If from kernel mode, continue restoration with volatile registers.
|
|
//
|
|
|
|
blt cr.0, ResKrnlVol
|
|
|
|
//
|
|
// If called in user mode (stack pointer in r.1 is < 0x80000000), branch
|
|
// directly to the "continue" system service to continue execution.
|
|
//
|
|
// If we fell thru from above, the blt below will fall thru also, and it's
|
|
// free on PowerPC.
|
|
//
|
|
|
|
NoExcpRec:
|
|
|
|
blt cr.0, ResKrnlAll // branch if kernel mode
|
|
|
|
lwz r.5, [toc] NtContinue (r.toc) // get function desc. addr
|
|
lwz r.0, 0(r.5) // get entry point address
|
|
li r.4, 0 // set "test alert" arg FALSE
|
|
mtctr r.0 // into Ctr
|
|
lwz r.2, 4(r.5) // get TOC address
|
|
bctr // branch to system service
|
|
|
|
ResKrnlAll:
|
|
|
|
//
|
|
// Restore the non-volatile Floating Point context
|
|
//
|
|
|
|
lfd f.14, CxFpr14 (r.3)
|
|
lfd f.15, CxFpr15 (r.3)
|
|
lfd f.16, CxFpr16 (r.3)
|
|
lfd f.17, CxFpr17 (r.3)
|
|
lfd f.18, CxFpr18 (r.3)
|
|
lfd f.19, CxFpr19 (r.3)
|
|
lfd f.20, CxFpr20 (r.3)
|
|
lfd f.21, CxFpr21 (r.3)
|
|
lfd f.22, CxFpr22 (r.3)
|
|
lfd f.23, CxFpr23 (r.3)
|
|
lfd f.24, CxFpr24 (r.3)
|
|
lfd f.25, CxFpr25 (r.3)
|
|
lfd f.26, CxFpr26 (r.3)
|
|
lfd f.27, CxFpr27 (r.3)
|
|
lfd f.28, CxFpr28 (r.3)
|
|
lfd f.29, CxFpr29 (r.3)
|
|
lfd f.30, CxFpr30 (r.3)
|
|
lfd f.31, CxFpr31 (r.3)
|
|
|
|
//
|
|
// Restore the non-volatile Integer context
|
|
//
|
|
|
|
lwz r.14, CxGpr14 (r.3)
|
|
lwz r.15, CxGpr15 (r.3)
|
|
lwz r.16, CxGpr16 (r.3)
|
|
lwz r.17, CxGpr17 (r.3)
|
|
lwz r.18, CxGpr18 (r.3)
|
|
lwz r.19, CxGpr19 (r.3)
|
|
lwz r.20, CxGpr20 (r.3)
|
|
lwz r.21, CxGpr21 (r.3)
|
|
lwz r.22, CxGpr22 (r.3)
|
|
lwz r.23, CxGpr23 (r.3)
|
|
lwz r.24, CxGpr24 (r.3)
|
|
lwz r.25, CxGpr25 (r.3)
|
|
lwz r.26, CxGpr26 (r.3)
|
|
lwz r.27, CxGpr27 (r.3)
|
|
lwz r.28, CxGpr28 (r.3)
|
|
lwz r.29, CxGpr29 (r.3)
|
|
lwz r.30, CxGpr30 (r.3)
|
|
lwz r.31, CxGpr31 (r.3)
|
|
|
|
//
|
|
// Restore the volatile floating-point context
|
|
//
|
|
|
|
ResKrnlVol:
|
|
|
|
lfd f.13, CxFpscr (r.3) // fetch FPSCR into f.13
|
|
lfd f.0, CxFpr0 (r.3)
|
|
lfd f.1, CxFpr1 (r.3)
|
|
lfd f.2, CxFpr2 (r.3)
|
|
lfd f.3, CxFpr3 (r.3)
|
|
lfd f.4, CxFpr4 (r.3)
|
|
lfd f.5, CxFpr5 (r.3)
|
|
lfd f.6, CxFpr6 (r.3)
|
|
lfd f.7, CxFpr7 (r.3)
|
|
lfd f.8, CxFpr8 (r.3)
|
|
lfd f.9, CxFpr9 (r.3)
|
|
lfd f.10, CxFpr10 (r.3)
|
|
lfd f.11, CxFpr11 (r.3)
|
|
lfd f.12, CxFpr12 (r.3)
|
|
mtfsf 0xff, f.13 // set the FPSCR value
|
|
lfd f.13, CxFpr13 (r.3)
|
|
|
|
//
|
|
// Restore the volatile integer and control context
|
|
//
|
|
|
|
lwz r.0, CxCr (r.3) // condition register
|
|
lwz r.4, CxXer (r.3) // fixed point exception register
|
|
lwz r.5, CxLr (r.3) // link register (return address)
|
|
lwz r.6, CxCtr (r.3) // count register
|
|
|
|
mtcrf 0xff, r.0 // restore CR
|
|
mtxer r.4 // restore XER
|
|
mtlr r.5 // restore LR
|
|
mtctr r.6 // restore CTR
|
|
|
|
lwz r.0, CxGpr0 (r.3) // restore GPRs
|
|
lwz r.2, CxGpr2 (r.3)
|
|
lwz r.4, CxGpr4 (r.3)
|
|
lwz r.5, CxGpr5 (r.3)
|
|
lwz r.6, CxGpr6 (r.3)
|
|
lwz r.9, CxGpr9 (r.3)
|
|
lwz r.10, CxGpr10 (r.3)
|
|
lwz r.11, CxGpr11 (r.3)
|
|
lwz r.12, CxGpr12 (r.3)
|
|
|
|
mfmsr r.8 // fetch current MSR value
|
|
rlwinm r.8, r.8, 0, ~MASK_SPR(MSR_EE,1) // turn off EE bit
|
|
mtmsr r.8 // disable interrupts
|
|
cror 0,0,0 // N.B. 603e/ev Errata 15
|
|
|
|
lwz r.1, CxGpr3 (r.3)
|
|
lwz r.7, CxGpr7 (r.3)
|
|
stw r.1, KiPcr+PCR_SAVE4 (r.0)
|
|
lwz r.1, CxGpr8 (r.3)
|
|
stw r.7, KiPcr+PCR_SAVE5 (r.0)
|
|
stw r.1, KiPcr+PCR_SAVE6 (r.0)
|
|
|
|
lwz r.1, CxGpr1 (r.3) // This MUST BE AFTER
|
|
// interrupts disabled
|
|
lwz r.7, CxIar (r.3) // instruction address (current PC)
|
|
lwz r.3, CxMsr (r.3) // machine state register
|
|
|
|
mfsprg r.8, sprg.1
|
|
|
|
DUMMY_ENTRY(RtlpRestoreContextRfiJump)
|
|
b $ // This is changed to be a branch
|
|
// to KSEG0 code at init time
|
|
RtlpRestoreContext.end:
|
|
|
|
//
|
|
// Define call frame for calling exception handlers.
|
|
//
|
|
|
|
.struct 0
|
|
CfBackChain: .space 4 // chain to previous call frame
|
|
.space 5*4 // remaining part of frame header
|
|
.space 8*4 // 8 words space for call args
|
|
CfDispContext: .space 4 // space to save the incoming
|
|
// Dispatcher Context ptr
|
|
CfSavedRtoc: .space 4 // space to save rtoc
|
|
.space 4 // space to save LR
|
|
.align 3 // force frame length to multiple of
|
|
CfEnd: // eight bytes
|
|
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExecuteHandlerForException (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext,
|
|
// IN PEXCEPTION_ROUTINE ExceptionRoutine
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function allocates a call frame, stores the establisher frame
|
|
// pointer in the frame, establishes an exception handler, and then calls
|
|
// the specified exception handler as an exception handler. If a nested
|
|
// exception occurs, then the exception handler of this function is called
|
|
// and the establisher frame pointer is returned to the exception dispatcher
|
|
// via the dispatcher context parameter. If control is returned to this
|
|
// routine, then the frame is deallocated and the disposition status is
|
|
// returned to the exception dispatcher.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of the exception handler that is to be called.
|
|
//
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// ExceptionRoutine (r.7) - supplies a pointer to the function descriptor
|
|
// for the exception handler that is to be called.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The disposition value returned by the specified exception handler is
|
|
// returned as the function value.
|
|
//
|
|
//--
|
|
|
|
NESTED_ENTRY_EX (RtlpExecuteHandlerForException,CfEnd,0,0,RtlpExceptionHandler,0)
|
|
|
|
stw r.toc,CfSavedRtoc(r.sp) // save rtoc
|
|
|
|
PROLOGUE_END (RtlpExecuteHandlerForException)
|
|
|
|
lwz r.0, 0 (r.7) // get entry point addr from descriptor
|
|
mtlr r.0 // LR <- entry point addr
|
|
lwz r.toc,4(r.7) // rtoc <- TOC addr from descriptor
|
|
stw r.6, CfDispContext (r.sp) // save Dispatcher Context where
|
|
// RtlpExectionHandler can find it
|
|
|
|
blrl // call the exception handler
|
|
|
|
lwz r.toc,CfSavedRtoc(r.sp) // restore rtoc
|
|
NESTED_EXIT (RtlpExecuteHandlerForException,CfEnd,0,0)
|
|
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExceptionHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function is called when a nested exception occurs. Its function
|
|
// is to retrieve the establisher frame pointer from its establisher's
|
|
// call frame, store this information in the dispatcher context record,
|
|
// and return a disposition value of nested exception.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
//
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// A disposition value ExceptionNestedException is returned if an unwind
|
|
// is not in progress. Otherwise a value of ExceptionContinueSearch is
|
|
// returned.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY (RtlpExceptionHandler)
|
|
lwz r.0, ErExceptionFlags (r.3) // get exception flags
|
|
li r.3, ExceptionContinueSearch // set usual disposition value
|
|
andi. r.0, r.0, EXCEPTION_UNWIND // check if unwind in progress
|
|
bnelr // if neq, unwind in progress
|
|
// return continue search disposition
|
|
|
|
//
|
|
// Unwind is not in progress - return nested exception disposition.
|
|
//
|
|
|
|
lwz r.7,CfDispContext-CfEnd(r.4) // get dispatcher context address
|
|
li r.3, ExceptionNestedException // set disposition value
|
|
lwz r.0, DcEstablisherFrame(r.7) // copy the establisher environment
|
|
stw r.0, DcEstablisherFrame (r.6) // to current dispatcher context
|
|
LEAF_EXIT (RtlpExceptionHandler)
|
|
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExecuteHandlerForUnwind (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN PVOID EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PVOID DispatcherContext,
|
|
// IN PEXCEPTION_ROUTINE ExceptionRoutine
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function allocates a call frame, stores the establisher frame
|
|
// pointer and the context record address in the frame, establishes an
|
|
// exception handler, and then calls the specified exception handler as
|
|
// an unwind handler. If a collided unwind occurs, then the exception
|
|
// handler of of this function is called and the establisher frame pointer
|
|
// and context record address are returned to the unwind dispatcher via
|
|
// the dispatcher context parameter. If control is returned to this routine,
|
|
// then the frame is deallocated and the disposition status is returned to
|
|
// the unwind dispatcher.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of the exception handler that is to be called.
|
|
//
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// ExceptionRoutine (r.7) - supplies a pointer to the exception handler
|
|
// that is to be called.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The disposition value returned by the specified exception handler is
|
|
// returned as the function value.
|
|
//
|
|
//--
|
|
|
|
NESTED_ENTRY_EX (RtlpExecuteHandlerForUnwind,CfEnd,0,0,RtlpUnwindHandler,0)
|
|
|
|
stw r.toc, CfSavedRtoc(r.sp) // save rtoc
|
|
|
|
PROLOGUE_END (RtlpExecuteHandlerForUnwind)
|
|
|
|
lwz r.0, 0 (r.7) // get entry point addr from descriptor
|
|
mtlr r.0 // LR <- entry point addr
|
|
lwz r.toc, 4 (r.7) // rtoc <- TOC addr from descriptor
|
|
stw r.6, CfDispContext (r.sp) // save Dispatcher Context where
|
|
// RtlpExectionHandler can find it
|
|
|
|
blrl // call the exception handler
|
|
|
|
lwz r.toc, CfSavedRtoc(r.sp) // restore rtoc
|
|
|
|
NESTED_EXIT (RtlpExecuteHandlerForUnwind,CfEnd,0,0)
|
|
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpUnwindHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN PVOID EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PVOID DispatcherContext
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function is called when a collided unwind occurs. Its function
|
|
// is to retrieve the establisher dispatcher context, copy it to the
|
|
// current dispatcher context, and return a disposition value of nested
|
|
// unwind.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
//
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// A disposition value ExceptionCollidedUnwind is returned if an unwind is
|
|
// in progress. Otherwise, a value of ExceptionContinueSearch is returned.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY (RtlpUnwindHandler)
|
|
|
|
lwz r.0, ErExceptionFlags (r.3) // get exception flags
|
|
li r.3, ExceptionContinueSearch // set usual disposition value
|
|
andi. r.0, r.0, EXCEPTION_UNWIND // check if unwind in progress
|
|
beqlr // if eq, unwind not in progress
|
|
// return continue search disposition
|
|
|
|
//
|
|
// Unwind is in progress - return collided exception disposition.
|
|
//
|
|
|
|
lwz r.7, CfDispContext-CfEnd (r.4) // get dispatcher context address
|
|
lwz r.0, DcControlPc (r.7) // copy the establisher frame's
|
|
lwz r.3, DcFunctionEntry (r.7) // dispatcher context to the
|
|
lwz r.4, DcEstablisherFrame (r.7) // current dispatcher context
|
|
lwz r.5, DcContextRecord (r.7)
|
|
stw r.0, DcControlPc (r.6)
|
|
stw r.3, DcFunctionEntry (r.6)
|
|
stw r.4, DcEstablisherFrame (r.6)
|
|
stw r.5, DcContextRecord (r.6)
|
|
li r.3, ExceptionCollidedUnwind // return collided unwind disposition
|
|
LEAF_EXIT (RtlpUnwindHandler)
|
|
|
|
//++
|
|
//
|
|
// VOID
|
|
// RtlpGetStackLimits (
|
|
// OUT PULONG LowLimit,
|
|
// OUT PULONG HighLimit
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function returns the current stack limits based on the current
|
|
// processor mode.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LowLimit (r.3) - Supplies a pointer to a variable that is to receive
|
|
// the low limit of the stack.
|
|
//
|
|
// HighLimit (r.4) - Supplies a pointer to a variable that is to receive
|
|
// the high limit of the stack.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY (RtlpGetStackLimits)
|
|
|
|
#ifdef ROS_DEBUG
|
|
li r.0, 0 // force return low=0, high=2GB for debug
|
|
stw r.0, 0(r.3)
|
|
lis r.0, 0x7FFF
|
|
ori r.0, r.0, 0xFFFF
|
|
stw r.0, 0(r.4)
|
|
blr
|
|
#endif
|
|
|
|
cmpwi r.sp, 0 // if stack ptr < 0x80000000, user mode
|
|
bnl Sl10 // branch if user mode
|
|
|
|
//
|
|
// Current mode is kernel - compute stack limits.
|
|
//
|
|
|
|
lwz r.6, KiPcr+PcInitialStack(r.0) // get high limit of kernel stack
|
|
lwz r.7, KiPcr+PcStackLimit(r.0) // get low limit of kernel stack
|
|
stw r.6, 0 (r.4) // store high limit
|
|
stw r.7, 0 (r.3) // store low limit
|
|
ALTERNATE_EXIT (RtlpGetStackLimits)
|
|
|
|
//
|
|
// Current mode is user - get stack limits from the TEB.
|
|
//
|
|
|
|
Sl10:
|
|
|
|
// Fast-path system service returns TEB address in r.3, having killed only CR
|
|
|
|
lwz r.0, TeStackLimit (r.13) // get low limit of user stack
|
|
lwz r.6, TeStackBase (r.13) // get high limit of user stack
|
|
stw r.0, 0 (r.3) // store low stack limit
|
|
stw r.6, 0 (r.4) // store high stack limit
|
|
LEAF_EXIT (RtlpGetStackLimits)
|