1 /* $Id: startup.c,v 1.56 2003/11/17 02:32:45 hyperion Exp $
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)
11 /* INCLUDES *****************************************************************/
13 #include <reactos/config.h>
14 #include <ddk/ntddk.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>
24 #include <ntdll/ntdll.h>
27 VOID
RtlInitializeHeapManager (VOID
);
28 VOID
LdrpInitLoader(VOID
);
31 /* GLOBALS *******************************************************************/
34 extern unsigned int _image_base__
;
36 static CRITICAL_SECTION PebLock
;
37 static CRITICAL_SECTION LoaderLock
;
38 static RTL_BITMAP TlsBitMap
;
40 ULONG NtGlobalFlag
= 0;
42 #define VALUE_BUFFER_SIZE 256
45 ReadCompatibilitySetting(HANDLE Key
, LPWSTR Value
, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
, DWORD
*Buffer
)
47 UNICODE_STRING ValueName
;
51 RtlInitUnicodeString(&ValueName
, Value
);
52 Status
= NtQueryValueKey(Key
,
54 KeyValuePartialInformation
,
59 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
61 RtlFreeUnicodeString(&ValueName
);
64 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
65 RtlFreeUnicodeString(&ValueName
);
70 LoadCompatibilitySettings(PPEB Peb
)
73 HANDLE UserKey
= NULL
;
76 OBJECT_ATTRIBUTES ObjectAttributes
;
77 UNICODE_STRING KeyName
;
78 UNICODE_STRING ValueName
;
79 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
80 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
82 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
83 SPMajorVersion
, SPMinorVersion
= 0;
85 if(Peb
->ProcessParameters
&&
86 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
88 Status
= RtlOpenCurrentUser(KEY_READ
,
90 if (!NT_SUCCESS(Status
))
95 RtlRosInitUnicodeStringFromLiteral(&KeyName
,
96 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
98 InitializeObjectAttributes(&ObjectAttributes
,
100 OBJ_CASE_INSENSITIVE
,
104 Status
= NtOpenKey(&KeyHandle
,
108 if (!NT_SUCCESS(Status
))
110 if (UserKey
) NtClose(UserKey
);
114 /* query version name for application */
115 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
116 Status
= NtQueryValueKey(KeyHandle
,
117 &Peb
->ProcessParameters
->ImagePathName
,
118 KeyValuePartialInformation
,
123 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
126 if (UserKey
) NtClose(UserKey
);
130 ValueName
.Length
= ValueInfo
->DataLength
;
131 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
132 ValueName
.Buffer
= (PWSTR
)ValueInfo
->Data
;
134 /* load version info */
135 InitializeObjectAttributes(&ObjectAttributes
,
137 OBJ_CASE_INSENSITIVE
,
141 Status
= NtOpenKey(&SubKeyHandle
,
145 if (!NT_SUCCESS(Status
))
148 if (UserKey
) NtClose(UserKey
);
152 DPRINT("Loading version information for: %wZ\n", &ValueName
);
154 /* read settings from registry */
155 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
157 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
159 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
161 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
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
;
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
;
178 NtClose(SubKeyHandle
);
180 if (UserKey
) NtClose(UserKey
);
187 /* FUNCTIONS *****************************************************************/
190 __true_LdrInitializeThunk (ULONG Unknown1
,
195 PIMAGE_NT_HEADERS NTHeaders
;
197 PIMAGE_DOS_HEADER PEDosHeader
;
200 PLDR_MODULE NtModule
; // ntdll
201 PLDR_MODULE ExeModule
; // executable
202 NLSTABLEINFO NlsTable
;
203 WCHAR FullNtDllPath
[MAX_PATH
];
205 DPRINT("LdrInitializeThunk()\n");
206 if (NtCurrentPeb()->Ldr
!= NULL
&& NtCurrentPeb()->Ldr
->Initialized
== TRUE
)
208 PLIST_ENTRY current_entry
;
209 PDLLMAIN_FUNC Entrypoint
;
212 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
214 NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
.Flink
;
215 while (current_entry
!=
216 &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
)
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
)
224 (VOID
)Entrypoint(current
->BaseAddress
, DLL_THREAD_ATTACH
, NULL
);
226 current_entry
= current_entry
->Flink
;
228 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
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)
238 DPRINT("ImageBase is null\n");
239 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
242 NtGlobalFlag
= Peb
->NtGlobalFlag
;
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
)
251 DbgPrint("Image has bad header\n");
252 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
255 /* normalize process parameters */
256 RtlNormalizeProcessParams (Peb
->ProcessParameters
);
258 /* Initialize NLS data */
259 RtlInitNlsTables (Peb
->AnsiCodePageData
,
260 Peb
->OemCodePageData
,
261 Peb
->UnicodeCaseTableData
,
263 RtlResetRtlTranslations (&NlsTable
);
265 NTHeaders
= (PIMAGE_NT_HEADERS
)(ImageBase
+ PEDosHeader
->e_lfanew
);
267 /* create process heap */
268 RtlInitializeHeapManager();
269 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
271 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
272 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
275 if (Peb
->ProcessHeap
== 0)
277 DbgPrint("Failed to create process heap\n");
278 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
281 /* initalize peb lock support */
282 RtlInitializeCriticalSection (&PebLock
);
283 Peb
->FastPebLock
= &PebLock
;
284 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
285 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
287 /* initialize tls bitmap */
288 RtlInitializeBitMap (&TlsBitMap
,
290 TLS_MINIMUM_AVAILABLE
);
291 Peb
->TlsBitmap
= &TlsBitMap
;
292 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
294 /* Initialize table of callbacks for the kernel. */
295 Peb
->KernelCallbackTable
=
296 RtlAllocateHeap(RtlGetProcessHeap(),
298 sizeof(PVOID
) * (USER32_CALLBACK_MAXIMUM
+ 1));
300 /* initalize loader lock */
301 RtlInitializeCriticalSection (&LoaderLock
);
302 Peb
->LoaderLock
= &LoaderLock
;
304 /* create loader information */
305 Peb
->Ldr
= (PPEB_LDR_DATA
)RtlAllocateHeap (Peb
->ProcessHeap
,
307 sizeof(PEB_LDR_DATA
));
308 if (Peb
->Ldr
== NULL
)
310 DbgPrint("Failed to create loader data\n");
311 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
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
);
320 /* Load compatibility settings */
321 LoadCompatibilitySettings(Peb
);
323 /* build full ntdll path */
324 wcscpy (FullNtDllPath
, SharedUserData
->NtSystemRoot
);
325 wcscat (FullNtDllPath
, L
"\\system32\\ntdll.dll");
327 /* add entry for ntdll */
328 NtModule
= (PLDR_MODULE
)RtlAllocateHeap (Peb
->ProcessHeap
,
331 if (NtModule
== NULL
)
333 DbgPrint("Failed to create loader module entry (NTDLL)\n");
334 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
336 memset(NtModule
, 0, sizeof(LDR_MODULE
));
338 NtModule
->BaseAddress
= (PVOID
)&_image_base__
;
339 NtModule
->EntryPoint
= 0; /* no entry point */
340 RtlCreateUnicodeString (&NtModule
->FullDllName
,
342 RtlCreateUnicodeString (&NtModule
->BaseDllName
,
345 NtModule
->LoadCount
= -1; /* don't unload */
346 NtModule
->TlsIndex
= 0;
347 NtModule
->SectionHandle
= NULL
;
348 NtModule
->CheckSum
= 0;
350 NTHeaders
= RtlImageNtHeader (NtModule
->BaseAddress
);
351 NtModule
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
352 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
354 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
355 &NtModule
->InLoadOrderModuleList
);
356 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
357 &NtModule
->InInitializationOrderModuleList
);
361 LdrpLoadUserModuleSymbols(NtModule
);
365 /* add entry for executable (becomes first list entry) */
366 ExeModule
= (PLDR_MODULE
)RtlAllocateHeap (Peb
->ProcessHeap
,
369 if (ExeModule
== NULL
)
371 DbgPrint("Failed to create loader module infomation\n");
372 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
374 ExeModule
->BaseAddress
= Peb
->ImageBaseAddress
;
376 if ((Peb
->ProcessParameters
== NULL
) ||
377 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
379 DbgPrint("Failed to access the process parameter block\n");
380 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
383 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
384 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
385 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
386 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
388 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
389 &ExeModule
->BaseDllName
,
390 &ExeModule
->FullDllName
);
392 ExeModule
->Flags
= 0;
393 ExeModule
->LoadCount
= -1; /* don't unload */
394 ExeModule
->TlsIndex
= 0;
395 ExeModule
->SectionHandle
= NULL
;
396 ExeModule
->CheckSum
= 0;
398 NTHeaders
= RtlImageNtHeader (ExeModule
->BaseAddress
);
399 ExeModule
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
400 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
402 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
403 &ExeModule
->InLoadOrderModuleList
);
409 LdrpLoadUserModuleSymbols(ExeModule
);
413 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
414 ExeModule
->EntryPoint
= (ULONG
)EntryPoint
;
416 /* all required dlls are loaded now */
417 Peb
->Ldr
->Initialized
= TRUE
;
419 /* Check before returning that we can run the image safely. */
420 if (EntryPoint
== NULL
)
422 DbgPrint("Failed to initialize image\n");
423 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);