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