2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Rtl user thread functions
5 * FILE: lib/ntdll/rtl/thread.c
7 * Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
19 /* PRIVATE FUNCTIONS *******************************************************/
23 RtlpCreateUserStack(HANDLE hProcess
,
27 PINITIAL_TEB InitialTeb
)
30 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
31 PIMAGE_NT_HEADERS Headers
;
33 BOOLEAN UseGuard
= FALSE
;
35 DPRINT("RtlpCreateUserStack\n");
37 /* Get some memory information */
38 Status
= NtQuerySystemInformation(SystemBasicInformation
,
40 sizeof(SYSTEM_BASIC_INFORMATION
),
42 if (!NT_SUCCESS(Status
))
44 DPRINT1("Failure to query system info\n");
48 /* Use the Image Settings if we are dealing with the current Process */
49 if (hProcess
== NtCurrentProcess())
51 /* Get the Image Headers */
52 Headers
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
53 DPRINT("Headers: %p\n", Headers
);
55 /* If we didn't get the parameters, find them ourselves */
56 StackReserve
= (StackReserve
) ?
57 StackReserve
: Headers
->OptionalHeader
.SizeOfStackReserve
;
58 StackCommit
= (StackCommit
) ?
59 StackCommit
: Headers
->OptionalHeader
.SizeOfStackCommit
;
63 /* Use the System Settings if needed */
64 StackReserve
= (StackReserve
) ? StackReserve
:
65 SystemBasicInfo
.AllocationGranularity
;
66 StackCommit
= (StackCommit
) ? StackCommit
: SystemBasicInfo
.PageSize
;
69 /* Align everything to Page Size */
70 StackReserve
= ROUND_UP(StackReserve
, SystemBasicInfo
.AllocationGranularity
);
71 StackCommit
= ROUND_UP(StackCommit
, SystemBasicInfo
.PageSize
);
72 #if 1 // FIXME: Remove once Guard Page support is here
73 StackCommit
= StackReserve
;
75 DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve
, StackCommit
);
77 /* Reserve memory for the stack */
78 Status
= ZwAllocateVirtualMemory(hProcess
,
84 if (!NT_SUCCESS(Status
))
86 DPRINT1("Failure to reserve stack\n");
90 /* Now set up some basic Initial TEB Parameters */
91 InitialTeb
->PreviousStackBase
= NULL
;
92 InitialTeb
->PreviousStackLimit
= NULL
;
93 InitialTeb
->AllocatedStackBase
= (PVOID
)Stack
;
94 InitialTeb
->StackBase
= (PVOID
)(Stack
+ StackReserve
);
96 /* Update the Stack Position */
97 Stack
+= StackReserve
- StackCommit
;
99 /* Check if we will need a guard page */
100 if (StackReserve
> StackCommit
)
102 Stack
-= SystemBasicInfo
.PageSize
;
103 StackCommit
+= SystemBasicInfo
.PageSize
;
107 DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %p, StackCommit: %lx\n",
108 InitialTeb
->AllocatedStackBase
, InitialTeb
->StackBase
, Stack
,
111 /* Allocate memory for the stack */
112 Status
= ZwAllocateVirtualMemory(hProcess
,
118 if (!NT_SUCCESS(Status
))
120 DPRINT1("Failure to allocate stack\n");
124 /* Now set the current Stack Limit */
125 InitialTeb
->StackLimit
= (PVOID
)Stack
;
126 DPRINT("StackLimit: %p\n", Stack
);
128 /* Create a guard page */
131 ULONG GuardPageSize
= SystemBasicInfo
.PageSize
;
134 /* Attempt maximum space possible */
135 Status
= ZwProtectVirtualMemory(hProcess
,
138 PAGE_GUARD
| PAGE_READWRITE
,
140 if (!NT_SUCCESS(Status
))
142 DPRINT1("Failure to create guard page\n");
146 /* Update the Stack Limit keeping in mind the Guard Page */
147 InitialTeb
->StackLimit
= (PVOID
)((ULONG_PTR
)InitialTeb
->StackLimit
-
149 DPRINT1("StackLimit: %p\n", Stack
);
158 RtlpFreeUserStack(HANDLE hProcess
,
159 PINITIAL_TEB InitialTeb
)
164 return ZwFreeVirtualMemory(hProcess
,
165 &InitialTeb
->AllocatedStackBase
,
170 /* FUNCTIONS ***************************************************************/
177 RtlCreateUserThread(HANDLE ProcessHandle
,
178 PSECURITY_DESCRIPTOR SecurityDescriptor
,
179 BOOLEAN CreateSuspended
,
183 PTHREAD_START_ROUTINE StartAddress
,
185 PHANDLE ThreadHandle
,
191 INITIAL_TEB InitialTeb
;
192 OBJECT_ATTRIBUTES ObjectAttributes
;
195 DPRINT1("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx,"
196 "ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx,"
197 "StartAddress: %p, Parameter: %lx)\n", ProcessHandle
,
198 CreateSuspended
, StackZeroBits
, StackReserve
, StackCommit
,
199 StartAddress
, Parameter
);
201 /* First, we'll create the Stack */
202 Status
= RtlpCreateUserStack(ProcessHandle
,
207 if (!NT_SUCCESS(Status
))
209 DPRINT1("Failure to create User Stack\n");
213 /* Next, we'll set up the Initial Context */
214 RtlInitializeContext(ProcessHandle
,
218 InitialTeb
.StackBase
);
220 /* We are now ready to create the Kernel Thread Object */
221 InitializeObjectAttributes(&ObjectAttributes
,
226 Status
= ZwCreateThread(&Handle
,
234 if (!NT_SUCCESS(Status
))
236 DPRINT1("Failure to create Thread\n");
239 RtlpFreeUserStack(ProcessHandle
, &InitialTeb
);
243 DPRINT("Thread created: %lx\n", Handle
);
244 if (ThreadHandle
) *ThreadHandle
= Handle
;
245 if (ClientId
) *ClientId
= ThreadCid
;
248 /* Return success or the previous failure */
253 * FIXME: Should go in /i386
258 RtlInitializeContext(IN HANDLE ProcessHandle
,
259 OUT PCONTEXT ThreadContext
,
260 IN PVOID ThreadStartParam OPTIONAL
,
261 IN PTHREAD_START_ROUTINE ThreadStartAddress
,
262 IN PINITIAL_TEB InitialTeb
)
264 DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n",
265 ProcessHandle
, ThreadContext
, InitialTeb
);
268 * Set the Initial Registers
269 * This is based on NT's default values -- crazy apps might expect this...
271 ThreadContext
->Ebp
= 0;
272 ThreadContext
->Eax
= 0;
273 ThreadContext
->Ebx
= 1;
274 ThreadContext
->Ecx
= 2;
275 ThreadContext
->Edx
= 3;
276 ThreadContext
->Esi
= 4;
277 ThreadContext
->Edi
= 5;
279 /* Set the Selectors */
280 ThreadContext
->SegGs
= 0;
281 ThreadContext
->SegFs
= TEB_SELECTOR
;
282 ThreadContext
->SegEs
= USER_DS
;
283 ThreadContext
->SegDs
= USER_DS
;
284 ThreadContext
->SegCs
= USER_CS
;
285 ThreadContext
->SegSs
= USER_DS
;
287 /* Enable Interrupts */
288 ThreadContext
->EFlags
= 0x200; /*X86_EFLAGS_IF */
290 /* Settings passed */
291 ThreadContext
->Eip
= (ULONG
)ThreadStartAddress
;
292 ThreadContext
->Esp
= (ULONG
)InitialTeb
;
294 /* Only the basic Context is initialized */
295 ThreadContext
->ContextFlags
= CONTEXT_CONTROL
|
299 /* Set up ESP to the right value */
300 ThreadContext
->Esp
-= sizeof(PVOID
);
301 ZwWriteVirtualMemory(ProcessHandle
,
302 (PVOID
)ThreadContext
->Esp
,
303 (PVOID
)&ThreadStartParam
,
307 /* Push it down one more notch for RETEIP */
308 ThreadContext
->Esp
-= sizeof(PVOID
);
316 RtlFreeUserThreadStack(HANDLE ProcessHandle
,
320 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
321 ULONG Dummy
, Size
= 0;
324 /* Query the Basic Info */
325 Status
= NtQueryInformationThread(ThreadHandle
,
326 ThreadBasicInformation
,
328 sizeof(THREAD_BASIC_INFORMATION
),
330 if (!NT_SUCCESS(Status
) || !ThreadBasicInfo
.TebBaseAddress
)
332 DPRINT1("Could not query info, or TEB is NULL\n");
336 /* Get the deallocation stack */
337 Status
= NtReadVirtualMemory(ProcessHandle
,
338 &((PTEB
)ThreadBasicInfo
.TebBaseAddress
)->
343 if (!NT_SUCCESS(Status
) || !StackLocation
)
345 DPRINT1("Could not read Deallocation Base\n");
350 NtFreeVirtualMemory(ProcessHandle
, &StackLocation
, &Size
, MEM_RELEASE
);