Windows NT 4.0 source code leak
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

// 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)