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)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
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
"");
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
;
31 RTL_CRITICAL_SECTION LdrpLoaderLock
;
35 /* FUNCTIONS *****************************************************************/
42 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey
,
44 OUT PHKEY NewKeyHandle
)
46 PHKEY RootKeyLocation
;
48 UNICODE_STRING SubKeyString
;
49 OBJECT_ATTRIBUTES ObjectAttributes
;
53 /* Check which root key to open */
55 RootKeyLocation
= &Wow64ExecOptionsKey
;
57 RootKeyLocation
= &ImageExecOptionsKey
;
59 /* Get the current key */
60 RootKey
= *RootKeyLocation
;
62 /* Setup the object attributes */
63 InitializeObjectAttributes(&ObjectAttributes
,
65 &Wow64OptionsString
: &ImageExecOptionsString
,
70 /* Open the root key */
71 Status
= ZwOpenKey(&RootKey
, KEY_ENUMERATE_SUB_KEYS
, &ObjectAttributes
);
72 if (NT_SUCCESS(Status
))
74 /* Write the key handle */
75 if (_InterlockedCompareExchange((LONG
*)RootKeyLocation
, (LONG
)RootKey
, 0) != 0)
77 /* Someone already opened it, use it instead */
79 RootKey
= *RootKeyLocation
;
82 /* Extract the name */
83 SubKeyString
= *SubKey
;
84 p1
= (PWCHAR
)((ULONG_PTR
)SubKeyString
.Buffer
+ SubKeyString
.Length
);
85 while (SubKey
->Length
)
87 if (p1
[-1] == L
'\\') break;
89 SubKeyString
.Length
-= sizeof(*p1
);
91 SubKeyString
.Buffer
= p1
;
92 SubKeyString
.Length
= SubKeyString
.MaximumLength
- SubKeyString
.Length
- sizeof(WCHAR
);
94 /* Setup the object attributes */
95 InitializeObjectAttributes(&ObjectAttributes
,
101 /* Open the setting key */
102 Status
= ZwOpenKey((PHANDLE
)NewKeyHandle
, GENERIC_READ
, &ObjectAttributes
);
105 /* Return to caller */
114 LdrQueryImageFileKeyOption(IN HKEY KeyHandle
,
119 OUT PULONG ReturnedLength OPTIONAL
)
122 UNICODE_STRING ValueNameString
, IntegerString
;
123 ULONG KeyInfoSize
, ResultSize
;
124 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)&KeyInfo
;
125 BOOLEAN FreeHeap
= FALSE
;
128 /* Build a string for the value name */
129 Status
= RtlInitUnicodeStringEx(&ValueNameString
, ValueName
);
130 if (!NT_SUCCESS(Status
)) return Status
;
132 /* Query the value */
133 Status
= NtQueryValueKey(KeyHandle
,
135 KeyValuePartialInformation
,
139 if (Status
== STATUS_BUFFER_OVERFLOW
)
141 /* Our local buffer wasn't enough, allocate one */
142 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
143 KeyValueInformation
->DataLength
;
144 KeyValueInformation
= RtlAllocateHeap(RtlGetProcessHeap(),
149 /* Give up this time */
150 Status
= STATUS_NO_MEMORY
;
154 Status
= NtQueryValueKey(KeyHandle
,
156 KeyValuePartialInformation
,
163 /* Check for success */
164 if (NT_SUCCESS(Status
))
166 /* Handle binary data */
167 if (KeyValueInformation
->Type
== REG_BINARY
)
170 if ((Buffer
) && (KeyValueInformation
->DataLength
<= BufferSize
))
172 /* Copy into buffer */
173 RtlMoveMemory(Buffer
,
174 &KeyValueInformation
->Data
,
175 KeyValueInformation
->DataLength
);
179 Status
= STATUS_BUFFER_OVERFLOW
;
182 /* Copy the result length */
183 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
185 else if (KeyValueInformation
->Type
== REG_DWORD
)
187 /* Check for valid type */
188 if (KeyValueInformation
->Type
!= Type
)
191 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
197 (BufferSize
== sizeof(ULONG
)) &&
198 (KeyValueInformation
->DataLength
<= BufferSize
))
200 /* Copy into buffer */
201 RtlMoveMemory(Buffer
,
202 &KeyValueInformation
->Data
,
203 KeyValueInformation
->DataLength
);
207 Status
= STATUS_BUFFER_OVERFLOW
;
210 /* Copy the result length */
211 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
214 else if (KeyValueInformation
->Type
!= REG_SZ
)
216 /* We got something weird */
217 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
221 /* String, check what you requested */
222 if (Type
== REG_DWORD
)
225 if (BufferSize
!= sizeof(ULONG
))
229 Status
= STATUS_INFO_LENGTH_MISMATCH
;
233 /* OK, we know what you want... */
234 IntegerString
.Buffer
= (PWSTR
)KeyValueInformation
->Data
;
235 IntegerString
.Length
= KeyValueInformation
->DataLength
-
237 IntegerString
.MaximumLength
= KeyValueInformation
->DataLength
;
238 Status
= RtlUnicodeStringToInteger(&IntegerString
, 0, (PULONG
)Buffer
);
244 if (KeyValueInformation
->DataLength
> BufferSize
)
247 Status
= STATUS_BUFFER_OVERFLOW
;
252 BufferSize
= KeyValueInformation
->DataLength
;
255 /* Copy the string */
256 RtlMoveMemory(Buffer
, &KeyValueInformation
->Data
, BufferSize
);
259 /* Copy the result length */
260 if (ReturnedLength
) *ReturnedLength
= KeyValueInformation
->DataLength
;
264 /* Check if buffer was in heap */
265 if (FreeHeap
) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation
);
267 /* Close key and return */
277 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey
,
282 OUT PULONG ReturnedLength OPTIONAL
,
288 /* Open a handle to the key */
289 Status
= LdrOpenImageFileOptionsKey(SubKey
, Wow64
, &KeyHandle
);
291 /* Check for success */
292 if (NT_SUCCESS(Status
))
295 Status
= LdrQueryImageFileKeyOption(KeyHandle
,
306 /* Return to caller */
315 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey
,
320 OUT PULONG ReturnedLength OPTIONAL
)
322 /* Call the newer function */
323 return LdrQueryImageFileExecutionOptionsEx(SubKey
,
334 LdrpInitializeTls(VOID
)
336 PLIST_ENTRY NextEntry
, ListHead
;
337 PLDR_DATA_TABLE_ENTRY LdrEntry
;
338 PIMAGE_TLS_DIRECTORY TlsDirectory
;
339 PLDRP_TLS_DATA TlsData
;
342 /* Initialize the TLS List */
343 InitializeListHead(&LdrpTlsList
);
345 /* Loop all the modules */
346 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
347 NextEntry
= ListHead
->Flink
;
348 while (ListHead
!= NextEntry
)
351 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
352 NextEntry
= NextEntry
->Flink
;
354 /* Get the TLS directory */
355 TlsDirectory
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
357 IMAGE_DIRECTORY_ENTRY_TLS
,
360 /* Check if we have a directory */
361 if (!TlsDirectory
) continue;
363 /* Check if the image has TLS */
364 if (!LdrpImageHasTls
) LdrpImageHasTls
= TRUE
;
366 /* Show debug message */
369 DPRINT1("LDR: Tls Found in %wZ at %p\n",
370 &LdrEntry
->BaseDllName
,
374 /* Allocate an entry */
375 TlsData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA
));
376 if (!TlsData
) return STATUS_NO_MEMORY
;
378 /* Lock the DLL and mark it for TLS Usage */
379 LdrEntry
->LoadCount
= -1;
380 LdrEntry
->TlsIndex
= -1;
382 /* Save the cached TLS data */
383 TlsData
->TlsDirectory
= *TlsDirectory
;
384 InsertTailList(&LdrpTlsList
, &TlsData
->TlsLinks
);
386 /* Update the index */
387 *(PLONG
)TlsData
->TlsDirectory
.AddressOfIndex
= LdrpNumberOfTlsEntries
;
388 TlsData
->TlsDirectory
.Characteristics
= LdrpNumberOfTlsEntries
++;
391 /* Done setting up TLS, allocate entries */
392 return LdrpAllocateTls();
397 LdrpAllocateTls(VOID
)
399 PTEB Teb
= NtCurrentTeb();
400 PLIST_ENTRY NextEntry
, ListHead
;
401 PLDRP_TLS_DATA TlsData
;
405 /* Check if we have any entries */
406 if (LdrpNumberOfTlsEntries
)
409 /* Allocate the vector array */
410 TlsVector
= RtlAllocateHeap(RtlGetProcessHeap(),
412 LdrpNumberOfTlsEntries
* sizeof(PVOID
));
413 if (!TlsVector
) return STATUS_NO_MEMORY
;
414 Teb
->ThreadLocalStoragePointer
= TlsVector
;
416 /* Loop the TLS Array */
417 ListHead
= &LdrpTlsList
;
418 NextEntry
= ListHead
->Flink
;
419 while (NextEntry
!= ListHead
)
422 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
423 NextEntry
= NextEntry
->Flink
;
425 /* Allocate this vector */
426 TlsDataSize
= TlsData
->TlsDirectory
.EndAddressOfRawData
-
427 TlsData
->TlsDirectory
.StartAddressOfRawData
;
428 TlsVector
[TlsData
->TlsDirectory
.Characteristics
] = RtlAllocateHeap(RtlGetProcessHeap(),
431 if (!TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
434 return STATUS_NO_MEMORY
;
437 /* Show debug message */
440 DPRINT1("LDR: TlsVector %x Index %d = %x copied from %x to %x\n",
442 TlsData
->TlsDirectory
.Characteristics
,
443 &TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
444 TlsData
->TlsDirectory
.StartAddressOfRawData
,
445 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
449 RtlCopyMemory(TlsVector
[TlsData
->TlsDirectory
.Characteristics
],
450 (PVOID
)TlsData
->TlsDirectory
.StartAddressOfRawData
,
455 return STATUS_SUCCESS
;
462 PLIST_ENTRY ListHead
, NextEntry
;
463 PLDRP_TLS_DATA TlsData
;
465 PTEB Teb
= NtCurrentTeb();
467 /* Get a pointer to the vector array */
468 TlsVector
= Teb
->ThreadLocalStoragePointer
;
469 if (!TlsVector
) return;
471 /* Loop through it */
472 ListHead
= &LdrpTlsList
;
473 NextEntry
= ListHead
->Flink
;
474 while (NextEntry
!= ListHead
)
476 TlsData
= CONTAINING_RECORD(NextEntry
, LDRP_TLS_DATA
, TlsLinks
);
477 NextEntry
= NextEntry
->Flink
;
479 /* Free each entry */
480 if (TlsVector
[TlsData
->TlsDirectory
.Characteristics
])
482 RtlFreeHeap(RtlGetProcessHeap(),
484 TlsVector
[TlsData
->TlsDirectory
.Characteristics
]);
488 /* Free the array itself */
489 RtlFreeHeap(RtlGetProcessHeap(),