[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / dll / ntdll / ldr / startup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: dll/ntdll/ldr/startup.c
5 * PURPOSE: Process startup for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #define NDEBUG
14 #include <debug.h>
15 #include <win32k/callback.h>
16
17 VOID RtlInitializeHeapManager(VOID);
18 VOID LdrpInitLoader(VOID);
19 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
20 NTSTATUS LdrpAttachThread(VOID);
21 VOID RtlpInitializeVectoredExceptionHandling(VOID);
22 extern PTEB LdrpTopLevelDllBeingLoadedTeb;
23
24 /* GLOBALS *******************************************************************/
25
26 PLDR_DATA_TABLE_ENTRY ExeModule;
27 static RTL_CRITICAL_SECTION PebLock;
28 static RTL_CRITICAL_SECTION LoaderLock;
29 static RTL_BITMAP TlsBitMap;
30 static RTL_BITMAP TlsExpansionBitMap;
31 static volatile BOOLEAN LdrpInitialized = FALSE;
32 static LONG LdrpInitLock = 0;
33
34 #define VALUE_BUFFER_SIZE 256
35
36 /* FUNCTIONS *****************************************************************/
37
38 BOOLEAN
39 FASTCALL
40 ReadCompatibilitySetting(HANDLE Key,
41 LPWSTR Value,
42 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo,
43 DWORD * Buffer)
44 {
45 UNICODE_STRING ValueName;
46 NTSTATUS Status;
47 ULONG Length;
48
49 RtlInitUnicodeString(&ValueName, Value);
50 Status = NtQueryValueKey(Key,
51 &ValueName,
52 KeyValuePartialInformation,
53 ValueInfo,
54 VALUE_BUFFER_SIZE,
55 &Length);
56
57 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
58 {
59 RtlFreeUnicodeString(&ValueName);
60 return FALSE;
61 }
62
63 RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
64 RtlFreeUnicodeString(&ValueName);
65 return TRUE;
66 }
67
68 VOID
69 FASTCALL
70 LoadImageFileExecutionOptions(PPEB Peb)
71 {
72 NTSTATUS Status = STATUS_SUCCESS;
73 ULONG Value = 0;
74 UNICODE_STRING ImageName;
75 UNICODE_STRING ImagePathName;
76 ULONG ValueSize;
77 extern ULONG RtlpPageHeapGlobalFlags, RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
78 extern ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
79 extern WCHAR RtlpPageHeapTargetDlls[512];
80 extern BOOLEAN RtlpPageHeapEnabled;
81
82 if (Peb->ProcessParameters &&
83 Peb->ProcessParameters->ImagePathName.Length > 0)
84 {
85 DPRINT("%wZ\n", &Peb->ProcessParameters->ImagePathName);
86
87 ImagePathName = Peb->ProcessParameters->ImagePathName;
88 ImageName.Buffer = ImagePathName.Buffer + ImagePathName.Length / sizeof(WCHAR);
89 ImageName.Length = 0;
90
91 while (ImagePathName.Buffer < ImageName.Buffer)
92 {
93 ImageName.Buffer--;
94 if (*ImageName.Buffer == L'\\')
95 {
96 ImageName.Buffer++;
97 break;
98 }
99 }
100
101 ImageName.Length = ImagePathName.Length -
102 (ImageName.Buffer - ImagePathName.Buffer) * sizeof(WCHAR);
103 ImageName.MaximumLength = ImageName.Length +
104 ImagePathName.MaximumLength - ImagePathName.Length;
105
106 DPRINT("%wZ\n", &ImageName);
107
108 /* global flag */
109 Status = LdrQueryImageFileExecutionOptions(&ImageName,
110 L"GlobalFlag",
111 REG_DWORD,
112 (PVOID)&Value,
113 sizeof(Value),
114 &ValueSize);
115 if (NT_SUCCESS(Status))
116 {
117 Peb->NtGlobalFlag = Value;
118 DPRINT("GlobalFlag: Value=0x%lx\n", Value);
119 }
120 else
121 {
122 /* Add debugging flags if there is no GlobalFlags override */
123 if (Peb->BeingDebugged)
124 {
125 Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS |
126 FLG_HEAP_ENABLE_FREE_CHECK |
127 FLG_HEAP_ENABLE_TAIL_CHECK;
128 }
129 }
130
131 /* Handle the case when page heap is enabled */
132 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
133 {
134 /* Disable all heap debugging flags so that no heap call goes via page heap branch */
135 Peb->NtGlobalFlag &= ~(FLG_HEAP_VALIDATE_PARAMETERS |
136 FLG_HEAP_VALIDATE_ALL |
137 FLG_HEAP_ENABLE_FREE_CHECK |
138 FLG_HEAP_ENABLE_TAIL_CHECK |
139 FLG_USER_STACK_TRACE_DB |
140 FLG_HEAP_ENABLE_TAGGING |
141 FLG_HEAP_ENABLE_TAG_BY_DLL);
142
143 /* Get page heap flags without checking return value */
144 LdrQueryImageFileExecutionOptions(&ImageName,
145 L"PageHeapFlags",
146 REG_DWORD,
147 (PVOID)&RtlpPageHeapGlobalFlags,
148 sizeof(RtlpPageHeapGlobalFlags),
149 &ValueSize);
150
151 LdrQueryImageFileExecutionOptions(&ImageName,
152 L"PageHeapSizeRangeStart",
153 REG_DWORD,
154 (PVOID)&RtlpPageHeapSizeRangeStart,
155 sizeof(RtlpPageHeapSizeRangeStart),
156 &ValueSize);
157
158 LdrQueryImageFileExecutionOptions(&ImageName,
159 L"PageHeapSizeRangeEnd",
160 REG_DWORD,
161 (PVOID)&RtlpPageHeapSizeRangeEnd,
162 sizeof(RtlpPageHeapSizeRangeEnd),
163 &ValueSize);
164
165 LdrQueryImageFileExecutionOptions(&ImageName,
166 L"PageHeapDllRangeStart",
167 REG_DWORD,
168 (PVOID)&RtlpPageHeapDllRangeStart,
169 sizeof(RtlpPageHeapDllRangeStart),
170 &ValueSize);
171
172 LdrQueryImageFileExecutionOptions(&ImageName,
173 L"PageHeapDllRangeEnd",
174 REG_DWORD,
175 (PVOID)&RtlpPageHeapDllRangeEnd,
176 sizeof(RtlpPageHeapDllRangeEnd),
177 &ValueSize);
178
179 LdrQueryImageFileExecutionOptions(&ImageName,
180 L"PageHeapTargetDlls",
181 REG_SZ,
182 (PVOID)RtlpPageHeapTargetDlls,
183 sizeof(RtlpPageHeapTargetDlls),
184 &ValueSize);
185
186 /* Now when all parameters are read, enable page heap */
187 RtlpPageHeapEnabled = TRUE;
188 }
189 }
190 }
191
192 BOOLEAN
193 FASTCALL
194 LoadCompatibilitySettings(PPEB Peb)
195 {
196 NTSTATUS Status;
197 HANDLE UserKey = NULL;
198 HANDLE KeyHandle;
199 HANDLE SubKeyHandle;
200 OBJECT_ATTRIBUTES ObjectAttributes;
201 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(
202 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
203 UNICODE_STRING ValueName;
204 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
205 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
206 ULONG Length;
207 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
208 SPMajorVersion, SPMinorVersion = 0;
209
210 if (Peb->ProcessParameters &&
211 (Peb->ProcessParameters->ImagePathName.Length > 0))
212 {
213 Status = RtlOpenCurrentUser(KEY_READ, &UserKey);
214 if (!NT_SUCCESS(Status))
215 {
216 return FALSE;
217 }
218
219 InitializeObjectAttributes(&ObjectAttributes,
220 &KeyName,
221 OBJ_CASE_INSENSITIVE,
222 UserKey,
223 NULL);
224
225 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
226
227 if (!NT_SUCCESS(Status))
228 {
229 if (UserKey)
230 NtClose(UserKey);
231 return FALSE;
232 }
233
234 /* query version name for application */
235 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer;
236 Status = NtQueryValueKey(KeyHandle,
237 &Peb->ProcessParameters->ImagePathName,
238 KeyValuePartialInformation,
239 ValueBuffer,
240 VALUE_BUFFER_SIZE,
241 &Length);
242
243 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
244 {
245 NtClose(KeyHandle);
246 if (UserKey)
247 NtClose(UserKey);
248 return FALSE;
249 }
250
251 ValueName.Length = ValueInfo->DataLength;
252 ValueName.MaximumLength = ValueInfo->DataLength;
253 ValueName.Buffer = (PWSTR) ValueInfo->Data;
254
255 /* load version info */
256 InitializeObjectAttributes(&ObjectAttributes,
257 &ValueName,
258 OBJ_CASE_INSENSITIVE,
259 KeyHandle,
260 NULL);
261
262 Status = NtOpenKey(&SubKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
263
264 if (!NT_SUCCESS(Status))
265 {
266 NtClose(KeyHandle);
267 if (UserKey)
268 NtClose(UserKey);
269 return FALSE;
270 }
271
272 DPRINT("Loading version information for: %wZ\n", &ValueName);
273
274 /* read settings from registry */
275 if (!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
276 goto finish;
277 if (!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
278 goto finish;
279 if (!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
280 goto finish;
281 if (!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
282 goto finish;
283
284 /* now assign the settings */
285 Peb->OSMajorVersion = (ULONG) MajorVersion;
286 Peb->OSMinorVersion = (ULONG) MinorVersion;
287 Peb->OSBuildNumber = (USHORT) BuildNumber;
288 Peb->OSPlatformId = (ULONG) PlatformId;
289
290 /* optional service pack version numbers */
291 if (ReadCompatibilitySetting(SubKeyHandle,
292 L"SPMajorVersion",
293 ValueInfo,
294 &SPMajorVersion) &&
295 ReadCompatibilitySetting(SubKeyHandle,
296 L"SPMinorVersion",
297 ValueInfo,
298 &SPMinorVersion))
299 {
300 Peb->OSCSDVersion = ((SPMajorVersion & 0xFF) << 8) |
301 (SPMinorVersion & 0xFF);
302 }
303
304 finish:
305 /* we're finished */
306 NtClose(SubKeyHandle);
307 NtClose(KeyHandle);
308 if (UserKey)
309 NtClose(UserKey);
310 return TRUE;
311 }
312
313 return FALSE;
314 }
315
316 static
317 VOID
318 LdrpInit2(PCONTEXT Context,
319 PVOID SystemArgument1,
320 PVOID SystemArgument2)
321 {
322 PIMAGE_NT_HEADERS NTHeaders;
323 PEPFUNC EntryPoint;
324 PIMAGE_DOS_HEADER PEDosHeader;
325 PVOID ImageBase;
326 PPEB Peb = NtCurrentPeb();
327 PLDR_DATA_TABLE_ENTRY NtModule; // ntdll
328 NLSTABLEINFO NlsTable;
329 WCHAR FullNtDllPath[MAX_PATH];
330 SYSTEM_BASIC_INFORMATION SystemInformation;
331 NTSTATUS Status;
332 PVOID BaseAddress = SystemArgument1;
333
334 DPRINT("LdrpInit()\n");
335 DPRINT("Peb %p\n", Peb);
336 ImageBase = Peb->ImageBaseAddress;
337 DPRINT("ImageBase %p\n", ImageBase);
338
339 if (ImageBase <= (PVOID) 0x1000)
340 {
341 DPRINT("ImageBase is null\n");
342 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
343 }
344
345 /* If MZ header exists */
346 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
347 DPRINT("PEDosHeader %p\n", PEDosHeader);
348
349 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
350 PEDosHeader->e_lfanew == 0L ||
351 *(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE)
352 {
353 DPRINT1("Image has bad header\n");
354 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
355 }
356
357 /* normalize process parameters */
358 RtlNormalizeProcessParams(Peb->ProcessParameters);
359
360 /* Initialize NLS data */
361 RtlInitNlsTables(Peb->AnsiCodePageData,
362 Peb->OemCodePageData,
363 Peb->UnicodeCaseTableData,
364 &NlsTable);
365 RtlResetRtlTranslations(&NlsTable);
366
367 NTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageBase + PEDosHeader->e_lfanew);
368
369 /* Get number of processors */
370 DPRINT("Here\n");
371 Status = ZwQuerySystemInformation(SystemBasicInformation,
372 &SystemInformation,
373 sizeof(SYSTEM_BASIC_INFORMATION),
374 NULL);
375 DPRINT("Here2\n");
376 if (!NT_SUCCESS(Status))
377 {
378 ZwTerminateProcess(NtCurrentProcess(), Status);
379 }
380
381 Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors;
382
383 /* Initialize Critical Section Data */
384 RtlpInitDeferedCriticalSection();
385
386 /* Load execution options */
387 LoadImageFileExecutionOptions(Peb);
388
389 /* create process heap */
390 RtlInitializeHeapManager();
391 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
392 NULL,
393 NTHeaders->OptionalHeader.SizeOfHeapReserve,
394 NTHeaders->OptionalHeader.SizeOfHeapCommit,
395 NULL,
396 NULL);
397 if (Peb->ProcessHeap == 0)
398 {
399 DPRINT1("Failed to create process heap\n");
400 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
401 }
402
403 /* initialized vectored exception handling */
404 RtlpInitializeVectoredExceptionHandling();
405
406 /* initalize peb lock support */
407 RtlInitializeCriticalSection(&PebLock);
408 Peb->FastPebLock = &PebLock;
409
410 /* initialize tls bitmaps */
411 RtlInitializeBitMap(&TlsBitMap, Peb->TlsBitmapBits, TLS_MINIMUM_AVAILABLE);
412 RtlInitializeBitMap(&TlsExpansionBitMap, Peb->TlsExpansionBitmapBits, TLS_EXPANSION_SLOTS);
413
414 Peb->TlsBitmap = &TlsBitMap;
415 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
416 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
417
418 /* Initialize table of callbacks for the kernel. */
419 Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(),
420 0,
421 sizeof(PVOID) *
422 (USER32_CALLBACK_MAXIMUM + 1));
423 if (Peb->KernelCallbackTable == NULL)
424 {
425 DPRINT1("Failed to create callback table\n");
426 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
427 }
428
429 /* initalize loader lock */
430 RtlInitializeCriticalSection(&LoaderLock);
431 Peb->LoaderLock = &LoaderLock;
432
433 /* create loader information */
434 Peb->Ldr = (PPEB_LDR_DATA) RtlAllocateHeap(Peb->ProcessHeap,
435 0,
436 sizeof(PEB_LDR_DATA));
437 if (Peb->Ldr == NULL)
438 {
439 DPRINT1("Failed to create loader data\n");
440 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
441 }
442
443 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
444 Peb->Ldr->Initialized = FALSE;
445 Peb->Ldr->SsHandle = NULL;
446 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
447 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
448 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
449
450 /* Load compatibility settings */
451 LoadCompatibilitySettings(Peb);
452
453 /* build full ntdll path */
454 wcscpy(FullNtDllPath, SharedUserData->NtSystemRoot);
455 wcscat(FullNtDllPath, L"\\system32\\ntdll.dll");
456
457 /* add entry for ntdll */
458 NtModule = (PLDR_DATA_TABLE_ENTRY)
459 RtlAllocateHeap(Peb->ProcessHeap,
460 0,
461 sizeof(LDR_DATA_TABLE_ENTRY));
462 if (NtModule == NULL)
463 {
464 DPRINT1("Failed to create loader module entry (NTDLL)\n");
465 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
466 }
467 memset(NtModule, 0, sizeof(LDR_DATA_TABLE_ENTRY));
468
469 NtModule->DllBase = BaseAddress;
470 NtModule->EntryPoint = 0; /* no entry point */
471 RtlCreateUnicodeString(&NtModule->FullDllName, FullNtDllPath);
472 RtlCreateUnicodeString(&NtModule->BaseDllName, L"ntdll.dll");
473 NtModule->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
474
475 NtModule->LoadCount = -1; /* don't unload */
476 NtModule->TlsIndex = -1;
477 NtModule->SectionPointer = NULL;
478 NtModule->CheckSum = 0;
479
480 NTHeaders = RtlImageNtHeader(NtModule->DllBase);
481 NtModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
482 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
483
484 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
485 &NtModule->InLoadOrderLinks);
486 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
487 &NtModule->InInitializationOrderModuleList);
488
489 /* add entry for executable (becomes first list entry) */
490 ExeModule = (PLDR_DATA_TABLE_ENTRY)
491 RtlAllocateHeap(Peb->ProcessHeap,
492 HEAP_ZERO_MEMORY,
493 sizeof(LDR_DATA_TABLE_ENTRY));
494 if (ExeModule == NULL)
495 {
496 DPRINT1("Failed to create loader module infomation\n");
497 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
498 }
499
500 ExeModule->DllBase = Peb->ImageBaseAddress;
501
502 if ((Peb->ProcessParameters == NULL) ||
503 (Peb->ProcessParameters->ImagePathName.Length == 0))
504 {
505 DPRINT1("Failed to access the process parameter block\n");
506 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
507 }
508
509 RtlCreateUnicodeString(&ExeModule->FullDllName,
510 Peb->ProcessParameters->ImagePathName.Buffer);
511 RtlCreateUnicodeString(&ExeModule->BaseDllName,
512 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
513
514 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule->BaseDllName, &ExeModule->FullDllName);
515
516 ExeModule->Flags = LDRP_ENTRY_PROCESSED;
517 ExeModule->LoadCount = -1; /* don't unload */
518 ExeModule->TlsIndex = -1;
519 ExeModule->SectionPointer = NULL;
520 ExeModule->CheckSum = 0;
521
522 NTHeaders = RtlImageNtHeader(ExeModule->DllBase);
523 ExeModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
524 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
525
526 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
527
528 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
529 &ExeModule->InLoadOrderLinks);
530
531 LdrpInitLoader();
532
533 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
534 ExeModule->EntryPoint = EntryPoint;
535
536 /* all required dlls are loaded now */
537 Peb->Ldr->Initialized = TRUE;
538
539 /* Check before returning that we can run the image safely. */
540 if (EntryPoint == NULL)
541 {
542 DPRINT1("Failed to initialize image\n");
543 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
544 }
545
546 /* Break into debugger */
547 if (Peb->BeingDebugged)
548 DbgBreakPoint();
549 }
550
551 VOID
552 NTAPI
553 LdrpInit(PCONTEXT Context,
554 PVOID SystemArgument1,
555 PVOID SystemArgument2)
556 {
557 if (!LdrpInitialized)
558 {
559 if (!_InterlockedExchange(&LdrpInitLock, 1))
560 {
561 LdrpInit2(Context, SystemArgument1, SystemArgument2);
562 LdrpInitialized = TRUE;
563 }
564 else
565 {
566 LARGE_INTEGER Interval = {{-200000, -1}};
567
568 do
569 {
570 NtDelayExecution(FALSE, &Interval);
571 }
572 while (!LdrpInitialized);
573 }
574 }
575
576 /* attach the thread */
577 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
578 LdrpAttachThread();
579 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
580 }
581
582 /* EOF */