- Create another branch for networking fixes
[reactos.git] / 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 ValueString;
75 UNICODE_STRING ImageName;
76 UNICODE_STRING ImagePathName;
77 WCHAR ValueBuffer[64];
78 ULONG ValueSize;
79
80 if (Peb->ProcessParameters &&
81 Peb->ProcessParameters->ImagePathName.Length > 0)
82 {
83 DPRINT("%wZ\n", &Peb->ProcessParameters->ImagePathName);
84
85 ImagePathName = Peb->ProcessParameters->ImagePathName;
86 ImageName.Buffer = ImagePathName.Buffer + ImagePathName.Length / sizeof(WCHAR);
87 ImageName.Length = 0;
88
89 while (ImagePathName.Buffer < ImageName.Buffer)
90 {
91 ImageName.Buffer--;
92 if (*ImageName.Buffer == L'\\')
93 {
94 ImageName.Buffer++;
95 break;
96 }
97 }
98
99 ImageName.Length = ImagePathName.Length -
100 (ImageName.Buffer - ImagePathName.Buffer) * sizeof(WCHAR);
101 ImageName.MaximumLength = ImageName.Length +
102 ImagePathName.MaximumLength - ImagePathName.Length;
103
104 DPRINT("%wZ\n", &ImageName);
105
106 /* global flag */
107 Status = LdrQueryImageFileExecutionOptions(&ImageName,
108 L"GlobalFlag",
109 REG_SZ,
110 (PVOID)ValueBuffer,
111 sizeof(ValueBuffer),
112 &ValueSize);
113 if (NT_SUCCESS(Status))
114 {
115 ValueString.Buffer = ValueBuffer;
116 ValueString.Length = ValueSize - sizeof(WCHAR);
117 ValueString.MaximumLength = sizeof(ValueBuffer);
118 Status = RtlUnicodeStringToInteger(&ValueString, 16, &Value);
119 if (NT_SUCCESS(Status))
120 {
121 Peb->NtGlobalFlag |= Value;
122 DPRINT("GlobalFlag: Key='%S', Value=0x%lx\n", ValueBuffer, Value);
123 }
124 }
125 /*
126 * FIXME:
127 * read more options
128 */
129 }
130 }
131
132 BOOLEAN
133 FASTCALL
134 LoadCompatibilitySettings(PPEB Peb)
135 {
136 NTSTATUS Status;
137 HANDLE UserKey = NULL;
138 HANDLE KeyHandle;
139 HANDLE SubKeyHandle;
140 OBJECT_ATTRIBUTES ObjectAttributes;
141 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(
142 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
143 UNICODE_STRING ValueName;
144 UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
145 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
146 ULONG Length;
147 DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
148 SPMajorVersion, SPMinorVersion = 0;
149
150 if (Peb->ProcessParameters &&
151 (Peb->ProcessParameters->ImagePathName.Length > 0))
152 {
153 Status = RtlOpenCurrentUser(KEY_READ, &UserKey);
154 if (!NT_SUCCESS(Status))
155 {
156 return FALSE;
157 }
158
159 InitializeObjectAttributes(&ObjectAttributes,
160 &KeyName,
161 OBJ_CASE_INSENSITIVE,
162 UserKey,
163 NULL);
164
165 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
166
167 if (!NT_SUCCESS(Status))
168 {
169 if (UserKey)
170 NtClose(UserKey);
171 return FALSE;
172 }
173
174 /* query version name for application */
175 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer;
176 Status = NtQueryValueKey(KeyHandle,
177 &Peb->ProcessParameters->ImagePathName,
178 KeyValuePartialInformation,
179 ValueBuffer,
180 VALUE_BUFFER_SIZE,
181 &Length);
182
183 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
184 {
185 NtClose(KeyHandle);
186 if (UserKey)
187 NtClose(UserKey);
188 return FALSE;
189 }
190
191 ValueName.Length = ValueInfo->DataLength;
192 ValueName.MaximumLength = ValueInfo->DataLength;
193 ValueName.Buffer = (PWSTR) ValueInfo->Data;
194
195 /* load version info */
196 InitializeObjectAttributes(&ObjectAttributes,
197 &ValueName,
198 OBJ_CASE_INSENSITIVE,
199 KeyHandle,
200 NULL);
201
202 Status = NtOpenKey(&SubKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
203
204 if (!NT_SUCCESS(Status))
205 {
206 NtClose(KeyHandle);
207 if (UserKey)
208 NtClose(UserKey);
209 return FALSE;
210 }
211
212 DPRINT("Loading version information for: %wZ\n", &ValueName);
213
214 /* read settings from registry */
215 if (!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
216 goto finish;
217 if (!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
218 goto finish;
219 if (!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
220 goto finish;
221 if (!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
222 goto finish;
223
224 /* now assign the settings */
225 Peb->OSMajorVersion = (ULONG) MajorVersion;
226 Peb->OSMinorVersion = (ULONG) MinorVersion;
227 Peb->OSBuildNumber = (USHORT) BuildNumber;
228 Peb->OSPlatformId = (ULONG) PlatformId;
229
230 /* optional service pack version numbers */
231 if (ReadCompatibilitySetting(SubKeyHandle,
232 L"SPMajorVersion",
233 ValueInfo,
234 &SPMajorVersion) &&
235 ReadCompatibilitySetting(SubKeyHandle,
236 L"SPMinorVersion",
237 ValueInfo,
238 &SPMinorVersion))
239 {
240 Peb->OSCSDVersion = ((SPMajorVersion & 0xFF) << 8) |
241 (SPMinorVersion & 0xFF);
242 }
243
244 finish:
245 /* we're finished */
246 NtClose(SubKeyHandle);
247 NtClose(KeyHandle);
248 if (UserKey)
249 NtClose(UserKey);
250 return TRUE;
251 }
252
253 return FALSE;
254 }
255
256 static
257 VOID
258 LdrpInit2(PCONTEXT Context,
259 PVOID SystemArgument1,
260 PVOID SystemArgument2)
261 {
262 PIMAGE_NT_HEADERS NTHeaders;
263 PEPFUNC EntryPoint;
264 PIMAGE_DOS_HEADER PEDosHeader;
265 PVOID ImageBase;
266 PPEB Peb = NtCurrentPeb();
267 PLDR_DATA_TABLE_ENTRY NtModule; // ntdll
268 NLSTABLEINFO NlsTable;
269 WCHAR FullNtDllPath[MAX_PATH];
270 SYSTEM_BASIC_INFORMATION SystemInformation;
271 NTSTATUS Status;
272 PVOID BaseAddress = SystemArgument1;
273
274 DPRINT("LdrpInit()\n");
275 DPRINT("Peb %p\n", Peb);
276 ImageBase = Peb->ImageBaseAddress;
277 DPRINT("ImageBase %p\n", ImageBase);
278
279 if (ImageBase <= (PVOID) 0x1000)
280 {
281 DPRINT("ImageBase is null\n");
282 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
283 }
284
285 /* If MZ header exists */
286 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
287 DPRINT("PEDosHeader %p\n", PEDosHeader);
288
289 if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
290 PEDosHeader->e_lfanew == 0L ||
291 *(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE)
292 {
293 DPRINT1("Image has bad header\n");
294 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
295 }
296
297 /* normalize process parameters */
298 RtlNormalizeProcessParams(Peb->ProcessParameters);
299
300 /* Initialize NLS data */
301 RtlInitNlsTables(Peb->AnsiCodePageData,
302 Peb->OemCodePageData,
303 Peb->UnicodeCaseTableData,
304 &NlsTable);
305 RtlResetRtlTranslations(&NlsTable);
306
307 NTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageBase + PEDosHeader->e_lfanew);
308
309 /* Get number of processors */
310 DPRINT("Here\n");
311 Status = ZwQuerySystemInformation(SystemBasicInformation,
312 &SystemInformation,
313 sizeof(SYSTEM_BASIC_INFORMATION),
314 NULL);
315 DPRINT("Here2\n");
316 if (!NT_SUCCESS(Status))
317 {
318 ZwTerminateProcess(NtCurrentProcess(), Status);
319 }
320
321 Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors;
322
323 /* Initialize Critical Section Data */
324 RtlpInitDeferedCriticalSection();
325
326 /* create process heap */
327 RtlInitializeHeapManager();
328 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
329 NULL,
330 NTHeaders->OptionalHeader.SizeOfHeapReserve,
331 NTHeaders->OptionalHeader.SizeOfHeapCommit,
332 NULL,
333 NULL);
334 if (Peb->ProcessHeap == 0)
335 {
336 DPRINT1("Failed to create process heap\n");
337 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
338 }
339
340 /* initialized vectored exception handling */
341 RtlpInitializeVectoredExceptionHandling();
342
343 /* initalize peb lock support */
344 RtlInitializeCriticalSection(&PebLock);
345 Peb->FastPebLock = &PebLock;
346 Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
347 Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
348
349 /* initialize tls bitmaps */
350 RtlInitializeBitMap(&TlsBitMap, Peb->TlsBitmapBits, TLS_MINIMUM_AVAILABLE);
351 RtlInitializeBitMap(&TlsExpansionBitMap, Peb->TlsExpansionBitmapBits, TLS_EXPANSION_SLOTS);
352
353 Peb->TlsBitmap = &TlsBitMap;
354 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
355 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
356
357 /* Initialize table of callbacks for the kernel. */
358 Peb->KernelCallbackTable = RtlAllocateHeap(RtlGetProcessHeap(),
359 0,
360 sizeof(PVOID) *
361 (USER32_CALLBACK_MAXIMUM + 1));
362 if (Peb->KernelCallbackTable == NULL)
363 {
364 DPRINT1("Failed to create callback table\n");
365 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
366 }
367
368 /* initalize loader lock */
369 RtlInitializeCriticalSection(&LoaderLock);
370 Peb->LoaderLock = &LoaderLock;
371
372 /* create loader information */
373 Peb->Ldr = (PPEB_LDR_DATA) RtlAllocateHeap(Peb->ProcessHeap,
374 0,
375 sizeof(PEB_LDR_DATA));
376 if (Peb->Ldr == NULL)
377 {
378 DPRINT1("Failed to create loader data\n");
379 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
380 }
381
382 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
383 Peb->Ldr->Initialized = FALSE;
384 Peb->Ldr->SsHandle = NULL;
385 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
386 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
387 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
388
389 /* Load compatibility settings */
390 LoadCompatibilitySettings(Peb);
391
392 /* Load execution options */
393 LoadImageFileExecutionOptions(Peb);
394
395 /* build full ntdll path */
396 wcscpy(FullNtDllPath, SharedUserData->NtSystemRoot);
397 wcscat(FullNtDllPath, L"\\system32\\ntdll.dll");
398
399 /* add entry for ntdll */
400 NtModule = (PLDR_DATA_TABLE_ENTRY)
401 RtlAllocateHeap(Peb->ProcessHeap,
402 0,
403 sizeof(LDR_DATA_TABLE_ENTRY));
404 if (NtModule == NULL)
405 {
406 DPRINT1("Failed to create loader module entry (NTDLL)\n");
407 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
408 }
409 memset(NtModule, 0, sizeof(LDR_DATA_TABLE_ENTRY));
410
411 NtModule->DllBase = BaseAddress;
412 NtModule->EntryPoint = 0; /* no entry point */
413 RtlCreateUnicodeString(&NtModule->FullDllName, FullNtDllPath);
414 RtlCreateUnicodeString(&NtModule->BaseDllName, L"ntdll.dll");
415 NtModule->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
416
417 NtModule->LoadCount = -1; /* don't unload */
418 NtModule->TlsIndex = -1;
419 NtModule->SectionPointer = NULL;
420 NtModule->CheckSum = 0;
421
422 NTHeaders = RtlImageNtHeader(NtModule->DllBase);
423 NtModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
424 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
425
426 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
427 &NtModule->InLoadOrderLinks);
428 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
429 &NtModule->InInitializationOrderModuleList);
430
431 /* add entry for executable (becomes first list entry) */
432 ExeModule = (PLDR_DATA_TABLE_ENTRY)
433 RtlAllocateHeap(Peb->ProcessHeap,
434 0,
435 sizeof(LDR_DATA_TABLE_ENTRY));
436 if (ExeModule == NULL)
437 {
438 DPRINT1("Failed to create loader module infomation\n");
439 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES);
440 }
441
442 ExeModule->DllBase = Peb->ImageBaseAddress;
443
444 if ((Peb->ProcessParameters == NULL) ||
445 (Peb->ProcessParameters->ImagePathName.Length == 0))
446 {
447 DPRINT1("Failed to access the process parameter block\n");
448 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
449 }
450
451 RtlCreateUnicodeString(&ExeModule->FullDllName,
452 Peb->ProcessParameters->ImagePathName.Buffer);
453 RtlCreateUnicodeString(&ExeModule->BaseDllName,
454 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
455
456 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n", &ExeModule->BaseDllName, &ExeModule->FullDllName);
457
458 ExeModule->Flags = LDRP_ENTRY_PROCESSED;
459 ExeModule->LoadCount = -1; /* don't unload */
460 ExeModule->TlsIndex = -1;
461 ExeModule->SectionPointer = NULL;
462 ExeModule->CheckSum = 0;
463
464 NTHeaders = RtlImageNtHeader(ExeModule->DllBase);
465 ExeModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
466 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
467
468 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
469
470 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
471 &ExeModule->InLoadOrderLinks);
472
473 LdrpInitLoader();
474
475 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
476 ExeModule->EntryPoint = EntryPoint;
477
478 /* all required dlls are loaded now */
479 Peb->Ldr->Initialized = TRUE;
480
481 /* Check before returning that we can run the image safely. */
482 if (EntryPoint == NULL)
483 {
484 DPRINT1("Failed to initialize image\n");
485 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT);
486 }
487
488 /* Break into debugger */
489 if (Peb->BeingDebugged)
490 DbgBreakPoint();
491 }
492
493 VOID
494 NTAPI
495 LdrpInit(PCONTEXT Context,
496 PVOID SystemArgument1,
497 PVOID SystemArgument2)
498 {
499 if (!LdrpInitialized)
500 {
501 if (!_InterlockedExchange(&LdrpInitLock, 1))
502 {
503 LdrpInit2(Context, SystemArgument1, SystemArgument2);
504 LdrpInitialized = TRUE;
505 }
506 else
507 {
508 LARGE_INTEGER Interval = {{-200000, -1}};
509
510 do
511 {
512 NtDelayExecution(FALSE, &Interval);
513 }
514 while (!LdrpInitialized);
515 }
516 }
517
518 /* attach the thread */
519 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
520 LdrpAttachThread();
521 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
522 }
523
524 /* EOF */