update for HEAD-2003091401
[reactos.git] / lib / rosrtl / thread / stack.c
1 /* $Id$
2 */
3 /*
4 */
5
6 #define NTOS_MODE_USER
7 #include <ntos.h>
8
9 #define NDEBUG
10 #include <ntdll/ntdll.h>
11
12 #include <rosrtl/thread.h>
13
14 NTSTATUS NTAPI RtlRosCreateStack
15 (
16  IN HANDLE ProcessHandle,
17  OUT PUSER_STACK UserStack,
18  IN LONG StackZeroBits,
19  IN OUT PULONG StackReserve OPTIONAL,
20  IN OUT PULONG StackCommit OPTIONAL
21 )
22 {
23  /* FIXME: read the defaults from the executable image */
24  ULONG_PTR nStackReserve = 0x100000;
25  /* FIXME: when we finally have exception handling, make this PAGE_SIZE */
26  ULONG_PTR nStackCommit = 0x100000;
27  NTSTATUS nErrCode;
28
29  if(StackReserve == NULL) StackReserve = &nStackReserve;
30  else *StackReserve = ROUNDUP(*StackReserve, PAGE_SIZE);
31
32  if(StackCommit == NULL) StackCommit = &nStackCommit;
33  else *StackCommit = ROUNDUP(*StackCommit, PAGE_SIZE);
34
35 #if 0
36  /* the stack commit size must be equal to or less than the reserve size */
37  if(*StackCommit > *StackReserve) *StackCommit = *StackReserve;
38 #else
39  /* FIXME: no SEH, no guard pages */
40  *StackCommit = *StackReserve;
41 #endif
42
43  /* FIXME: this code assumes a stack growing downwards */
44  /* fixed stack */
45  if(*StackCommit == *StackReserve)
46  {
47   UserStack->ExpandableStackBase = NULL;
48   UserStack->ExpandableStackLimit = NULL; 
49   UserStack->ExpandableStackBottom = NULL;
50
51   UserStack->FixedStackLimit = NULL;
52
53   /* allocate the stack */
54   nErrCode = NtAllocateVirtualMemory
55   (
56    ProcessHandle,
57    &(UserStack->FixedStackLimit),
58    StackZeroBits,
59    StackReserve,
60    MEM_RESERVE | MEM_COMMIT,
61    PAGE_READWRITE
62   );
63
64   /* failure */
65   if(!NT_SUCCESS(nErrCode)) goto l_Fail;
66
67   /* store the highest (first) address of the stack */
68   UserStack->FixedStackBase =
69    (PUCHAR)(UserStack->FixedStackLimit) + *StackReserve;
70
71   *StackCommit = *StackReserve;
72  }
73  /* expandable stack */
74  else
75  {
76   ULONG_PTR nGuardSize = PAGE_SIZE;
77   PVOID pGuardBase;
78
79   DPRINT("Expandable stack\n");
80
81   UserStack->FixedStackBase = NULL;
82   UserStack->FixedStackLimit =  NULL;
83
84   UserStack->ExpandableStackBottom = NULL;
85
86   /* reserve the stack */
87   nErrCode = NtAllocateVirtualMemory
88   (
89    ProcessHandle,
90    &(UserStack->ExpandableStackBottom),
91    StackZeroBits,
92    StackReserve,
93    MEM_RESERVE,
94    PAGE_READWRITE
95   );
96
97   /* failure */
98   if(!NT_SUCCESS(nErrCode)) goto l_Fail;
99
100   DPRINT("Reserved %08X bytes\n", *StackReserve);
101
102   /* expandable stack base - the highest address of the stack */
103   UserStack->ExpandableStackBase =
104    (PUCHAR)(UserStack->ExpandableStackBottom) + *StackReserve;
105
106   /* expandable stack limit - the lowest committed address of the stack */
107   UserStack->ExpandableStackLimit =
108    (PUCHAR)(UserStack->ExpandableStackBase) - *StackCommit;
109
110   DPRINT("Stack base   %p\n", UserStack->ExpandableStackBase);
111   DPRINT("Stack limit  %p\n", UserStack->ExpandableStackLimit);
112   DPRINT("Stack bottom %p\n", UserStack->ExpandableStackBottom);
113
114   /* commit as much stack as requested */
115   nErrCode = NtAllocateVirtualMemory
116   (
117    ProcessHandle,
118    &(UserStack->ExpandableStackLimit),
119    0,
120    StackCommit,
121    MEM_COMMIT,
122    PAGE_READWRITE
123   );
124
125   /* failure */
126   if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
127
128   assert((*StackReserve - *StackCommit) >= PAGE_SIZE);
129   assert((*StackReserve - *StackCommit) % PAGE_SIZE == 0);
130
131   pGuardBase = (PUCHAR)(UserStack->ExpandableStackLimit) - PAGE_SIZE;
132
133   DPRINT("Guard base %p\n", UserStack->ExpandableStackBase);
134
135   /* set up the guard page */
136   nErrCode = NtAllocateVirtualMemory
137   (
138    ProcessHandle,
139    &pGuardBase,
140    0,
141    &nGuardSize,
142    MEM_COMMIT,
143    PAGE_READWRITE | PAGE_GUARD
144   );
145
146   /* failure */
147   if(!NT_SUCCESS(nErrCode)) goto l_Cleanup;
148
149   DPRINT("Guard base %p\n", UserStack->ExpandableStackBase);
150  }
151
152
153  /* success */
154  return STATUS_SUCCESS;
155
156  /* deallocate the stack */
157 l_Cleanup:
158  RtlRosDeleteStack(ProcessHandle, UserStack);
159
160  /* failure */
161 l_Fail:
162  assert(!NT_SUCCESS(nErrCode));
163  return nErrCode;
164 }
165
166 NTSTATUS NTAPI RtlRosDeleteStack
167 (
168  IN HANDLE ProcessHandle,
169  IN PUSER_STACK UserStack
170 )
171 {
172  PVOID pStackLowest = NULL;
173  ULONG_PTR nSize;
174
175  if(UserStack->FixedStackLimit)
176   pStackLowest = UserStack->FixedStackLimit;
177  else if(UserStack->ExpandableStackBottom)
178   pStackLowest = UserStack->ExpandableStackBottom;
179
180  /* free the stack, if it was allocated */
181  if(pStackLowest != NULL)
182   return NtFreeVirtualMemory(ProcessHandle, &pStackLowest, &nSize, MEM_RELEASE);
183
184  return STATUS_SUCCESS;
185 }
186
187
188 NTSTATUS NTAPI RtlpRosGetStackLimits
189 (
190  IN PUSER_STACK UserStack,
191  OUT PVOID * StackBase,
192  OUT PVOID * StackLimit
193 )
194 {
195  /* fixed-size stack */
196  if(UserStack->FixedStackBase && UserStack->FixedStackLimit)
197  {
198   *StackBase = UserStack->FixedStackBase;
199   *StackLimit = UserStack->FixedStackLimit;
200  }
201  /* expandable stack */
202  else if(UserStack->ExpandableStackBase && UserStack->ExpandableStackLimit)
203  {
204   *StackBase = UserStack->ExpandableStackBase;
205   *StackLimit = UserStack->ExpandableStackLimit;
206  }
207  /* can't determine the type of stack: failure */
208  else
209  {
210   DPRINT("Invalid user-mode stack\n");
211   return STATUS_BAD_INITIAL_STACK;
212  }
213
214  /* valid stack */
215  return STATUS_SUCCESS;
216 }
217
218 /* EOF */