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