dc0a3701cc6d4fb2c24c33136170fb8cf1dde90d
[reactos.git] / 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 #include <compat_undoc.h>
14 #include <compatguid_undoc.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* GLOBALS *******************************************************************/
21
22 HANDLE ImageExecOptionsKey;
23 HANDLE Wow64ExecOptionsKey;
24 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
25 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
26 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
27
28 BOOLEAN LdrpInLdrInit;
29 LONG LdrpProcessInitialized;
30 BOOLEAN LdrpLoaderLockInit;
31 BOOLEAN LdrpLdrDatabaseIsSetup;
32 BOOLEAN LdrpShutdownInProgress;
33 HANDLE LdrpShutdownThreadId;
34
35 BOOLEAN LdrpDllValidation;
36
37 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
38 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
39 WCHAR StringBuffer[156];
40 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
41 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
42 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
43
44 RTL_BITMAP TlsBitMap;
45 RTL_BITMAP TlsExpansionBitMap;
46 RTL_BITMAP FlsBitMap;
47 BOOLEAN LdrpImageHasTls;
48 LIST_ENTRY LdrpTlsList;
49 ULONG LdrpNumberOfTlsEntries;
50 ULONG LdrpNumberOfProcessors;
51 PVOID NtDllBase;
52 extern LARGE_INTEGER RtlpTimeout;
53 BOOLEAN RtlpTimeoutDisable;
54 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
55 LIST_ENTRY LdrpDllNotificationList;
56 HANDLE LdrpKnownDllObjectDirectory;
57 UNICODE_STRING LdrpKnownDllPath;
58 WCHAR LdrpKnownDllPathBuffer[128];
59 UNICODE_STRING LdrpDefaultPath;
60
61 PEB_LDR_DATA PebLdr;
62
63 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
64 RTL_CRITICAL_SECTION LdrpLoaderLock =
65 {
66 &LdrpLoaderLockDebug,
67 -1,
68 0,
69 0,
70 0,
71 0
72 };
73 RTL_CRITICAL_SECTION FastPebLock;
74
75 BOOLEAN ShowSnaps;
76
77 ULONG LdrpFatalHardErrorCount;
78 ULONG LdrpActiveUnloadCount;
79
80 //extern LIST_ENTRY RtlCriticalSectionList;
81
82 VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
83 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
84 VOID NTAPI RtlInitializeHeapManager(VOID);
85
86 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
87 ULONG RtlpShutdownProcessFlags; // TODO: Use it
88
89 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
90 void actctx_init(void);
91 extern BOOLEAN RtlpUse16ByteSLists;
92
93 #ifdef _WIN64
94 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
95 #else
96 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
97 #endif
98
99 /* FUNCTIONS *****************************************************************/
100
101 /*
102 * @implemented
103 */
104 NTSTATUS
105 NTAPI
106 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
107 IN BOOLEAN Wow64,
108 OUT PHANDLE NewKeyHandle)
109 {
110 PHANDLE RootKeyLocation;
111 HANDLE RootKey;
112 UNICODE_STRING SubKeyString;
113 OBJECT_ATTRIBUTES ObjectAttributes;
114 NTSTATUS Status;
115 PWCHAR p1;
116
117 /* Check which root key to open */
118 if (Wow64)
119 RootKeyLocation = &Wow64ExecOptionsKey;
120 else
121 RootKeyLocation = &ImageExecOptionsKey;
122
123 /* Get the current key */
124 RootKey = *RootKeyLocation;
125
126 /* Setup the object attributes */
127 InitializeObjectAttributes(&ObjectAttributes,
128 Wow64 ?
129 &Wow64OptionsString : &ImageExecOptionsString,
130 OBJ_CASE_INSENSITIVE,
131 NULL,
132 NULL);
133
134 /* Open the root key */
135 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
136 if (NT_SUCCESS(Status))
137 {
138 /* Write the key handle */
139 if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
140 {
141 /* Someone already opened it, use it instead */
142 NtClose(RootKey);
143 RootKey = *RootKeyLocation;
144 }
145
146 /* Extract the name */
147 SubKeyString = *SubKey;
148 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
149 while (SubKeyString.Length)
150 {
151 if (p1[-1] == L'\\') break;
152 p1--;
153 SubKeyString.Length -= sizeof(*p1);
154 }
155 SubKeyString.Buffer = p1;
156 SubKeyString.Length = SubKey->Length - SubKeyString.Length;
157
158 /* Setup the object attributes */
159 InitializeObjectAttributes(&ObjectAttributes,
160 &SubKeyString,
161 OBJ_CASE_INSENSITIVE,
162 RootKey,
163 NULL);
164
165 /* Open the setting key */
166 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
167 }
168
169 /* Return to caller */
170 return Status;
171 }
172
173 /*
174 * @implemented
175 */
176 NTSTATUS
177 NTAPI
178 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
179 IN PCWSTR ValueName,
180 IN ULONG Type,
181 OUT PVOID Buffer,
182 IN ULONG BufferSize,
183 OUT PULONG ReturnedLength OPTIONAL)
184 {
185 ULONG KeyInfo[256];
186 UNICODE_STRING ValueNameString, IntegerString;
187 ULONG KeyInfoSize, ResultSize;
188 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
189 BOOLEAN FreeHeap = FALSE;
190 NTSTATUS Status;
191
192 /* Build a string for the value name */
193 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
194 if (!NT_SUCCESS(Status)) return Status;
195
196 /* Query the value */
197 Status = ZwQueryValueKey(KeyHandle,
198 &ValueNameString,
199 KeyValuePartialInformation,
200 KeyValueInformation,
201 sizeof(KeyInfo),
202 &ResultSize);
203 if (Status == STATUS_BUFFER_OVERFLOW)
204 {
205 /* Our local buffer wasn't enough, allocate one */
206 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
207 KeyValueInformation->DataLength;
208 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
209 0,
210 KeyInfoSize);
211 if (KeyValueInformation != NULL)
212 {
213 /* Try again */
214 Status = ZwQueryValueKey(KeyHandle,
215 &ValueNameString,
216 KeyValuePartialInformation,
217 KeyValueInformation,
218 KeyInfoSize,
219 &ResultSize);
220 FreeHeap = TRUE;
221 }
222 else
223 {
224 /* Give up this time */
225 Status = STATUS_NO_MEMORY;
226 }
227 }
228
229 /* Check for success */
230 if (NT_SUCCESS(Status))
231 {
232 /* Handle binary data */
233 if (KeyValueInformation->Type == REG_BINARY)
234 {
235 /* Check validity */
236 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
237 {
238 /* Copy into buffer */
239 RtlMoveMemory(Buffer,
240 &KeyValueInformation->Data,
241 KeyValueInformation->DataLength);
242 }
243 else
244 {
245 Status = STATUS_BUFFER_OVERFLOW;
246 }
247
248 /* Copy the result length */
249 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
250 }
251 else if (KeyValueInformation->Type == REG_DWORD)
252 {
253 /* Check for valid type */
254 if (KeyValueInformation->Type != Type)
255 {
256 /* Error */
257 Status = STATUS_OBJECT_TYPE_MISMATCH;
258 }
259 else
260 {
261 /* Check validity */
262 if ((Buffer) &&
263 (BufferSize == sizeof(ULONG)) &&
264 (KeyValueInformation->DataLength <= BufferSize))
265 {
266 /* Copy into buffer */
267 RtlMoveMemory(Buffer,
268 &KeyValueInformation->Data,
269 KeyValueInformation->DataLength);
270 }
271 else
272 {
273 Status = STATUS_BUFFER_OVERFLOW;
274 }
275
276 /* Copy the result length */
277 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
278 }
279 }
280 else if (KeyValueInformation->Type != REG_SZ)
281 {
282 /* We got something weird */
283 Status = STATUS_OBJECT_TYPE_MISMATCH;
284 }
285 else
286 {
287 /* String, check what you requested */
288 if (Type == REG_DWORD)
289 {
290 /* Validate */
291 if (BufferSize != sizeof(ULONG))
292 {
293 /* Invalid size */
294 BufferSize = 0;
295 Status = STATUS_INFO_LENGTH_MISMATCH;
296 }
297 else
298 {
299 /* OK, we know what you want... */
300 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
301 IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
302 sizeof(WCHAR);
303 IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
304 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
305 }
306 }
307 else
308 {
309 /* Validate */
310 if (KeyValueInformation->DataLength > BufferSize)
311 {
312 /* Invalid */
313 Status = STATUS_BUFFER_OVERFLOW;
314 }
315 else
316 {
317 /* Set the size */
318 BufferSize = KeyValueInformation->DataLength;
319 }
320
321 /* Copy the string */
322 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
323 }
324
325 /* Copy the result length */
326 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
327 }
328 }
329
330 /* Check if buffer was in heap */
331 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
332
333 /* Return status */
334 return Status;
335 }
336
337 /*
338 * @implemented
339 */
340 NTSTATUS
341 NTAPI
342 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
343 IN PCWSTR ValueName,
344 IN ULONG Type,
345 OUT PVOID Buffer,
346 IN ULONG BufferSize,
347 OUT PULONG ReturnedLength OPTIONAL,
348 IN BOOLEAN Wow64)
349 {
350 NTSTATUS Status;
351 HANDLE KeyHandle;
352
353 /* Open a handle to the key */
354 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
355
356 /* Check for success */
357 if (NT_SUCCESS(Status))
358 {
359 /* Query the data */
360 Status = LdrQueryImageFileKeyOption(KeyHandle,
361 ValueName,
362 Type,
363 Buffer,
364 BufferSize,
365 ReturnedLength);
366
367 /* Close the key */
368 NtClose(KeyHandle);
369 }
370
371 /* Return to caller */
372 return Status;
373 }
374
375 /*
376 * @implemented
377 */
378 NTSTATUS
379 NTAPI
380 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
381 IN PCWSTR ValueName,
382 IN ULONG Type,
383 OUT PVOID Buffer,
384 IN ULONG BufferSize,
385 OUT PULONG ReturnedLength OPTIONAL)
386 {
387 /* Call the newer function */
388 return LdrQueryImageFileExecutionOptionsEx(SubKey,
389 ValueName,
390 Type,
391 Buffer,
392 BufferSize,
393 ReturnedLength,
394 FALSE);
395 }
396
397 VOID
398 NTAPI
399 LdrpEnsureLoaderLockIsHeld(VOID)
400 {
401 // Ignored atm
402 }
403
404 PVOID
405 NTAPI
406 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
407 {
408 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
409 ULONG DirSize;
410 PVOID Cookie = NULL;
411
412 /* Check NT header first */
413 if (!RtlImageNtHeader(BaseAddress)) return NULL;
414
415 /* Get the pointer to the config directory */
416 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
417 TRUE,
418 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
419 &DirSize);
420
421 /* Check for sanity */
422 if (!ConfigDir ||
423 (DirSize != 64 && ConfigDir->Size != DirSize) ||
424 (ConfigDir->Size < 0x48))
425 return NULL;
426
427 /* Now get the cookie */
428 Cookie = (PVOID)ConfigDir->SecurityCookie;
429
430 /* Check this cookie */
431 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
432 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
433 {
434 Cookie = NULL;
435 }
436
437 /* Return validated security cookie */
438 return Cookie;
439 }
440
441 PVOID
442 NTAPI
443 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
444 {
445 PULONG_PTR Cookie;
446 LARGE_INTEGER Counter;
447 ULONG_PTR NewCookie;
448
449 /* Fetch address of the cookie */
450 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
451
452 if (Cookie)
453 {
454 /* Check if it's a default one */
455 if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
456 (*Cookie == 0xBB40))
457 {
458 /* Make up a cookie from a bunch of values which may uniquely represent
459 current moment of time, environment, etc */
460 NtQueryPerformanceCounter(&Counter, NULL);
461
462 NewCookie = Counter.LowPart ^ Counter.HighPart;
463 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
464 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
465
466 /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
467 while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
468 {
469 YieldProcessor();
470 };
471
472 /* Calculate the milliseconds value and xor it to the cookie */
473 NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
474 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
475
476 /* Make the cookie 16bit if necessary */
477 if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
478
479 /* If the result is 0 or the same as we got, just subtract one from the existing value
480 and that's it */
481 if ((NewCookie == 0) || (NewCookie == *Cookie))
482 {
483 NewCookie = *Cookie - 1;
484 }
485
486 /* Set the new cookie value */
487 *Cookie = NewCookie;
488 }
489 }
490
491 return Cookie;
492 }
493
494 VOID
495 NTAPI
496 LdrpInitializeThread(IN PCONTEXT Context)
497 {
498 PPEB Peb = NtCurrentPeb();
499 PLDR_DATA_TABLE_ENTRY LdrEntry;
500 PLIST_ENTRY NextEntry, ListHead;
501 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
502 NTSTATUS Status;
503 PVOID EntryPoint;
504
505 DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
506 &LdrpImageEntry->BaseDllName,
507 NtCurrentTeb()->RealClientId.UniqueProcess,
508 NtCurrentTeb()->RealClientId.UniqueThread);
509
510 /* Allocate an Activation Context Stack */
511 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
512 Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
513 if (!NT_SUCCESS(Status))
514 {
515 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
516 }
517
518 /* Make sure we are not shutting down */
519 if (LdrpShutdownInProgress) return;
520
521 /* Allocate TLS */
522 LdrpAllocateTls();
523
524 /* Start at the beginning */
525 ListHead = &Peb->Ldr->InMemoryOrderModuleList;
526 NextEntry = ListHead->Flink;
527 while (NextEntry != ListHead)
528 {
529 /* Get the current entry */
530 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
531
532 /* Make sure it's not ourselves */
533 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
534 {
535 /* Check if we should call */
536 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
537 {
538 /* Get the entrypoint */
539 EntryPoint = LdrEntry->EntryPoint;
540
541 /* Check if we are ready to call it */
542 if ((EntryPoint) &&
543 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
544 (LdrEntry->Flags & LDRP_IMAGE_DLL))
545 {
546 /* Set up the Act Ctx */
547 ActCtx.Size = sizeof(ActCtx);
548 ActCtx.Format = 1;
549 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
550
551 /* Activate the ActCtx */
552 RtlActivateActivationContextUnsafeFast(&ActCtx,
553 LdrEntry->EntryPointActivationContext);
554
555 /* Check if it has TLS */
556 if (LdrEntry->TlsIndex)
557 {
558 /* Make sure we're not shutting down */
559 if (!LdrpShutdownInProgress)
560 {
561 /* Call TLS */
562 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
563 }
564 }
565
566 /* Make sure we're not shutting down */
567 if (!LdrpShutdownInProgress)
568 {
569 /* Call the Entrypoint */
570 DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
571 &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
572 NtCurrentTeb()->RealClientId.UniqueProcess,
573 NtCurrentTeb()->RealClientId.UniqueThread);
574 LdrpCallInitRoutine(LdrEntry->EntryPoint,
575 LdrEntry->DllBase,
576 DLL_THREAD_ATTACH,
577 NULL);
578 }
579
580 /* Deactivate the ActCtx */
581 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
582 }
583 }
584 }
585
586 /* Next entry */
587 NextEntry = NextEntry->Flink;
588 }
589
590 /* Check for TLS */
591 if (LdrpImageHasTls && !LdrpShutdownInProgress)
592 {
593 /* Set up the Act Ctx */
594 ActCtx.Size = sizeof(ActCtx);
595 ActCtx.Format = 1;
596 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
597
598 /* Activate the ActCtx */
599 RtlActivateActivationContextUnsafeFast(&ActCtx,
600 LdrpImageEntry->EntryPointActivationContext);
601
602 /* Do TLS callbacks */
603 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
604
605 /* Deactivate the ActCtx */
606 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
607 }
608
609 DPRINT("LdrpInitializeThread() done\n");
610 }
611
612 NTSTATUS
613 NTAPI
614 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
615 {
616 PLDR_DATA_TABLE_ENTRY LocalArray[16];
617 PLIST_ENTRY ListHead;
618 PLIST_ENTRY NextEntry;
619 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
620 PVOID EntryPoint;
621 ULONG Count, i;
622 //ULONG BreakOnInit;
623 NTSTATUS Status = STATUS_SUCCESS;
624 PPEB Peb = NtCurrentPeb();
625 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
626 ULONG BreakOnDllLoad;
627 PTEB OldTldTeb;
628 BOOLEAN DllStatus;
629
630 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
631 &LdrpImageEntry->BaseDllName,
632 NtCurrentTeb()->RealClientId.UniqueProcess,
633 NtCurrentTeb()->RealClientId.UniqueThread);
634
635 /* Check the Loader Lock */
636 LdrpEnsureLoaderLockIsHeld();
637
638 /* Get the number of entries to call */
639 if ((Count = LdrpClearLoadInProgress()))
640 {
641 /* Check if we can use our local buffer */
642 if (Count > 16)
643 {
644 /* Allocate space for all the entries */
645 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
646 0,
647 Count * sizeof(*LdrRootEntry));
648 if (!LdrRootEntry) return STATUS_NO_MEMORY;
649 }
650 else
651 {
652 /* Use our local array */
653 LdrRootEntry = LocalArray;
654 }
655 }
656 else
657 {
658 /* Don't need one */
659 LdrRootEntry = NULL;
660 }
661
662 /* Show debug message */
663 if (ShowSnaps)
664 {
665 DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
666 NtCurrentTeb()->RealClientId.UniqueThread,
667 NtCurrentTeb()->RealClientId.UniqueProcess,
668 &Peb->ProcessParameters->ImagePathName);
669 }
670
671 /* Loop in order */
672 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
673 NextEntry = ListHead->Flink;
674 i = 0;
675 while (NextEntry != ListHead)
676 {
677 /* Get the Data Entry */
678 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
679
680 /* Check if we have a Root Entry */
681 if (LdrRootEntry)
682 {
683 /* Check flags */
684 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
685 {
686 /* Setup the Cookie for the DLL */
687 LdrpInitSecurityCookie(LdrEntry);
688
689 /* Check for valid entrypoint */
690 if (LdrEntry->EntryPoint)
691 {
692 /* Write in array */
693 ASSERT(i < Count);
694 LdrRootEntry[i] = LdrEntry;
695
696 /* Display debug message */
697 if (ShowSnaps)
698 {
699 DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
700 NtCurrentTeb()->RealClientId.UniqueThread,
701 NtCurrentTeb()->RealClientId.UniqueProcess,
702 &LdrEntry->FullDllName,
703 LdrEntry->EntryPoint);
704 }
705 i++;
706 }
707 }
708 }
709
710 /* Set the flag */
711 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
712 NextEntry = NextEntry->Flink;
713 }
714
715 /* If we got a context, then we have to call Kernel32 for TS support */
716 if (Context)
717 {
718 /* Check if we have one */
719 //if (Kernel32ProcessInitPostImportfunction)
720 //{
721 /* Call it */
722 //Kernel32ProcessInitPostImportfunction();
723 //}
724
725 /* Clear it */
726 //Kernel32ProcessInitPostImportfunction = NULL;
727 //UNIMPLEMENTED;
728 }
729
730 /* No root entry? return */
731 if (!LdrRootEntry) return STATUS_SUCCESS;
732
733 /* Set the TLD TEB */
734 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
735 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
736
737 /* Loop */
738 i = 0;
739 while (i < Count)
740 {
741 /* Get an entry */
742 LdrEntry = LdrRootEntry[i];
743
744 /* FIXME: Verify NX Compat */
745
746 /* Move to next entry */
747 i++;
748
749 /* Get its entrypoint */
750 EntryPoint = LdrEntry->EntryPoint;
751
752 /* Are we being debugged? */
753 BreakOnDllLoad = 0;
754 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
755 {
756 /* Check if we should break on load */
757 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
758 L"BreakOnDllLoad",
759 REG_DWORD,
760 &BreakOnDllLoad,
761 sizeof(ULONG),
762 NULL);
763 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
764
765 /* Reset status back to STATUS_SUCCESS */
766 Status = STATUS_SUCCESS;
767 }
768
769 /* Break if aksed */
770 if (BreakOnDllLoad)
771 {
772 /* Check if we should show a message */
773 if (ShowSnaps)
774 {
775 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
776 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
777 }
778
779 /* Break in debugger */
780 DbgBreakPoint();
781 }
782
783 /* Make sure we have an entrypoint */
784 if (EntryPoint)
785 {
786 /* Save the old Dll Initializer and write the current one */
787 OldInitializer = LdrpCurrentDllInitializer;
788 LdrpCurrentDllInitializer = LdrEntry;
789
790 /* Set up the Act Ctx */
791 ActCtx.Size = sizeof(ActCtx);
792 ActCtx.Format = 1;
793 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
794
795 /* Activate the ActCtx */
796 RtlActivateActivationContextUnsafeFast(&ActCtx,
797 LdrEntry->EntryPointActivationContext);
798
799 /* Check if it has TLS */
800 if (LdrEntry->TlsIndex && Context)
801 {
802 /* Call TLS */
803 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_ATTACH);
804 }
805
806 /* Call the Entrypoint */
807 if (ShowSnaps)
808 {
809 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
810 &LdrEntry->BaseDllName, EntryPoint);
811 }
812 DllStatus = LdrpCallInitRoutine(EntryPoint,
813 LdrEntry->DllBase,
814 DLL_PROCESS_ATTACH,
815 Context);
816
817 /* Deactivate the ActCtx */
818 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
819
820 /* Save the Current DLL Initializer */
821 LdrpCurrentDllInitializer = OldInitializer;
822
823 /* Mark the entry as processed */
824 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
825
826 /* Fail if DLL init failed */
827 if (!DllStatus)
828 {
829 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
830 &LdrEntry->BaseDllName, EntryPoint);
831
832 Status = STATUS_DLL_INIT_FAILED;
833 goto Quickie;
834 }
835 }
836 }
837
838 /* Loop in order */
839 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
840 NextEntry = NextEntry->Flink;
841 while (NextEntry != ListHead)
842 {
843 /* Get the Data Entry */
844 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
845
846 /* FIXME: Verify NX Compat */
847 // LdrpCheckNXCompatibility()
848
849 /* Next entry */
850 NextEntry = NextEntry->Flink;
851 }
852
853 /* Check for TLS */
854 if (LdrpImageHasTls && Context)
855 {
856 /* Set up the Act Ctx */
857 ActCtx.Size = sizeof(ActCtx);
858 ActCtx.Format = 1;
859 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
860
861 /* Activate the ActCtx */
862 RtlActivateActivationContextUnsafeFast(&ActCtx,
863 LdrpImageEntry->EntryPointActivationContext);
864
865 /* Do TLS callbacks */
866 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_ATTACH);
867
868 /* Deactivate the ActCtx */
869 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
870 }
871
872 Quickie:
873 /* Restore old TEB */
874 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
875
876 /* Check if the array is in the heap */
877 if (LdrRootEntry != LocalArray)
878 {
879 /* Free the array */
880 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
881 }
882
883 /* Return to caller */
884 DPRINT("LdrpRunInitializeRoutines() done\n");
885 return Status;
886 }
887
888 /*
889 * @implemented
890 */
891 NTSTATUS
892 NTAPI
893 LdrShutdownProcess(VOID)
894 {
895 PPEB Peb = NtCurrentPeb();
896 PLDR_DATA_TABLE_ENTRY LdrEntry;
897 PLIST_ENTRY NextEntry, ListHead;
898 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
899 PVOID EntryPoint;
900
901 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
902 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
903
904 /* Tell the Shim Engine */
905 if (g_ShimsEnabled)
906 {
907 VOID(NTAPI *SE_ProcessDying)();
908 SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
909 SE_ProcessDying();
910 }
911
912 /* Tell the world */
913 if (ShowSnaps)
914 {
915 DPRINT1("\n");
916 }
917
918 /* Set the shutdown variables */
919 LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
920 LdrpShutdownInProgress = TRUE;
921
922 /* Enter the Loader Lock */
923 RtlEnterCriticalSection(&LdrpLoaderLock);
924
925 /* Cleanup trace logging data (Etw) */
926 if (SharedUserData->TraceLogging)
927 {
928 /* FIXME */
929 DPRINT1("We don't support Etw yet.\n");
930 }
931
932 /* Start at the end */
933 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
934 NextEntry = ListHead->Blink;
935 while (NextEntry != ListHead)
936 {
937 /* Get the current entry */
938 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
939 NextEntry = NextEntry->Blink;
940
941 /* Make sure it's not ourselves */
942 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
943 {
944 /* Get the entrypoint */
945 EntryPoint = LdrEntry->EntryPoint;
946
947 /* Check if we are ready to call it */
948 if (EntryPoint &&
949 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
950 LdrEntry->Flags)
951 {
952 /* Set up the Act Ctx */
953 ActCtx.Size = sizeof(ActCtx);
954 ActCtx.Format = 1;
955 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
956
957 /* Activate the ActCtx */
958 RtlActivateActivationContextUnsafeFast(&ActCtx,
959 LdrEntry->EntryPointActivationContext);
960
961 /* Check if it has TLS */
962 if (LdrEntry->TlsIndex)
963 {
964 /* Call TLS */
965 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_PROCESS_DETACH);
966 }
967
968 /* Call the Entrypoint */
969 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
970 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
971 LdrpCallInitRoutine(EntryPoint,
972 LdrEntry->DllBase,
973 DLL_PROCESS_DETACH,
974 (PVOID)1);
975
976 /* Deactivate the ActCtx */
977 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
978 }
979 }
980 }
981
982 /* Check for TLS */
983 if (LdrpImageHasTls)
984 {
985 /* Set up the Act Ctx */
986 ActCtx.Size = sizeof(ActCtx);
987 ActCtx.Format = 1;
988 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
989
990 /* Activate the ActCtx */
991 RtlActivateActivationContextUnsafeFast(&ActCtx,
992 LdrpImageEntry->EntryPointActivationContext);
993
994 /* Do TLS callbacks */
995 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_PROCESS_DETACH);
996
997 /* Deactivate the ActCtx */
998 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
999 }
1000
1001 /* FIXME: Do Heap detection and Etw final shutdown */
1002
1003 /* Release the lock */
1004 RtlLeaveCriticalSection(&LdrpLoaderLock);
1005 DPRINT("LdrpShutdownProcess() done\n");
1006
1007 return STATUS_SUCCESS;
1008 }
1009
1010 /*
1011 * @implemented
1012 */
1013 NTSTATUS
1014 NTAPI
1015 LdrShutdownThread(VOID)
1016 {
1017 PPEB Peb = NtCurrentPeb();
1018 PTEB Teb = NtCurrentTeb();
1019 PLDR_DATA_TABLE_ENTRY LdrEntry;
1020 PLIST_ENTRY NextEntry, ListHead;
1021 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1022 PVOID EntryPoint;
1023
1024 DPRINT("LdrShutdownThread() called for %wZ\n",
1025 &LdrpImageEntry->BaseDllName);
1026
1027 /* Cleanup trace logging data (Etw) */
1028 if (SharedUserData->TraceLogging)
1029 {
1030 /* FIXME */
1031 DPRINT1("We don't support Etw yet.\n");
1032 }
1033
1034 /* Get the Ldr Lock */
1035 RtlEnterCriticalSection(&LdrpLoaderLock);
1036
1037 /* Start at the end */
1038 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1039 NextEntry = ListHead->Blink;
1040 while (NextEntry != ListHead)
1041 {
1042 /* Get the current entry */
1043 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1044 NextEntry = NextEntry->Blink;
1045
1046 /* Make sure it's not ourselves */
1047 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1048 {
1049 /* Check if we should call */
1050 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1051 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1052 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1053 {
1054 /* Get the entrypoint */
1055 EntryPoint = LdrEntry->EntryPoint;
1056
1057 /* Check if we are ready to call it */
1058 if (EntryPoint)
1059 {
1060 /* Set up the Act Ctx */
1061 ActCtx.Size = sizeof(ActCtx);
1062 ActCtx.Format = 1;
1063 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1064
1065 /* Activate the ActCtx */
1066 RtlActivateActivationContextUnsafeFast(&ActCtx,
1067 LdrEntry->EntryPointActivationContext);
1068
1069 /* Check if it has TLS */
1070 if (LdrEntry->TlsIndex)
1071 {
1072 /* Make sure we're not shutting down */
1073 if (!LdrpShutdownInProgress)
1074 {
1075 /* Call TLS */
1076 LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_DETACH);
1077 }
1078 }
1079
1080 /* Make sure we're not shutting down */
1081 if (!LdrpShutdownInProgress)
1082 {
1083 /* Call the Entrypoint */
1084 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1085 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1086 LdrpCallInitRoutine(EntryPoint,
1087 LdrEntry->DllBase,
1088 DLL_THREAD_DETACH,
1089 NULL);
1090 }
1091
1092 /* Deactivate the ActCtx */
1093 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1094 }
1095 }
1096 }
1097 }
1098
1099 /* Check for TLS */
1100 if (LdrpImageHasTls)
1101 {
1102 /* Set up the Act Ctx */
1103 ActCtx.Size = sizeof(ActCtx);
1104 ActCtx.Format = 1;
1105 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1106
1107 /* Activate the ActCtx */
1108 RtlActivateActivationContextUnsafeFast(&ActCtx,
1109 LdrpImageEntry->EntryPointActivationContext);
1110
1111 /* Do TLS callbacks */
1112 LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_DETACH);
1113
1114 /* Deactivate the ActCtx */
1115 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1116 }
1117
1118 /* Free TLS */
1119 LdrpFreeTls();
1120 RtlLeaveCriticalSection(&LdrpLoaderLock);
1121
1122 /* Check for expansion slots */
1123 if (Teb->TlsExpansionSlots)
1124 {
1125 /* Free expansion slots */
1126 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1127 }
1128
1129 /* Check for FLS Data */
1130 if (Teb->FlsData)
1131 {
1132 /* FIXME */
1133 DPRINT1("We don't support FLS Data yet\n");
1134 }
1135
1136 /* Check for Fiber data */
1137 if (Teb->HasFiberData)
1138 {
1139 /* Free Fiber data*/
1140 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1141 Teb->NtTib.FiberData = NULL;
1142 }
1143
1144 /* Free the activation context stack */
1145 RtlFreeThreadActivationContextStack();
1146 DPRINT("LdrShutdownThread() done\n");
1147
1148 return STATUS_SUCCESS;
1149 }
1150
1151 NTSTATUS
1152 NTAPI
1153 LdrpInitializeTls(VOID)
1154 {
1155 PLIST_ENTRY NextEntry, ListHead;
1156 PLDR_DATA_TABLE_ENTRY LdrEntry;
1157 PIMAGE_TLS_DIRECTORY TlsDirectory;
1158 PLDRP_TLS_DATA TlsData;
1159 ULONG Size;
1160
1161 /* Initialize the TLS List */
1162 InitializeListHead(&LdrpTlsList);
1163
1164 /* Loop all the modules */
1165 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1166 NextEntry = ListHead->Flink;
1167 while (ListHead != NextEntry)
1168 {
1169 /* Get the entry */
1170 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1171 NextEntry = NextEntry->Flink;
1172
1173 /* Get the TLS directory */
1174 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1175 TRUE,
1176 IMAGE_DIRECTORY_ENTRY_TLS,
1177 &Size);
1178
1179 /* Check if we have a directory */
1180 if (!TlsDirectory) continue;
1181
1182 /* Check if the image has TLS */
1183 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1184
1185 /* Show debug message */
1186 if (ShowSnaps)
1187 {
1188 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1189 &LdrEntry->BaseDllName,
1190 TlsDirectory);
1191 }
1192
1193 /* Allocate an entry */
1194 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1195 if (!TlsData) return STATUS_NO_MEMORY;
1196
1197 /* Lock the DLL and mark it for TLS Usage */
1198 LdrEntry->LoadCount = -1;
1199 LdrEntry->TlsIndex = -1;
1200
1201 /* Save the cached TLS data */
1202 TlsData->TlsDirectory = *TlsDirectory;
1203 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1204
1205 /* Update the index */
1206 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1207 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1208 }
1209
1210 /* Done setting up TLS, allocate entries */
1211 return LdrpAllocateTls();
1212 }
1213
1214 NTSTATUS
1215 NTAPI
1216 LdrpAllocateTls(VOID)
1217 {
1218 PTEB Teb = NtCurrentTeb();
1219 PLIST_ENTRY NextEntry, ListHead;
1220 PLDRP_TLS_DATA TlsData;
1221 SIZE_T TlsDataSize;
1222 PVOID *TlsVector;
1223
1224 /* Check if we have any entries */
1225 if (!LdrpNumberOfTlsEntries)
1226 return STATUS_SUCCESS;
1227
1228 /* Allocate the vector array */
1229 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1230 0,
1231 LdrpNumberOfTlsEntries * sizeof(PVOID));
1232 if (!TlsVector) return STATUS_NO_MEMORY;
1233 Teb->ThreadLocalStoragePointer = TlsVector;
1234
1235 /* Loop the TLS Array */
1236 ListHead = &LdrpTlsList;
1237 NextEntry = ListHead->Flink;
1238 while (NextEntry != ListHead)
1239 {
1240 /* Get the entry */
1241 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1242 NextEntry = NextEntry->Flink;
1243
1244 /* Allocate this vector */
1245 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1246 TlsData->TlsDirectory.StartAddressOfRawData;
1247 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1248 0,
1249 TlsDataSize);
1250 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1251 {
1252 /* Out of memory */
1253 return STATUS_NO_MEMORY;
1254 }
1255
1256 /* Show debug message */
1257 if (ShowSnaps)
1258 {
1259 DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1260 TlsVector,
1261 TlsData->TlsDirectory.Characteristics,
1262 &TlsVector[TlsData->TlsDirectory.Characteristics],
1263 TlsData->TlsDirectory.StartAddressOfRawData,
1264 TlsVector[TlsData->TlsDirectory.Characteristics]);
1265 }
1266
1267 /* Copy the data */
1268 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1269 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1270 TlsDataSize);
1271 }
1272
1273 /* Done */
1274 return STATUS_SUCCESS;
1275 }
1276
1277 VOID
1278 NTAPI
1279 LdrpFreeTls(VOID)
1280 {
1281 PLIST_ENTRY ListHead, NextEntry;
1282 PLDRP_TLS_DATA TlsData;
1283 PVOID *TlsVector;
1284 PTEB Teb = NtCurrentTeb();
1285
1286 /* Get a pointer to the vector array */
1287 TlsVector = Teb->ThreadLocalStoragePointer;
1288 if (!TlsVector) return;
1289
1290 /* Loop through it */
1291 ListHead = &LdrpTlsList;
1292 NextEntry = ListHead->Flink;
1293 while (NextEntry != ListHead)
1294 {
1295 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1296 NextEntry = NextEntry->Flink;
1297
1298 /* Free each entry */
1299 if (TlsVector[TlsData->TlsDirectory.Characteristics])
1300 {
1301 RtlFreeHeap(RtlGetProcessHeap(),
1302 0,
1303 TlsVector[TlsData->TlsDirectory.Characteristics]);
1304 }
1305 }
1306
1307 /* Free the array itself */
1308 RtlFreeHeap(RtlGetProcessHeap(),
1309 0,
1310 TlsVector);
1311 }
1312
1313 NTSTATUS
1314 NTAPI
1315 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1316 {
1317 NTSTATUS Status;
1318 HANDLE KeyHandle;
1319 ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1320
1321 /* Return error if we were not provided a pointer where to save the options key handle */
1322 if (!OptionsKey) return STATUS_INVALID_HANDLE;
1323
1324 /* Zero initialize the options key pointer */
1325 *OptionsKey = NULL;
1326
1327 /* Open the options key */
1328 Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1329
1330 /* Save it if it was opened successfully */
1331 if (NT_SUCCESS(Status))
1332 *OptionsKey = KeyHandle;
1333
1334 if (KeyHandle)
1335 {
1336 /* There are image specific options, read them starting with NXCOMPAT */
1337 Status = LdrQueryImageFileKeyOption(KeyHandle,
1338 L"ExecuteOptions",
1339 4,
1340 &ExecuteOptions,
1341 sizeof(ExecuteOptions),
1342 0);
1343
1344 if (NT_SUCCESS(Status))
1345 {
1346 /* TODO: Set execution options for the process */
1347 /*
1348 if (ExecuteOptions == 0)
1349 ExecuteOptions = 1;
1350 else
1351 ExecuteOptions = 2;
1352 ZwSetInformationProcess(NtCurrentProcess(),
1353 ProcessExecuteFlags,
1354 &ExecuteOptions,
1355 sizeof(ULONG));*/
1356
1357 }
1358
1359 /* Check if this image uses large pages */
1360 if (Peb->ImageUsesLargePages)
1361 {
1362 /* TODO: If it does, open large page key */
1363 UNIMPLEMENTED;
1364 }
1365
1366 /* Get various option values */
1367 LdrQueryImageFileKeyOption(KeyHandle,
1368 L"DisableHeapLookaside",
1369 REG_DWORD,
1370 &RtlpDisableHeapLookaside,
1371 sizeof(RtlpDisableHeapLookaside),
1372 NULL);
1373
1374 LdrQueryImageFileKeyOption(KeyHandle,
1375 L"ShutdownFlags",
1376 REG_DWORD,
1377 &RtlpShutdownProcessFlags,
1378 sizeof(RtlpShutdownProcessFlags),
1379 NULL);
1380
1381 LdrQueryImageFileKeyOption(KeyHandle,
1382 L"MinimumStackCommitInBytes",
1383 REG_DWORD,
1384 &MinimumStackCommit,
1385 sizeof(MinimumStackCommit),
1386 NULL);
1387
1388 /* Update PEB's minimum stack commit if it's lower */
1389 if (Peb->MinimumStackCommit < MinimumStackCommit)
1390 Peb->MinimumStackCommit = MinimumStackCommit;
1391
1392 /* Set the global flag */
1393 Status = LdrQueryImageFileKeyOption(KeyHandle,
1394 L"GlobalFlag",
1395 REG_DWORD,
1396 &GlobalFlag,
1397 sizeof(GlobalFlag),
1398 NULL);
1399
1400 if (NT_SUCCESS(Status))
1401 Peb->NtGlobalFlag = GlobalFlag;
1402 else
1403 GlobalFlag = 0;
1404
1405 /* Call AVRF if necessary */
1406 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1407 {
1408 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1409 if (!NT_SUCCESS(Status))
1410 {
1411 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1412 }
1413 }
1414 }
1415 else
1416 {
1417 /* There are no image-specific options, so perform global initialization */
1418 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1419 {
1420 /* Initialize app verifier package */
1421 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1422 if (!NT_SUCCESS(Status))
1423 {
1424 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1425 }
1426 }
1427 }
1428
1429 return STATUS_SUCCESS;
1430 }
1431
1432 VOID
1433 NTAPI
1434 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1435 {
1436 UNIMPLEMENTED;
1437 }
1438
1439 VOID
1440 NTAPI
1441 LdrpInitializeProcessCompat(PVOID* pOldShimData)
1442 {
1443 static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8,
1444 &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA };
1445 static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA };
1446
1447 ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1448 ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1449 SIZE_T SizeRequired;
1450 NTSTATUS Status;
1451 DWORD n, cur;
1452 ReactOS_ShimData* pShimData = *pOldShimData;
1453
1454 C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions));
1455
1456 if (pShimData)
1457 {
1458 if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1459 pShimData->dwSize != sizeof(ReactOS_ShimData))
1460 {
1461 DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1462 return;
1463 }
1464 if (pShimData->dwRosProcessCompatVersion)
1465 {
1466 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1467 return;
1468 }
1469 }
1470
1471 SizeRequired = sizeof(Buffer);
1472 Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1473 NULL,
1474 NULL,
1475 CompatibilityInformationInActivationContext,
1476 Buffer,
1477 sizeof(Buffer),
1478 &SizeRequired);
1479
1480 if (!NT_SUCCESS(Status))
1481 {
1482 DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1483 return;
1484 }
1485
1486 ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1487 /* No Compatibility elements present, bail out */
1488 if (ContextCompatInfo->ElementCount == 0)
1489 return;
1490
1491 /* Search for known GUID's, starting from newest to oldest. */
1492 for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur)
1493 {
1494 for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1495 {
1496 if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1497 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID))
1498 {
1499 /* If this process did not need shim data before, allocate and store it */
1500 if (pShimData == NULL)
1501 {
1502 PPEB Peb = NtCurrentPeb();
1503
1504 ASSERT(Peb->pShimData == NULL);
1505 pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1506
1507 if (!pShimData)
1508 {
1509 DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1510 return;
1511 }
1512
1513 pShimData->dwSize = sizeof(*pShimData);
1514 pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1515
1516 Peb->pShimData = pShimData;
1517 *pOldShimData = pShimData;
1518 }
1519
1520 /* Store the highest found version, and bail out. */
1521 pShimData->dwRosProcessCompatVersion = GuidVersions[cur];
1522 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]);
1523 return;
1524 }
1525 }
1526 }
1527 }
1528
1529
1530 NTSTATUS
1531 NTAPI
1532 LdrpInitializeProcess(IN PCONTEXT Context,
1533 IN PVOID SystemArgument1)
1534 {
1535 RTL_HEAP_PARAMETERS HeapParameters;
1536 ULONG ComSectionSize;
1537 //ANSI_STRING FunctionName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1538 PVOID OldShimData;
1539 OBJECT_ATTRIBUTES ObjectAttributes;
1540 //UNICODE_STRING LocalFileName, FullImageName;
1541 HANDLE SymLinkHandle;
1542 //ULONG DebugHeapOnly;
1543 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1544 PPEB Peb = NtCurrentPeb();
1545 BOOLEAN IsDotNetImage = FALSE;
1546 BOOLEAN FreeCurDir = FALSE;
1547 //HANDLE CompatKey;
1548 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1549 //LPWSTR ImagePathBuffer;
1550 ULONG ConfigSize;
1551 UNICODE_STRING CurrentDirectory;
1552 HANDLE OptionsKey;
1553 ULONG HeapFlags;
1554 PIMAGE_NT_HEADERS NtHeader;
1555 LPWSTR NtDllName = NULL;
1556 NTSTATUS Status, ImportStatus;
1557 NLSTABLEINFO NlsTable;
1558 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1559 PTEB Teb = NtCurrentTeb();
1560 PLIST_ENTRY ListHead;
1561 PLIST_ENTRY NextEntry;
1562 ULONG i;
1563 PWSTR ImagePath;
1564 ULONG DebugProcessHeapOnly = 0;
1565 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1566 PWCHAR Current;
1567 ULONG ExecuteOptions = 0;
1568 PVOID ViewBase;
1569
1570 /* Set a NULL SEH Filter */
1571 RtlSetUnhandledExceptionFilter(NULL);
1572
1573 /* Get the image path */
1574 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1575
1576 /* Check if it's not normalized */
1577 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1578 {
1579 /* Normalize it*/
1580 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1581 }
1582
1583 /* Create a unicode string for the Image Path */
1584 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1585 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1586 ImagePathName.Buffer = ImagePath;
1587
1588 /* Get the NT Headers */
1589 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1590
1591 /* Get the execution options */
1592 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1593
1594 /* Check if this is a .NET executable */
1595 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1596 TRUE,
1597 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1598 &ComSectionSize))
1599 {
1600 /* Remember this for later */
1601 IsDotNetImage = TRUE;
1602 }
1603
1604 /* Save the NTDLL Base address */
1605 NtDllBase = SystemArgument1;
1606
1607 /* If this is a Native Image */
1608 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1609 {
1610 /* Then do DLL Validation */
1611 LdrpDllValidation = TRUE;
1612 }
1613
1614 /* Save the old Shim Data */
1615 OldShimData = Peb->pShimData;
1616
1617 /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1618 //Peb->pShimData = NULL;
1619
1620 /* Save the number of processors and CS Timeout */
1621 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1622 RtlpTimeout = Peb->CriticalSectionTimeout;
1623
1624 /* Normalize the parameters */
1625 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1626 if (ProcessParameters)
1627 {
1628 /* Save the Image and Command Line Names */
1629 ImageFileName = ProcessParameters->ImagePathName;
1630 CommandLine = ProcessParameters->CommandLine;
1631 }
1632 else
1633 {
1634 /* It failed, initialize empty strings */
1635 RtlInitUnicodeString(&ImageFileName, NULL);
1636 RtlInitUnicodeString(&CommandLine, NULL);
1637 }
1638
1639 /* Initialize NLS data */
1640 RtlInitNlsTables(Peb->AnsiCodePageData,
1641 Peb->OemCodePageData,
1642 Peb->UnicodeCaseTableData,
1643 &NlsTable);
1644
1645 /* Reset NLS Translations */
1646 RtlResetRtlTranslations(&NlsTable);
1647
1648 /* Get the Image Config Directory */
1649 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1650 TRUE,
1651 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1652 &ConfigSize);
1653
1654 /* Setup the Heap Parameters */
1655 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1656 HeapFlags = HEAP_GROWABLE;
1657 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1658
1659 /* Check if we have Configuration Data */
1660 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1661 {
1662 /* FIXME: Custom heap settings and misc. */
1663 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1664 }
1665
1666 /* Check for custom affinity mask */
1667 if (Peb->ImageProcessAffinityMask)
1668 {
1669 /* Set it */
1670 Status = NtSetInformationProcess(NtCurrentProcess(),
1671 ProcessAffinityMask,
1672 &Peb->ImageProcessAffinityMask,
1673 sizeof(Peb->ImageProcessAffinityMask));
1674 }
1675
1676 /* Check if verbose debugging (ShowSnaps) was requested */
1677 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1678
1679 /* Start verbose debugging messages right now if they were requested */
1680 if (ShowSnaps)
1681 {
1682 DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1683 Teb->ClientId.UniqueProcess,
1684 &CommandLine);
1685 }
1686
1687 /* If the timeout is too long */
1688 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1689 {
1690 /* Then disable CS Timeout */
1691 RtlpTimeoutDisable = TRUE;
1692 }
1693
1694 /* Initialize Critical Section Data */
1695 RtlpInitDeferedCriticalSection();
1696
1697 /* Initialize VEH Call lists */
1698 RtlpInitializeVectoredExceptionHandling();
1699
1700 /* Set TLS/FLS Bitmap data */
1701 Peb->FlsBitmap = &FlsBitMap;
1702 Peb->TlsBitmap = &TlsBitMap;
1703 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1704
1705 /* Initialize FLS Bitmap */
1706 RtlInitializeBitMap(&FlsBitMap,
1707 Peb->FlsBitmapBits,
1708 FLS_MAXIMUM_AVAILABLE);
1709 RtlSetBit(&FlsBitMap, 0);
1710
1711 /* Initialize TLS Bitmap */
1712 RtlInitializeBitMap(&TlsBitMap,
1713 Peb->TlsBitmapBits,
1714 TLS_MINIMUM_AVAILABLE);
1715 RtlSetBit(&TlsBitMap, 0);
1716 RtlInitializeBitMap(&TlsExpansionBitMap,
1717 Peb->TlsExpansionBitmapBits,
1718 TLS_EXPANSION_SLOTS);
1719 RtlSetBit(&TlsExpansionBitMap, 0);
1720
1721 /* Initialize the Hash Table */
1722 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1723 {
1724 InitializeListHead(&LdrpHashTable[i]);
1725 }
1726
1727 /* Initialize the Loader Lock */
1728 // FIXME: What's the point of initing it manually, if two lines lower
1729 // a call to RtlInitializeCriticalSection() is being made anyway?
1730 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1731 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1732 RtlInitializeCriticalSection(&LdrpLoaderLock);
1733 LdrpLoaderLockInit = TRUE;
1734
1735 /* Check if User Stack Trace Database support was requested */
1736 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1737 {
1738 DPRINT1("We don't support user stack trace databases yet\n");
1739 }
1740
1741 /* Setup Fast PEB Lock */
1742 RtlInitializeCriticalSection(&FastPebLock);
1743 Peb->FastPebLock = &FastPebLock;
1744 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1745 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1746
1747 /* Setup Callout Lock and Notification list */
1748 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1749 InitializeListHead(&LdrpDllNotificationList);
1750
1751 /* For old executables, use 16-byte aligned heap */
1752 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1753 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1754 {
1755 HeapFlags |= HEAP_CREATE_ALIGN_16;
1756 }
1757
1758 /* Setup the Heap */
1759 RtlInitializeHeapManager();
1760 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1761 NULL,
1762 NtHeader->OptionalHeader.SizeOfHeapReserve,
1763 NtHeader->OptionalHeader.SizeOfHeapCommit,
1764 NULL,
1765 &HeapParameters);
1766
1767 if (!Peb->ProcessHeap)
1768 {
1769 DPRINT1("Failed to create process heap\n");
1770 return STATUS_NO_MEMORY;
1771 }
1772
1773 /* Allocate an Activation Context Stack */
1774 Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
1775 if (!NT_SUCCESS(Status)) return Status;
1776
1777 // FIXME: Loader private heap is missing
1778 //DPRINT1("Loader private heap is missing\n");
1779
1780 /* Check for Debug Heap */
1781 if (OptionsKey)
1782 {
1783 /* Query the setting */
1784 Status = LdrQueryImageFileKeyOption(OptionsKey,
1785 L"DebugProcessHeapOnly",
1786 REG_DWORD,
1787 &DebugProcessHeapOnly,
1788 sizeof(ULONG),
1789 NULL);
1790
1791 if (NT_SUCCESS(Status))
1792 {
1793 /* Reset DPH if requested */
1794 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1795 {
1796 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
1797 RtlpPageHeapEnabled = FALSE;
1798 }
1799 }
1800 }
1801
1802 /* Build the NTDLL Path */
1803 FullPath.Buffer = StringBuffer;
1804 FullPath.Length = 0;
1805 FullPath.MaximumLength = sizeof(StringBuffer);
1806 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1807 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1808 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1809
1810 /* Open the Known DLLs directory */
1811 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1812 InitializeObjectAttributes(&ObjectAttributes,
1813 &KnownDllString,
1814 OBJ_CASE_INSENSITIVE,
1815 NULL,
1816 NULL);
1817 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1818 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1819 &ObjectAttributes);
1820
1821 /* Check if it exists */
1822 if (NT_SUCCESS(Status))
1823 {
1824 /* Open the Known DLLs Path */
1825 RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1826 InitializeObjectAttributes(&ObjectAttributes,
1827 &KnownDllString,
1828 OBJ_CASE_INSENSITIVE,
1829 LdrpKnownDllObjectDirectory,
1830 NULL);
1831 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1832 SYMBOLIC_LINK_QUERY,
1833 &ObjectAttributes);
1834 if (NT_SUCCESS(Status))
1835 {
1836 /* Query the path */
1837 LdrpKnownDllPath.Length = 0;
1838 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1839 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1840 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1841 NtClose(SymLinkHandle);
1842 if (!NT_SUCCESS(Status))
1843 {
1844 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1845 return Status;
1846 }
1847 }
1848 }
1849
1850 /* Check if we failed */
1851 if (!NT_SUCCESS(Status))
1852 {
1853 /* Assume System32 */
1854 LdrpKnownDllObjectDirectory = NULL;
1855 RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1856 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1857 }
1858
1859 /* If we have process parameters, get the default path and current path */
1860 if (ProcessParameters)
1861 {
1862 /* Check if we have a Dll Path */
1863 if (ProcessParameters->DllPath.Length)
1864 {
1865 /* Get the path */
1866 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1867 }
1868 else
1869 {
1870 /* We need a valid path */
1871 DPRINT1("No valid DllPath was given!\n");
1872 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1873 }
1874
1875 /* Set the current directory */
1876 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1877
1878 /* Check if it's empty or invalid */
1879 if ((!CurrentDirectory.Buffer) ||
1880 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1881 (!CurrentDirectory.Length))
1882 {
1883 /* Allocate space for the buffer */
1884 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1885 0,
1886 3 * sizeof(WCHAR) +
1887 sizeof(UNICODE_NULL));
1888 if (!CurrentDirectory.Buffer)
1889 {
1890 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1891 // FIXME: And what?
1892 }
1893
1894 /* Copy the drive of the system root */
1895 RtlMoveMemory(CurrentDirectory.Buffer,
1896 SharedUserData->NtSystemRoot,
1897 3 * sizeof(WCHAR));
1898 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1899 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1900 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1901
1902 FreeCurDir = TRUE;
1903 DPRINT("Using dynamically allocd curdir\n");
1904 }
1905 else
1906 {
1907 /* Use the local buffer */
1908 DPRINT("Using local system root\n");
1909 }
1910 }
1911
1912 /* Setup Loader Data */
1913 Peb->Ldr = &PebLdr;
1914 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1915 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1916 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1917 PebLdr.Length = sizeof(PEB_LDR_DATA);
1918 PebLdr.Initialized = TRUE;
1919
1920 /* Allocate a data entry for the Image */
1921 LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
1922
1923 /* Set it up */
1924 LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
1925 LdrpImageEntry->LoadCount = -1;
1926 LdrpImageEntry->EntryPointActivationContext = 0;
1927 LdrpImageEntry->FullDllName = ImageFileName;
1928
1929 if (IsDotNetImage)
1930 LdrpImageEntry->Flags = LDRP_COR_IMAGE;
1931 else
1932 LdrpImageEntry->Flags = 0;
1933
1934 /* Check if the name is empty */
1935 if (!ImageFileName.Buffer[0])
1936 {
1937 /* Use the same Base name */
1938 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
1939 }
1940 else
1941 {
1942 /* Find the last slash */
1943 Current = ImageFileName.Buffer;
1944 while (*Current)
1945 {
1946 if (*Current++ == '\\')
1947 {
1948 /* Set this path */
1949 NtDllName = Current;
1950 }
1951 }
1952
1953 /* Did we find anything? */
1954 if (!NtDllName)
1955 {
1956 /* Use the same Base name */
1957 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
1958 }
1959 else
1960 {
1961 /* Setup the name */
1962 LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
1963 LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
1964 LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
1965 (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
1966 }
1967 }
1968
1969 /* Processing done, insert it */
1970 LdrpInsertMemoryTableEntry(LdrpImageEntry);
1971 LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
1972
1973 /* Now add an entry for NTDLL */
1974 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
1975 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
1976 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
1977 NtLdrEntry->LoadCount = -1;
1978 NtLdrEntry->EntryPointActivationContext = 0;
1979
1980 NtLdrEntry->FullDllName.Length = FullPath.Length;
1981 NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
1982 NtLdrEntry->FullDllName.Buffer = StringBuffer;
1983 RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
1984
1985 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
1986 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
1987 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
1988
1989 /* Processing done, insert it */
1990 LdrpNtDllDataTableEntry = NtLdrEntry;
1991 LdrpInsertMemoryTableEntry(NtLdrEntry);
1992
1993 /* Let the world know */
1994 if (ShowSnaps)
1995 {
1996 DPRINT1("LDR: NEW PROCESS\n");
1997 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
1998 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
1999 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
2000 }
2001
2002 /* Link the Init Order List */
2003 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2004 &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2005
2006 /* Initialize Wine's active context implementation for the current process */
2007 actctx_init();
2008
2009 /* ReactOS specific */
2010 LdrpInitializeProcessCompat(&OldShimData);
2011
2012 /* Set the current directory */
2013 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2014 if (!NT_SUCCESS(Status))
2015 {
2016 /* We failed, check if we should free it */
2017 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2018
2019 /* Set it to the NT Root */
2020 CurrentDirectory = NtSystemRoot;
2021 RtlSetCurrentDirectory_U(&CurrentDirectory);
2022 }
2023 else
2024 {
2025 /* We're done with it, free it */
2026 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2027 }
2028
2029 /* Check if we should look for a .local file */
2030 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
2031 {
2032 /* FIXME */
2033 DPRINT1("We don't support .local overrides yet\n");
2034 }
2035
2036 /* Check if the Application Verifier was enabled */
2037 if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2038 {
2039 Status = AVrfInitializeVerifier();
2040 if (!NT_SUCCESS(Status))
2041 {
2042 DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2043 return Status;
2044 }
2045
2046 }
2047
2048 if (IsDotNetImage)
2049 {
2050 /* FIXME */
2051 DPRINT1("We don't support .NET applications yet\n");
2052 }
2053
2054 /* FIXME: Load support for Terminal Services */
2055 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
2056 {
2057 /* Load kernel32 and call BasePostImportInit... */
2058 DPRINT("Unimplemented codepath!\n");
2059 }
2060
2061 /* Walk the IAT and load all the DLLs */
2062 ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2063
2064 /* Check if relocation is needed */
2065 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2066 {
2067 DPRINT1("LDR: Performing EXE relocation\n");
2068
2069 /* Change the protection to prepare for relocation */
2070 ViewBase = Peb->ImageBaseAddress;
2071 Status = LdrpSetProtection(ViewBase, FALSE);
2072 if (!NT_SUCCESS(Status)) return Status;
2073
2074 /* Do the relocation */
2075 Status = LdrRelocateImageWithBias(ViewBase,
2076 0LL,
2077 NULL,
2078 STATUS_SUCCESS,
2079 STATUS_CONFLICTING_ADDRESSES,
2080 STATUS_INVALID_IMAGE_FORMAT);
2081 if (!NT_SUCCESS(Status))
2082 {
2083 DPRINT1("LdrRelocateImageWithBias() failed\n");
2084 return Status;
2085 }
2086
2087 /* Check if a start context was provided */
2088 if (Context)
2089 {
2090 DPRINT1("WARNING: Relocated EXE Context");
2091 UNIMPLEMENTED; // We should support this
2092 return STATUS_INVALID_IMAGE_FORMAT;
2093 }
2094
2095 /* Restore the protection */
2096 Status = LdrpSetProtection(ViewBase, TRUE);
2097 if (!NT_SUCCESS(Status)) return Status;
2098 }
2099
2100 /* Lock the DLLs */
2101 ListHead = &Peb->Ldr->InLoadOrderModuleList;
2102 NextEntry = ListHead->Flink;
2103 while (ListHead != NextEntry)
2104 {
2105 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2106 NtLdrEntry->LoadCount = -1;
2107 NextEntry = NextEntry->Flink;
2108 }
2109
2110 /* Phase 0 is done */
2111 LdrpLdrDatabaseIsSetup = TRUE;
2112
2113 /* Check whether all static imports were properly loaded and return here */
2114 if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2115
2116 /* Initialize TLS */
2117 Status = LdrpInitializeTls();
2118 if (!NT_SUCCESS(Status))
2119 {
2120 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2121 Status);
2122 return Status;
2123 }
2124
2125 /* FIXME Mark the DLL Ranges for Stack Traces later */
2126
2127 /* Notify the debugger now */
2128 if (Peb->BeingDebugged)
2129 {
2130 /* Break */
2131 DbgBreakPoint();
2132
2133 /* Update show snaps again */
2134 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2135 }
2136
2137 /* Validate the Image for MP Usage */
2138 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2139
2140 /* Check NX Options */
2141 if (SharedUserData->NXSupportPolicy == 1)
2142 {
2143 ExecuteOptions = 0xD;
2144 }
2145 else if (!SharedUserData->NXSupportPolicy)
2146 {
2147 ExecuteOptions = 0xA;
2148 }
2149
2150 /* Let Mm know */
2151 ZwSetInformationProcess(NtCurrentProcess(),
2152 ProcessExecuteFlags,
2153 &ExecuteOptions,
2154 sizeof(ULONG));
2155
2156 // FIXME: Should be done by Application Compatibility features,
2157 // by reading the registry, etc...
2158 // For now, this is the old code from ntdll!RtlGetVersion().
2159 RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2160 if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2161 {
2162 WCHAR szCSDVersion[128];
2163 LONG i;
2164 ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
2165 i = _snwprintf(szCSDVersion, Length,
2166 L"Service Pack %d",
2167 ((Peb->OSCSDVersion >> 8) & 0xFF));
2168 if (i < 0)
2169 {
2170 /* Null-terminate if it was overflowed */
2171 szCSDVersion[Length] = UNICODE_NULL;
2172 }
2173
2174 Length *= sizeof(WCHAR);
2175 Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2176 0,
2177 Length + sizeof(UNICODE_NULL));
2178 if (Peb->CSDVersion.Buffer)
2179 {
2180 Peb->CSDVersion.Length = Length;
2181 Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2182
2183 RtlCopyMemory(Peb->CSDVersion.Buffer,
2184 szCSDVersion,
2185 Peb->CSDVersion.MaximumLength);
2186 Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2187 }
2188 }
2189
2190 /* Check if we had Shim Data */
2191 if (OldShimData)
2192 {
2193 /* Load the Shim Engine */
2194 Peb->AppCompatInfo = NULL;
2195 LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2196 }
2197 else
2198 {
2199 /* Check for Application Compatibility Goo */
2200 //LdrQueryApplicationCompatibilityGoo(hKey);
2201 DPRINT("Querying app compat hacks is missing!\n");
2202 }
2203
2204 /*
2205 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2206 * incompatible images.
2207 */
2208
2209 /* Now call the Init Routines */
2210 Status = LdrpRunInitializeRoutines(Context);
2211 if (!NT_SUCCESS(Status))
2212 {
2213 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2214 Status);
2215 return Status;
2216 }
2217
2218 /* Notify Shim Engine */
2219 if (g_ShimsEnabled)
2220 {
2221 VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2222 SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2223 SE_InstallAfterInit(&ImagePathName, OldShimData);
2224 }
2225
2226 /* Check if we have a user-defined Post Process Routine */
2227 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2228 {
2229 /* Call it */
2230 Peb->PostProcessInitRoutine();
2231 }
2232
2233 /* Close the key if we have one opened */
2234 if (OptionsKey) NtClose(OptionsKey);
2235
2236 /* Return status */
2237 return Status;
2238 }
2239
2240 VOID
2241 NTAPI
2242 LdrpInitFailure(NTSTATUS Status)
2243 {
2244 ULONG Response;
2245 PPEB Peb = NtCurrentPeb();
2246
2247 /* Print a debug message */
2248 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2249 &Peb->ProcessParameters->ImagePathName, Status);
2250
2251 /* Raise a hard error */
2252 if (!LdrpFatalHardErrorCount)
2253 {
2254 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2255 }
2256 }
2257
2258 VOID
2259 NTAPI
2260 LdrpInit(PCONTEXT Context,
2261 PVOID SystemArgument1,
2262 PVOID SystemArgument2)
2263 {
2264 LARGE_INTEGER Timeout;
2265 PTEB Teb = NtCurrentTeb();
2266 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2267 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2268 PPEB Peb = NtCurrentPeb();
2269
2270 DPRINT("LdrpInit() %p/%p\n",
2271 NtCurrentTeb()->RealClientId.UniqueProcess,
2272 NtCurrentTeb()->RealClientId.UniqueThread);
2273
2274 #ifdef _WIN64
2275 /* Set the SList header usage */
2276 RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2277 #endif /* _WIN64 */
2278
2279 /* Check if we have a deallocation stack */
2280 if (!Teb->DeallocationStack)
2281 {
2282 /* We don't, set one */
2283 Status = NtQueryVirtualMemory(NtCurrentProcess(),
2284 Teb->NtTib.StackLimit,
2285 MemoryBasicInformation,
2286 &MemoryBasicInfo,
2287 sizeof(MEMORY_BASIC_INFORMATION),
2288 NULL);
2289 if (!NT_SUCCESS(Status))
2290 {
2291 /* Fail */
2292 LdrpInitFailure(Status);
2293 RtlRaiseStatus(Status);
2294 return;
2295 }
2296
2297 /* Set the stack */
2298 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2299 }
2300
2301 /* Now check if the process is already being initialized */
2302 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2303 1,
2304 0) == 1)
2305 {
2306 /* Set the timeout to 30 milliseconds */
2307 Timeout.QuadPart = Int32x32To64(30, -10000);
2308
2309 /* Make sure the status hasn't changed */
2310 while (LdrpProcessInitialized == 1)
2311 {
2312 /* Do the wait */
2313 ZwDelayExecution(FALSE, &Timeout);
2314 }
2315 }
2316
2317 /* Check if we have already setup LDR data */
2318 if (!Peb->Ldr)
2319 {
2320 /* Setup the Loader Lock */
2321 Peb->LoaderLock = &LdrpLoaderLock;
2322
2323 /* Let other code know we're initializing */
2324 LdrpInLdrInit = TRUE;
2325
2326 /* Protect with SEH */
2327 _SEH2_TRY
2328 {
2329 /* Initialize the Process */
2330 LoaderStatus = LdrpInitializeProcess(Context,
2331 SystemArgument1);
2332
2333 /* Check for success and if MinimumStackCommit was requested */
2334 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2335 {
2336 /* Enforce the limit */
2337 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2338 UNIMPLEMENTED;
2339 }
2340 }
2341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2342 {
2343 /* Fail with the SEH error */
2344 LoaderStatus = _SEH2_GetExceptionCode();
2345 }
2346 _SEH2_END;
2347
2348 /* We're not initializing anymore */
2349 LdrpInLdrInit = FALSE;
2350
2351 /* Check if init worked */
2352 if (NT_SUCCESS(LoaderStatus))
2353 {
2354 /* Set the process as Initialized */
2355 _InterlockedIncrement(&LdrpProcessInitialized);
2356 }
2357 }
2358 else
2359 {
2360 /* Loader data is there... is this a fork() ? */
2361 if(Peb->InheritedAddressSpace)
2362 {
2363 /* Handle the fork() */
2364 //LoaderStatus = LdrpForkProcess();
2365 LoaderStatus = STATUS_NOT_IMPLEMENTED;
2366 UNIMPLEMENTED;
2367 }
2368 else
2369 {
2370 /* This is a new thread initializing */
2371 LdrpInitializeThread(Context);
2372 }
2373 }
2374
2375 /* All done, test alert the thread */
2376 NtTestAlert();
2377
2378 /* Return */
2379 if (!NT_SUCCESS(LoaderStatus))
2380 {
2381 /* Fail */
2382 LdrpInitFailure(LoaderStatus);
2383 RtlRaiseStatus(LoaderStatus);
2384 }
2385 }
2386
2387 /* EOF */