1 /* $Id: startup.c,v 1.60 2004/12/15 03:00:33 royce 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
);
30 /* GLOBALS *******************************************************************/
33 extern unsigned int _image_base__
;
35 static CRITICAL_SECTION PebLock
;
36 static CRITICAL_SECTION LoaderLock
;
37 static RTL_BITMAP TlsBitMap
;
38 PLDR_MODULE ExeModule
;
40 ULONG NtGlobalFlag
= 0;
42 NTSTATUS
LdrpAttachThread (VOID
);
45 #define VALUE_BUFFER_SIZE 256
48 ReadCompatibilitySetting(HANDLE Key
, LPWSTR Value
, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
, DWORD
*Buffer
)
50 UNICODE_STRING ValueName
;
54 RtlInitUnicodeString(&ValueName
, Value
);
55 Status
= NtQueryValueKey(Key
,
57 KeyValuePartialInformation
,
62 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
64 RtlFreeUnicodeString(&ValueName
);
67 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
68 RtlFreeUnicodeString(&ValueName
);
73 LoadImageFileExecutionOptions(PPEB Peb
)
75 NTSTATUS Status
= STATUS_SUCCESS
;
77 UNICODE_STRING ValueString
;
78 WCHAR ValueBuffer
[64];
81 if (Peb
->ProcessParameters
&&
82 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
85 Status
= LdrQueryImageFileExecutionOptions (&Peb
->ProcessParameters
->ImagePathName
,
91 if (NT_SUCCESS(Status
))
93 ValueString
.Buffer
= ValueBuffer
+ 1;
94 ValueString
.Length
= ValueSize
- 2 * sizeof(WCHAR
);
95 ValueString
.MaximumLength
= sizeof(ValueBuffer
);
96 RtlUnicodeStringToInteger(&ValueString
, 16, &Value
);
97 Peb
->NtGlobalFlag
|= Value
;
98 DPRINT("GlobalFlag: Key='%S', Value=%08x\n", ValueBuffer
, Value
);
105 NtGlobalFlag
= Peb
->NtGlobalFlag
;
112 LoadCompatibilitySettings(PPEB Peb
)
115 HANDLE UserKey
= NULL
;
118 OBJECT_ATTRIBUTES ObjectAttributes
;
119 UNICODE_STRING KeyName
;
120 UNICODE_STRING ValueName
;
121 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
122 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
124 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
125 SPMajorVersion
, SPMinorVersion
= 0;
127 if(Peb
->ProcessParameters
&&
128 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
130 Status
= RtlOpenCurrentUser(KEY_READ
,
132 if (!NT_SUCCESS(Status
))
137 RtlRosInitUnicodeStringFromLiteral(&KeyName
,
138 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
140 InitializeObjectAttributes(&ObjectAttributes
,
142 OBJ_CASE_INSENSITIVE
,
146 Status
= NtOpenKey(&KeyHandle
,
150 if (!NT_SUCCESS(Status
))
152 if (UserKey
) NtClose(UserKey
);
156 /* query version name for application */
157 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
158 Status
= NtQueryValueKey(KeyHandle
,
159 &Peb
->ProcessParameters
->ImagePathName
,
160 KeyValuePartialInformation
,
165 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
168 if (UserKey
) NtClose(UserKey
);
172 ValueName
.Length
= ValueInfo
->DataLength
;
173 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
174 ValueName
.Buffer
= (PWSTR
)ValueInfo
->Data
;
176 /* load version info */
177 InitializeObjectAttributes(&ObjectAttributes
,
179 OBJ_CASE_INSENSITIVE
,
183 Status
= NtOpenKey(&SubKeyHandle
,
187 if (!NT_SUCCESS(Status
))
190 if (UserKey
) NtClose(UserKey
);
194 DPRINT("Loading version information for: %wZ\n", &ValueName
);
196 /* read settings from registry */
197 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
199 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
201 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
203 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
206 /* now assign the settings */
207 Peb
->OSMajorVersion
= (ULONG
)MajorVersion
;
208 Peb
->OSMinorVersion
= (ULONG
)MinorVersion
;
209 Peb
->OSBuildNumber
= (USHORT
)BuildNumber
;
210 Peb
->OSPlatformId
= (ULONG
)PlatformId
;
212 /* optional service pack version numbers */
213 if(ReadCompatibilitySetting(SubKeyHandle
, L
"SPMajorVersion", ValueInfo
, &SPMajorVersion
))
214 Peb
->SPMajorVersion
= (UCHAR
)SPMajorVersion
;
215 if(ReadCompatibilitySetting(SubKeyHandle
, L
"SPMinorVersion", ValueInfo
, &SPMinorVersion
))
216 Peb
->SPMinorVersion
= (UCHAR
)SPMinorVersion
;
220 NtClose(SubKeyHandle
);
222 if (UserKey
) NtClose(UserKey
);
229 /* FUNCTIONS *****************************************************************/
232 __true_LdrInitializeThunk (ULONG Unknown1
,
237 PIMAGE_NT_HEADERS NTHeaders
;
239 PIMAGE_DOS_HEADER PEDosHeader
;
242 PLDR_MODULE NtModule
; // ntdll
243 NLSTABLEINFO NlsTable
;
244 WCHAR FullNtDllPath
[MAX_PATH
];
246 DPRINT("LdrInitializeThunk()\n");
247 if (NtCurrentPeb()->Ldr
== NULL
|| NtCurrentPeb()->Ldr
->Initialized
== FALSE
)
249 Peb
= (PPEB
)(PEB_BASE
);
250 DPRINT("Peb %x\n", Peb
);
251 ImageBase
= Peb
->ImageBaseAddress
;
252 DPRINT("ImageBase %x\n", ImageBase
);
253 if (ImageBase
<= (PVOID
)0x1000)
255 DPRINT("ImageBase is null\n");
256 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
259 /* If MZ header exists */
260 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
261 DPRINT("PEDosHeader %x\n", PEDosHeader
);
262 if (PEDosHeader
->e_magic
!= IMAGE_DOS_MAGIC
||
263 PEDosHeader
->e_lfanew
== 0L ||
264 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_PE_MAGIC
)
266 DPRINT1("Image has bad header\n");
267 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
270 /* normalize process parameters */
271 RtlNormalizeProcessParams (Peb
->ProcessParameters
);
273 /* Initialize NLS data */
274 RtlInitNlsTables (Peb
->AnsiCodePageData
,
275 Peb
->OemCodePageData
,
276 Peb
->UnicodeCaseTableData
,
278 RtlResetRtlTranslations (&NlsTable
);
280 NTHeaders
= (PIMAGE_NT_HEADERS
)(ImageBase
+ PEDosHeader
->e_lfanew
);
282 /* create process heap */
283 RtlInitializeHeapManager();
284 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
286 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
287 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
290 if (Peb
->ProcessHeap
== 0)
292 DPRINT1("Failed to create process heap\n");
293 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
296 /* initalize peb lock support */
297 RtlInitializeCriticalSection (&PebLock
);
298 Peb
->FastPebLock
= &PebLock
;
299 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
300 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
302 /* initialize tls bitmap */
303 RtlInitializeBitMap (&TlsBitMap
,
305 TLS_MINIMUM_AVAILABLE
);
306 Peb
->TlsBitmap
= &TlsBitMap
;
307 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
309 /* Initialize table of callbacks for the kernel. */
310 Peb
->KernelCallbackTable
=
311 RtlAllocateHeap(RtlGetProcessHeap(),
313 sizeof(PVOID
) * (USER32_CALLBACK_MAXIMUM
+ 1));
315 /* initalize loader lock */
316 RtlInitializeCriticalSection (&LoaderLock
);
317 Peb
->LoaderLock
= &LoaderLock
;
319 /* create loader information */
320 Peb
->Ldr
= (PPEB_LDR_DATA
)RtlAllocateHeap (Peb
->ProcessHeap
,
322 sizeof(PEB_LDR_DATA
));
323 if (Peb
->Ldr
== NULL
)
325 DPRINT1("Failed to create loader data\n");
326 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
328 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
329 Peb
->Ldr
->Initialized
= FALSE
;
330 Peb
->Ldr
->SsHandle
= NULL
;
331 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
332 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
333 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
335 /* Load compatibility settings */
336 LoadCompatibilitySettings(Peb
);
338 /* Load execution options */
339 LoadImageFileExecutionOptions(Peb
);
341 /* build full ntdll path */
342 wcscpy (FullNtDllPath
, SharedUserData
->NtSystemRoot
);
343 wcscat (FullNtDllPath
, L
"\\system32\\ntdll.dll");
345 /* add entry for ntdll */
346 NtModule
= (PLDR_MODULE
)RtlAllocateHeap (Peb
->ProcessHeap
,
349 if (NtModule
== NULL
)
351 DPRINT1("Failed to create loader module entry (NTDLL)\n");
352 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
354 memset(NtModule
, 0, sizeof(LDR_MODULE
));
356 NtModule
->BaseAddress
= (PVOID
)&_image_base__
;
357 NtModule
->EntryPoint
= 0; /* no entry point */
358 RtlCreateUnicodeString (&NtModule
->FullDllName
,
360 RtlCreateUnicodeString (&NtModule
->BaseDllName
,
362 NtModule
->Flags
= IMAGE_DLL
|ENTRY_PROCESSED
;
364 NtModule
->LoadCount
= -1; /* don't unload */
365 NtModule
->TlsIndex
= -1;
366 NtModule
->SectionHandle
= NULL
;
367 NtModule
->CheckSum
= 0;
369 NTHeaders
= RtlImageNtHeader (NtModule
->BaseAddress
);
370 NtModule
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
371 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
373 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
374 &NtModule
->InLoadOrderModuleList
);
375 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
376 &NtModule
->InInitializationOrderModuleList
);
378 #if defined(DBG) || defined(KDBG)
380 LdrpLoadUserModuleSymbols(NtModule
);
382 #endif /* DBG || KDBG */
384 /* add entry for executable (becomes first list entry) */
385 ExeModule
= (PLDR_MODULE
)RtlAllocateHeap (Peb
->ProcessHeap
,
388 if (ExeModule
== NULL
)
390 DPRINT1("Failed to create loader module infomation\n");
391 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
393 ExeModule
->BaseAddress
= Peb
->ImageBaseAddress
;
395 if ((Peb
->ProcessParameters
== NULL
) ||
396 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
398 DPRINT1("Failed to access the process parameter block\n");
399 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
402 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
403 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
404 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
405 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
407 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
408 &ExeModule
->BaseDllName
,
409 &ExeModule
->FullDllName
);
411 ExeModule
->Flags
= ENTRY_PROCESSED
;
412 ExeModule
->LoadCount
= -1; /* don't unload */
413 ExeModule
->TlsIndex
= -1;
414 ExeModule
->SectionHandle
= NULL
;
415 ExeModule
->CheckSum
= 0;
417 NTHeaders
= RtlImageNtHeader (ExeModule
->BaseAddress
);
418 ExeModule
->SizeOfImage
= NTHeaders
->OptionalHeader
.SizeOfImage
;
419 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
421 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
422 &ExeModule
->InLoadOrderModuleList
);
426 #if defined(DBG) || defined(KDBG)
428 LdrpLoadUserModuleSymbols(ExeModule
);
430 #endif /* DBG || KDBG */
432 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
433 ExeModule
->EntryPoint
= (ULONG
)EntryPoint
;
435 /* all required dlls are loaded now */
436 Peb
->Ldr
->Initialized
= TRUE
;
438 /* Check before returning that we can run the image safely. */
439 if (EntryPoint
== NULL
)
441 DPRINT1("Failed to initialize image\n");
442 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
445 /* attach the thread */
446 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
448 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);