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