132 lines
4.3 KiB
ArmAsm
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
// 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