8e8c7c227eead713de491c71d84cde223ff17314
[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 STDCALL 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=%08x\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 STDCALL
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 = (PPEB)(PEB_BASE);
263 DPRINT("Peb %x\n", Peb);
264 ImageBase = Peb->ImageBaseAddress;
265 DPRINT("ImageBase %x\n", ImageBase);
266 if (ImageBase <= (PVOID)0x1000)
267 {
268 DPRINT("ImageBase is null\n");
269 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
270 }
271
272 /* If MZ header exists */
273 PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
274 DPRINT("PEDosHeader %x\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_UNSUCCESSFUL);
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 Status = ZwQuerySystemInformation(SystemBasicInformation,
298 &SystemInformation,
299 sizeof(SYSTEM_BASIC_INFORMATION),
300 NULL);
301 if (!NT_SUCCESS(Status))
302 {
303 ZwTerminateProcess(NtCurrentProcess(), Status);
304 }
305
306 Peb->NumberOfProcessors = SystemInformation.NumberOfProcessors;
307
308 /* Initialize Critical Section Data */
309 RtlpInitDeferedCriticalSection();
310
311 /* create process heap */
312 RtlInitializeHeapManager();
313 Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
314 NULL,
315 NTHeaders->OptionalHeader.SizeOfHeapReserve,
316 NTHeaders->OptionalHeader.SizeOfHeapCommit,
317 NULL,
318 NULL);
319 if (Peb->ProcessHeap == 0)
320 {
321 DPRINT1("Failed to create process heap\n");
322 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
323 }
324
325 /* initialized vectored exception handling */
326 RtlpInitializeVectoredExceptionHandling();
327
328 /* initalize peb lock support */
329 RtlInitializeCriticalSection (&PebLock);
330 Peb->FastPebLock = &PebLock;
331 Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
332 Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
333
334 /* initialize tls bitmap */
335 RtlInitializeBitMap (&TlsBitMap,
336 Peb->TlsBitmapBits,
337 TLS_MINIMUM_AVAILABLE);
338 Peb->TlsBitmap = &TlsBitMap;
339 Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
340
341 /* Initialize table of callbacks for the kernel. */
342 Peb->KernelCallbackTable =
343 RtlAllocateHeap(RtlGetProcessHeap(),
344 0,
345 sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM + 1));
346
347 /* initalize loader lock */
348 RtlInitializeCriticalSection (&LoaderLock);
349 Peb->LoaderLock = &LoaderLock;
350
351 /* create loader information */
352 Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
353 0,
354 sizeof(PEB_LDR_DATA));
355 if (Peb->Ldr == NULL)
356 {
357 DPRINT1("Failed to create loader data\n");
358 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
359 }
360 Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
361 Peb->Ldr->Initialized = FALSE;
362 Peb->Ldr->SsHandle = NULL;
363 InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
364 InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
365 InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
366
367 /* Load compatibility settings */
368 LoadCompatibilitySettings(Peb);
369
370 /* Load execution options */
371 LoadImageFileExecutionOptions(Peb);
372
373 /* build full ntdll path */
374 wcscpy (FullNtDllPath, SharedUserData->NtSystemRoot);
375 wcscat (FullNtDllPath, L"\\system32\\ntdll.dll");
376
377 /* add entry for ntdll */
378 NtModule = (PLDR_DATA_TABLE_ENTRY)RtlAllocateHeap (Peb->ProcessHeap,
379 0,
380 sizeof(LDR_DATA_TABLE_ENTRY));
381 if (NtModule == NULL)
382 {
383 DPRINT1("Failed to create loader module entry (NTDLL)\n");
384 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
385 }
386 memset(NtModule, 0, sizeof(LDR_DATA_TABLE_ENTRY));
387
388 NtModule->DllBase = (PVOID)&_image_base__;
389 NtModule->EntryPoint = 0; /* no entry point */
390 RtlCreateUnicodeString (&NtModule->FullDllName,
391 FullNtDllPath);
392 RtlCreateUnicodeString (&NtModule->BaseDllName,
393 L"ntdll.dll");
394 NtModule->Flags = LDRP_IMAGE_DLL|LDRP_ENTRY_PROCESSED;
395
396 NtModule->LoadCount = -1; /* don't unload */
397 NtModule->TlsIndex = -1;
398 NtModule->SectionPointer = NULL;
399 NtModule->CheckSum = 0;
400
401 NTHeaders = RtlImageNtHeader (NtModule->DllBase);
402 NtModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
403 NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
404
405 InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
406 &NtModule->InLoadOrderModuleList);
407 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
408 &NtModule->InInitializationOrderModuleList);
409
410 #if defined(DBG) || defined(KDBG)
411
412 LdrpLoadUserModuleSymbols(NtModule);
413
414 #endif /* DBG || KDBG */
415
416 /* add entry for executable (becomes first list entry) */
417 ExeModule = (PLDR_DATA_TABLE_ENTRY)RtlAllocateHeap (Peb->ProcessHeap,
418 0,
419 sizeof(LDR_DATA_TABLE_ENTRY));
420 if (ExeModule == NULL)
421 {
422 DPRINT1("Failed to create loader module infomation\n");
423 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
424 }
425 ExeModule->DllBase = Peb->ImageBaseAddress;
426
427 if ((Peb->ProcessParameters == NULL) ||
428 (Peb->ProcessParameters->ImagePathName.Length == 0))
429 {
430 DPRINT1("Failed to access the process parameter block\n");
431 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
432 }
433
434 RtlCreateUnicodeString(&ExeModule->FullDllName,
435 Peb->ProcessParameters->ImagePathName.Buffer);
436 RtlCreateUnicodeString(&ExeModule->BaseDllName,
437 wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
438
439 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
440 &ExeModule->BaseDllName,
441 &ExeModule->FullDllName);
442
443 ExeModule->Flags = LDRP_ENTRY_PROCESSED;
444 ExeModule->LoadCount = -1; /* don't unload */
445 ExeModule->TlsIndex = -1;
446 ExeModule->SectionPointer = NULL;
447 ExeModule->CheckSum = 0;
448
449 NTHeaders = RtlImageNtHeader (ExeModule->DllBase);
450 ExeModule->SizeOfImage = LdrpGetResidentSize(NTHeaders);
451 ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
452
453 InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
454 &ExeModule->InLoadOrderModuleList);
455
456 LdrpInitLoader();
457
458 #if defined(DBG) || defined(KDBG)
459
460 LdrpLoadUserModuleSymbols(ExeModule);
461
462 #endif /* DBG || KDBG */
463
464 EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
465 ExeModule->EntryPoint = EntryPoint;
466
467 /* all required dlls are loaded now */
468 Peb->Ldr->Initialized = TRUE;
469
470 /* Check before returning that we can run the image safely. */
471 if (EntryPoint == NULL)
472 {
473 DPRINT1("Failed to initialize image\n");
474 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
475 }
476 }
477 /* attach the thread */
478 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
479 LdrpAttachThread();
480 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
481 }
482
483 /* EOF */