132 lines
4.3 KiB
ArmAsm
132 lines
4.3 KiB
ArmAsm
|
// TITLE("Runtime Stack Checking")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Copyright (c) 1991 Microsoft Corporation
|
|||
|
// Copyright (c) 1992 Digital Equipment Corporation
|
|||
|
//
|
|||
|
// Module Name:
|
|||
|
//
|
|||
|
// chkstk.s
|
|||
|
//
|
|||
|
// Abstract:
|
|||
|
//
|
|||
|
// This module implements runtime stack checking.
|
|||
|
//
|
|||
|
// Author:
|
|||
|
//
|
|||
|
// David N. Cutler (davec) 14-Mar-1991
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Any mode.
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
// Thomas Van Baak (tvb) 7-May-1992
|
|||
|
//
|
|||
|
// Adapted for Alpha AXP.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksalpha.h"
|
|||
|
|
|||
|
SBTTL("Check Stack")
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// _RtlCheckStack (
|
|||
|
// IN ULONG Allocation
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This function provides runtime stack checking for local allocations
|
|||
|
// that are more than a page and for storage dynamically allocated with
|
|||
|
// the alloca function. Stack checking consists of probing downward in
|
|||
|
// the stack a page at a time. If the current stack commitment is exceeded,
|
|||
|
// then the system will automatically attempts to expand the stack. If the
|
|||
|
// attempt succeeds, then another page is committed. Otherwise, a stack
|
|||
|
// overflow exception is raised. It is the responsibility of the caller to
|
|||
|
// handle this exception.
|
|||
|
//
|
|||
|
// N.B. This routine is called using a non-standard calling sequence since
|
|||
|
// it is typically called from within the prologue. The allocation size
|
|||
|
// argument is in register t12 and it must be preserved. Register t11
|
|||
|
// may contain the callers saved ra and it must be preserved. The choice
|
|||
|
// of these registers is hard-coded into the acc C compiler. Register v0
|
|||
|
// may contain a static link pointer (exception handlers) and so it must
|
|||
|
// be preserved. Since this function is called from within the prolog,
|
|||
|
// the a' registers must be preserved, as well as all the s' registers.
|
|||
|
// Registers t8, t9, and t10 are used by this function and are not
|
|||
|
// preserved.
|
|||
|
//
|
|||
|
// The typical calling sequence from the prologue is:
|
|||
|
//
|
|||
|
// mov ra, t11 // save return address
|
|||
|
// ldil t12, SIZE // set requested stack frame size
|
|||
|
// bsr ra, _RtlCheckStack // check stack page allocation
|
|||
|
// subq sp, t12, sp // allocate stack frame
|
|||
|
// mov t11, ra // restore return address
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Allocation (t12) - Supplies the size of the allocation on the stack.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(_RtlCheckStack)
|
|||
|
|
|||
|
subq sp, t12, t8 // compute requested new stack address
|
|||
|
mov v0, t10 // save v0 since the PALcode uses it
|
|||
|
bgt sp, 10f // if sp>0, then running on user stack
|
|||
|
|
|||
|
//
|
|||
|
// Running on kernel stack - compute stack limit from initial kernel stack.
|
|||
|
//
|
|||
|
|
|||
|
GET_INITIAL_KERNEL_STACK // (PALcode) result in v0
|
|||
|
|
|||
|
lda t9, -KERNEL_STACK_SIZE(v0) // compute low limit of kernel stack
|
|||
|
br zero, 20f // finish in common code
|
|||
|
|
|||
|
//
|
|||
|
// Running on user stack - get stack limit from thread environment block.
|
|||
|
//
|
|||
|
|
|||
|
10: GET_THREAD_ENVIRONMENT_BLOCK // (PALcode) put TEB address in v0
|
|||
|
|
|||
|
ldl t9, TeStackLimit(v0) // get low limit of user stack address
|
|||
|
|
|||
|
//
|
|||
|
// The requested bottom of the stack is in t8.
|
|||
|
// The current low limit of the stack is in t9.
|
|||
|
//
|
|||
|
// If the new stack address is greater than the current stack limit, then the
|
|||
|
// pages have already been allocated, and nothing further needs to be done.
|
|||
|
//
|
|||
|
|
|||
|
20: mov t10, v0 // restore v0, no further PAL calls
|
|||
|
cmpult t8, t9, t10 // t8<t9? new stack base within limit?
|
|||
|
beq t10, 40f // if eq [false], then t8>=t9, so yes
|
|||
|
|
|||
|
ldil t10, ~(PAGE_SIZE - 1) // round down new stack address
|
|||
|
and t8, t10, t8 // to next page boundary
|
|||
|
|
|||
|
//
|
|||
|
// Go down one page, touch one quadword in it, and repeat until we reach the
|
|||
|
// new stack limit.
|
|||
|
//
|
|||
|
|
|||
|
30: lda t9, -PAGE_SIZE(t9) // compute next address to check
|
|||
|
stq zero, 0(t9) // probe stack address with a write
|
|||
|
cmpeq t8, t9, t10 // t8=t9? at the low limit yet?
|
|||
|
beq t10, 30b // if eq [false], more pages to probe
|
|||
|
|
|||
|
40: ret zero, (ra) // return
|
|||
|
|
|||
|
.end _RtlCheckStack
|