[NTDLL/LDR]
[reactos.git] / reactos / dll / ntdll / ldr / ldrinit.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrinit.c
5 * PURPOSE: User-Mode Process/Thread Startup
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 HKEY ImageExecOptionsKey;
19 HKEY Wow64ExecOptionsKey;
20 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
21 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
22
23 //RTL_BITMAP TlsBitMap;
24 //RTL_BITMAP TlsExpansionBitMap;
25 //RTL_BITMAP FlsBitMap;
26 BOOLEAN LdrpImageHasTls;
27 LIST_ENTRY LdrpTlsList;
28 ULONG LdrpNumberOfTlsEntries;
29 ULONG LdrpNumberOfProcessors;
30
31 RTL_CRITICAL_SECTION LdrpLoaderLock;
32
33 BOOLEAN ShowSnaps;
34
35 /* FUNCTIONS *****************************************************************/
36
37 /*
38 * @implemented
39 */
40 NTSTATUS
41 NTAPI
42 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
43 IN BOOLEAN Wow64,
44 OUT PHKEY NewKeyHandle)
45 {
46 PHKEY RootKeyLocation;
47 HANDLE RootKey;
48 UNICODE_STRING SubKeyString;
49 OBJECT_ATTRIBUTES ObjectAttributes;
50 NTSTATUS Status;
51 PWCHAR p1;
52
53 /* Check which root key to open */
54 if (Wow64)
55 RootKeyLocation = &Wow64ExecOptionsKey;
56 else
57 RootKeyLocation = &ImageExecOptionsKey;
58
59 /* Get the current key */
60 RootKey = *RootKeyLocation;
61
62 /* Setup the object attributes */
63 InitializeObjectAttributes(&ObjectAttributes,
64 Wow64 ?
65 &Wow64OptionsString : &ImageExecOptionsString,
66 OBJ_CASE_INSENSITIVE,
67 NULL,
68 NULL);
69
70 /* Open the root key */
71 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
72 if (NT_SUCCESS(Status))
73 {
74 /* Write the key handle */
75 if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
76 {
77 /* Someone already opened it, use it instead */
78 NtClose(RootKey);
79 RootKey = *RootKeyLocation;
80 }
81
82 /* Extract the name */
83 SubKeyString = *SubKey;
84 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
85 while (SubKey->Length)
86 {
87 if (p1[-1] == L'\\') break;
88 p1--;
89 SubKeyString.Length -= sizeof(*p1);
90 }
91 SubKeyString.Buffer = p1;
92 SubKeyString.Length = SubKeyString.MaximumLength - SubKeyString.Length - sizeof(WCHAR);
93
94 /* Setup the object attributes */
95 InitializeObjectAttributes(&ObjectAttributes,
96 &SubKeyString,
97 OBJ_CASE_INSENSITIVE,
98 RootKey,
99 NULL);
100
101 /* Open the setting key */
102 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
103 }
104
105 /* Return to caller */
106 return Status;
107 }
108
109 /*
110 * @implemented
111 */
112 NTSTATUS
113 NTAPI
114 LdrQueryImageFileKeyOption(IN HKEY KeyHandle,
115 IN PCWSTR ValueName,
116 IN ULONG Type,
117 OUT PVOID Buffer,
118 IN ULONG BufferSize,
119 OUT PULONG ReturnedLength OPTIONAL)
120 {
121 ULONG KeyInfo[256];
122 UNICODE_STRING ValueNameString, IntegerString;
123 ULONG KeyInfoSize, ResultSize;
124 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
125 BOOLEAN FreeHeap = FALSE;
126 NTSTATUS Status;
127
128 /* Build a string for the value name */
129 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
130 if (!NT_SUCCESS(Status)) return Status;
131
132 /* Query the value */
133 Status = NtQueryValueKey(KeyHandle,
134 &ValueNameString,
135 KeyValuePartialInformation,
136 KeyValueInformation,
137 sizeof(KeyInfo),
138 &ResultSize);
139 if (Status == STATUS_BUFFER_OVERFLOW)
140 {
141 /* Our local buffer wasn't enough, allocate one */
142 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
143 KeyValueInformation->DataLength;
144 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
145 0,
146 KeyInfoSize);
147 if (KeyInfo == NULL)
148 {
149 /* Give up this time */
150 Status = STATUS_NO_MEMORY;
151 }
152
153 /* Try again */
154 Status = NtQueryValueKey(KeyHandle,
155 &ValueNameString,
156 KeyValuePartialInformation,
157 KeyValueInformation,
158 KeyInfoSize,
159 &ResultSize);
160 FreeHeap = TRUE;
161 }
162
163 /* Check for success */
164 if (NT_SUCCESS(Status))
165 {
166 /* Handle binary data */
167 if (KeyValueInformation->Type == REG_BINARY)
168 {
169 /* Check validity */
170 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
171 {
172 /* Copy into buffer */
173 RtlMoveMemory(Buffer,
174 &KeyValueInformation->Data,
175 KeyValueInformation->DataLength);
176 }
177 else
178 {
179 Status = STATUS_BUFFER_OVERFLOW;
180 }
181
182 /* Copy the result length */
183 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
184 }
185 else if (KeyValueInformation->Type == REG_DWORD)
186 {
187 /* Check for valid type */
188 if (KeyValueInformation->Type != Type)
189 {
190 /* Error */
191 Status = STATUS_OBJECT_TYPE_MISMATCH;
192 }
193 else
194 {
195 /* Check validity */
196 if ((Buffer) &&
197 (BufferSize == sizeof(ULONG)) &&
198 (KeyValueInformation->DataLength <= BufferSize))
199 {
200 /* Copy into buffer */
201 RtlMoveMemory(Buffer,
202 &KeyValueInformation->Data,
203 KeyValueInformation->DataLength);
204 }
205 else
206 {
207 Status = STATUS_BUFFER_OVERFLOW;
208 }
209
210 /* Copy the result length */
211 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
212 }
213 }
214 else if (KeyValueInformation->Type != REG_SZ)
215 {
216 /* We got something weird */
217 Status = STATUS_OBJECT_TYPE_MISMATCH;
218 }
219 else
220 {
221 /* String, check what you requested */
222 if (Type == REG_DWORD)
223 {
224 /* Validate */
225 if (BufferSize != sizeof(ULONG))
226 {
227 /* Invalid size */
228 BufferSize = 0;
229 Status = STATUS_INFO_LENGTH_MISMATCH;
230 }
231 else
232 {
233 /* OK, we know what you want... */
234 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
235 IntegerString.Length = KeyValueInformation->DataLength -
236 sizeof(WCHAR);
237 IntegerString.MaximumLength = KeyValueInformation->DataLength;
238 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
239 }
240 }
241 else
242 {
243 /* Validate */
244 if (KeyValueInformation->DataLength > BufferSize)
245 {
246 /* Invalid */
247 Status = STATUS_BUFFER_OVERFLOW;
248 }
249 else
250 {
251 /* Set the size */
252 BufferSize = KeyValueInformation->DataLength;
253 }
254
255 /* Copy the string */
256 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
257 }
258
259 /* Copy the result length */
260 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
261 }
262 }
263
264 /* Check if buffer was in heap */
265 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
266
267 /* Close key and return */
268 NtClose(KeyHandle);
269 return Status;
270 }
271
272 /*
273 * @implemented
274 */
275 NTSTATUS
276 NTAPI
277 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
278 IN PCWSTR ValueName,
279 IN ULONG Type,
280 OUT PVOID Buffer,
281 IN ULONG BufferSize,
282 OUT PULONG ReturnedLength OPTIONAL,
283 IN BOOLEAN Wow64)
284 {
285 NTSTATUS Status;
286 HKEY KeyHandle;
287
288 /* Open a handle to the key */
289 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
290
291 /* Check for success */
292 if (NT_SUCCESS(Status))
293 {
294 /* Query the data */
295 Status = LdrQueryImageFileKeyOption(KeyHandle,
296 ValueName,
297 Type,
298 Buffer,
299 BufferSize,
300 ReturnedLength);
301
302 /* Close the key */
303 NtClose(KeyHandle);
304 }
305
306 /* Return to caller */
307 return Status;
308 }
309
310 /*
311 * @implemented
312 */
313 NTSTATUS
314 NTAPI
315 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
316 IN PCWSTR ValueName,
317 IN ULONG Type,
318 OUT PVOID Buffer,
319 IN ULONG BufferSize,
320 OUT PULONG ReturnedLength OPTIONAL)
321 {
322 /* Call the newer function */
323 return LdrQueryImageFileExecutionOptionsEx(SubKey,
324 ValueName,
325 Type,
326 Buffer,
327 BufferSize,
328 ReturnedLength,
329 FALSE);
330 }
331
332 NTSTATUS
333 NTAPI
334 LdrpInitializeTls(VOID)
335 {
336 PLIST_ENTRY NextEntry, ListHead;
337 PLDR_DATA_TABLE_ENTRY LdrEntry;
338 PIMAGE_TLS_DIRECTORY TlsDirectory;
339 PLDRP_TLS_DATA TlsData;
340 ULONG Size;
341
342 /* Initialize the TLS List */
343 InitializeListHead(&LdrpTlsList);
344
345 /* Loop all the modules */
346 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
347 NextEntry = ListHead->Flink;
348 while (ListHead != NextEntry)
349 {
350 /* Get the entry */
351 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
352 NextEntry = NextEntry->Flink;
353
354 /* Get the TLS directory */
355 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
356 TRUE,
357 IMAGE_DIRECTORY_ENTRY_TLS,
358 &Size);
359
360 /* Check if we have a directory */
361 if (!TlsDirectory) continue;
362
363 /* Check if the image has TLS */
364 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
365
366 /* Show debug message */
367 if (ShowSnaps)
368 {
369 DPRINT1("LDR: Tls Found in %wZ at %p\n",
370 &LdrEntry->BaseDllName,
371 TlsDirectory);
372 }
373
374 /* Allocate an entry */
375 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
376 if (!TlsData) return STATUS_NO_MEMORY;
377
378 /* Lock the DLL and mark it for TLS Usage */
379 LdrEntry->LoadCount = -1;
380 LdrEntry->TlsIndex = -1;
381
382 /* Save the cached TLS data */
383 TlsData->TlsDirectory = *TlsDirectory;
384 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
385
386 /* Update the index */
387 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
388 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
389 }
390
391 /* Done setting up TLS, allocate entries */
392 return LdrpAllocateTls();
393 }
394
395 NTSTATUS
396 NTAPI
397 LdrpAllocateTls(VOID)
398 {
399 PTEB Teb = NtCurrentTeb();
400 PLIST_ENTRY NextEntry, ListHead;
401 PLDRP_TLS_DATA TlsData;
402 ULONG TlsDataSize;
403 PVOID *TlsVector;
404
405 /* Check if we have any entries */
406 if (LdrpNumberOfTlsEntries)
407 return 0;
408
409 /* Allocate the vector array */
410 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
411 0,
412 LdrpNumberOfTlsEntries * sizeof(PVOID));
413 if (!TlsVector) return STATUS_NO_MEMORY;
414 Teb->ThreadLocalStoragePointer = TlsVector;
415
416 /* Loop the TLS Array */
417 ListHead = &LdrpTlsList;
418 NextEntry = ListHead->Flink;
419 while (NextEntry != ListHead)
420 {
421 /* Get the entry */
422 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
423 NextEntry = NextEntry->Flink;
424
425 /* Allocate this vector */
426 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
427 TlsData->TlsDirectory.StartAddressOfRawData;
428 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
429 0,
430 TlsDataSize);
431 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
432 {
433 /* Out of memory */
434 return STATUS_NO_MEMORY;
435 }
436
437 /* Show debug message */
438 if (ShowSnaps)
439 {
440 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
441 TlsVector,
442 TlsData->TlsDirectory.Characteristics,
443 &TlsVector[TlsData->TlsDirectory.Characteristics],
444 TlsData->TlsDirectory.StartAddressOfRawData,
445 TlsVector[TlsData->TlsDirectory.Characteristics]);
446 }
447
448 /* Copy the data */
449 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
450 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
451 TlsDataSize);
452 }
453
454 /* Done */
455 return STATUS_SUCCESS;
456 }
457
458 VOID
459 NTAPI
460 LdrpFreeTls(VOID)
461 {
462 PLIST_ENTRY ListHead, NextEntry;
463 PLDRP_TLS_DATA TlsData;
464 PVOID *TlsVector;
465 PTEB Teb = NtCurrentTeb();
466
467 /* Get a pointer to the vector array */
468 TlsVector = Teb->ThreadLocalStoragePointer;
469 if (!TlsVector) return;
470
471 /* Loop through it */
472 ListHead = &LdrpTlsList;
473 NextEntry = ListHead->Flink;
474 while (NextEntry != ListHead)
475 {
476 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
477 NextEntry = NextEntry->Flink;
478
479 /* Free each entry */
480 if (TlsVector[TlsData->TlsDirectory.Characteristics])
481 {
482 RtlFreeHeap(RtlGetProcessHeap(),
483 0,
484 TlsVector[TlsData->TlsDirectory.Characteristics]);
485 }
486 }
487
488 /* Free the array itself */
489 RtlFreeHeap(RtlGetProcessHeap(),
490 0,
491 TlsVector);
492 }
493
494
495 /* EOF */