summaryrefslogtreecommitdiffstats
path: root/private/crt32/startup/alpha/chkstk.s
blob: 104254349ecd25e071036c1f2020910b0de3e436 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//      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