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