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 *****************************************************************/
16 #include <win32k/callback.h>
18 VOID
RtlInitializeHeapManager (VOID
);
19 VOID
LdrpInitLoader(VOID
);
20 VOID STDCALL
RtlpInitDeferedCriticalSection(VOID
);
22 /* GLOBALS *******************************************************************/
25 extern unsigned int _image_base__
;
27 static RTL_CRITICAL_SECTION PebLock
;
28 static RTL_CRITICAL_SECTION LoaderLock
;
29 static RTL_BITMAP TlsBitMap
;
30 PLDR_DATA_TABLE_ENTRY ExeModule
;
32 NTSTATUS
LdrpAttachThread (VOID
);
34 VOID
RtlpInitializeVectoredExceptionHandling(VOID
);
37 #define VALUE_BUFFER_SIZE 256
40 ReadCompatibilitySetting(HANDLE Key
, LPWSTR Value
, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
, DWORD
*Buffer
)
42 UNICODE_STRING ValueName
;
46 RtlInitUnicodeString(&ValueName
, Value
);
47 Status
= NtQueryValueKey(Key
,
49 KeyValuePartialInformation
,
54 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_DWORD
))
56 RtlFreeUnicodeString(&ValueName
);
59 RtlCopyMemory(Buffer
, &ValueInfo
->Data
[0], sizeof(DWORD
));
60 RtlFreeUnicodeString(&ValueName
);
65 LoadImageFileExecutionOptions(PPEB Peb
)
67 NTSTATUS Status
= STATUS_SUCCESS
;
69 UNICODE_STRING ValueString
;
70 UNICODE_STRING ImageName
;
71 UNICODE_STRING ImagePathName
;
72 WCHAR ValueBuffer
[64];
75 if (Peb
->ProcessParameters
&&
76 Peb
->ProcessParameters
->ImagePathName
.Length
> 0)
78 DPRINT("%wZ\n", &Peb
->ProcessParameters
->ImagePathName
);
80 ImagePathName
= Peb
->ProcessParameters
->ImagePathName
;
81 ImageName
.Buffer
= ImagePathName
.Buffer
+ ImagePathName
.Length
/ sizeof(WCHAR
);
83 while (ImagePathName
.Buffer
< ImageName
.Buffer
)
86 if (*ImageName
.Buffer
== L
'\\')
92 ImageName
.Length
= ImagePathName
.Length
- (ImageName
.Buffer
- ImagePathName
.Buffer
) * sizeof(WCHAR
);
93 ImageName
.MaximumLength
= ImageName
.Length
+ ImagePathName
.MaximumLength
- ImagePathName
.Length
;
95 DPRINT("%wZ\n", &ImageName
);
98 Status
= LdrQueryImageFileExecutionOptions (&ImageName
,
104 if (NT_SUCCESS(Status
))
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
))
112 Peb
->NtGlobalFlag
|= Value
;
113 DPRINT("GlobalFlag: Key='%S', Value=%08x\n", ValueBuffer
, Value
);
127 LoadCompatibilitySettings(PPEB Peb
)
130 HANDLE UserKey
= NULL
;
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
;
140 DWORD MajorVersion
, MinorVersion
, BuildNumber
, PlatformId
,
141 SPMajorVersion
, SPMinorVersion
= 0;
143 if(Peb
->ProcessParameters
&&
144 (Peb
->ProcessParameters
->ImagePathName
.Length
> 0))
146 Status
= RtlOpenCurrentUser(KEY_READ
,
148 if (!NT_SUCCESS(Status
))
153 InitializeObjectAttributes(&ObjectAttributes
,
155 OBJ_CASE_INSENSITIVE
,
159 Status
= NtOpenKey(&KeyHandle
,
163 if (!NT_SUCCESS(Status
))
165 if (UserKey
) NtClose(UserKey
);
169 /* query version name for application */
170 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
171 Status
= NtQueryValueKey(KeyHandle
,
172 &Peb
->ProcessParameters
->ImagePathName
,
173 KeyValuePartialInformation
,
178 if (!NT_SUCCESS(Status
) || (ValueInfo
->Type
!= REG_SZ
))
181 if (UserKey
) NtClose(UserKey
);
185 ValueName
.Length
= ValueInfo
->DataLength
;
186 ValueName
.MaximumLength
= ValueInfo
->DataLength
;
187 ValueName
.Buffer
= (PWSTR
)ValueInfo
->Data
;
189 /* load version info */
190 InitializeObjectAttributes(&ObjectAttributes
,
192 OBJ_CASE_INSENSITIVE
,
196 Status
= NtOpenKey(&SubKeyHandle
,
200 if (!NT_SUCCESS(Status
))
203 if (UserKey
) NtClose(UserKey
);
207 DPRINT("Loading version information for: %wZ\n", &ValueName
);
209 /* read settings from registry */
210 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MajorVersion", ValueInfo
, &MajorVersion
))
212 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"MinorVersion", ValueInfo
, &MinorVersion
))
214 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"BuildNumber", ValueInfo
, &BuildNumber
))
216 if(!ReadCompatibilitySetting(SubKeyHandle
, L
"PlatformId", ValueInfo
, &PlatformId
))
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
;
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);
232 NtClose(SubKeyHandle
);
234 if (UserKey
) NtClose(UserKey
);
240 /* FUNCTIONS *****************************************************************/
244 LdrpInit(PCONTEXT Context
,
245 PVOID SystemArgument1
,
246 PVOID SystemArgument2
)
248 PIMAGE_NT_HEADERS NTHeaders
;
250 PIMAGE_DOS_HEADER PEDosHeader
;
253 PLDR_DATA_TABLE_ENTRY NtModule
; // ntdll
254 NLSTABLEINFO NlsTable
;
255 WCHAR FullNtDllPath
[MAX_PATH
];
256 SYSTEM_BASIC_INFORMATION SystemInformation
;
259 DPRINT("LdrpInit()\n");
260 if (NtCurrentPeb()->Ldr
== NULL
|| NtCurrentPeb()->Ldr
->Initialized
== FALSE
)
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)
268 DPRINT("ImageBase is null\n");
269 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
272 /* If MZ header exists */
273 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
274 DPRINT("PEDosHeader %x\n", PEDosHeader
);
276 if (PEDosHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
||
277 PEDosHeader
->e_lfanew
== 0L ||
278 *(PULONG
)((PUCHAR
)ImageBase
+ PEDosHeader
->e_lfanew
) != IMAGE_NT_SIGNATURE
)
280 DPRINT1("Image has bad header\n");
281 ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL
);
284 /* normalize process parameters */
285 RtlNormalizeProcessParams (Peb
->ProcessParameters
);
287 /* Initialize NLS data */
288 RtlInitNlsTables (Peb
->AnsiCodePageData
,
289 Peb
->OemCodePageData
,
290 Peb
->UnicodeCaseTableData
,
292 RtlResetRtlTranslations (&NlsTable
);
294 NTHeaders
= (PIMAGE_NT_HEADERS
)((ULONG_PTR
)ImageBase
+ PEDosHeader
->e_lfanew
);
296 /* Get number of processors */
297 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
299 sizeof(SYSTEM_BASIC_INFORMATION
),
301 if (!NT_SUCCESS(Status
))
303 ZwTerminateProcess(NtCurrentProcess(), Status
);
306 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
308 /* Initialize Critical Section Data */
309 RtlpInitDeferedCriticalSection();
311 /* create process heap */
312 RtlInitializeHeapManager();
313 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
315 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
316 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
319 if (Peb
->ProcessHeap
== 0)
321 DPRINT1("Failed to create process heap\n");
322 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
325 /* initialized vectored exception handling */
326 RtlpInitializeVectoredExceptionHandling();
328 /* initalize peb lock support */
329 RtlInitializeCriticalSection (&PebLock
);
330 Peb
->FastPebLock
= &PebLock
;
331 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
332 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
334 /* initialize tls bitmap */
335 RtlInitializeBitMap (&TlsBitMap
,
337 TLS_MINIMUM_AVAILABLE
);
338 Peb
->TlsBitmap
= &TlsBitMap
;
339 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
341 /* Initialize table of callbacks for the kernel. */
342 Peb
->KernelCallbackTable
=
343 RtlAllocateHeap(RtlGetProcessHeap(),
345 sizeof(PVOID
) * (USER32_CALLBACK_MAXIMUM
+ 1));
347 /* initalize loader lock */
348 RtlInitializeCriticalSection (&LoaderLock
);
349 Peb
->LoaderLock
= &LoaderLock
;
351 /* create loader information */
352 Peb
->Ldr
= (PPEB_LDR_DATA
)RtlAllocateHeap (Peb
->ProcessHeap
,
354 sizeof(PEB_LDR_DATA
));
355 if (Peb
->Ldr
== NULL
)
357 DPRINT1("Failed to create loader data\n");
358 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
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
);
367 /* Load compatibility settings */
368 LoadCompatibilitySettings(Peb
);
370 /* Load execution options */
371 LoadImageFileExecutionOptions(Peb
);
373 /* build full ntdll path */
374 wcscpy (FullNtDllPath
, SharedUserData
->NtSystemRoot
);
375 wcscat (FullNtDllPath
, L
"\\system32\\ntdll.dll");
377 /* add entry for ntdll */
378 NtModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
380 sizeof(LDR_DATA_TABLE_ENTRY
));
381 if (NtModule
== NULL
)
383 DPRINT1("Failed to create loader module entry (NTDLL)\n");
384 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
386 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
388 NtModule
->DllBase
= (PVOID
)&_image_base__
;
389 NtModule
->EntryPoint
= 0; /* no entry point */
390 RtlCreateUnicodeString (&NtModule
->FullDllName
,
392 RtlCreateUnicodeString (&NtModule
->BaseDllName
,
394 NtModule
->Flags
= LDRP_IMAGE_DLL
|LDRP_ENTRY_PROCESSED
;
396 NtModule
->LoadCount
= -1; /* don't unload */
397 NtModule
->TlsIndex
= -1;
398 NtModule
->SectionPointer
= NULL
;
399 NtModule
->CheckSum
= 0;
401 NTHeaders
= RtlImageNtHeader (NtModule
->DllBase
);
402 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
403 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
405 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
406 &NtModule
->InLoadOrderModuleList
);
407 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
408 &NtModule
->InInitializationOrderModuleList
);
410 #if defined(DBG) || defined(KDBG)
412 LdrpLoadUserModuleSymbols(NtModule
);
414 #endif /* DBG || KDBG */
416 /* add entry for executable (becomes first list entry) */
417 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
419 sizeof(LDR_DATA_TABLE_ENTRY
));
420 if (ExeModule
== NULL
)
422 DPRINT1("Failed to create loader module infomation\n");
423 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
425 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
427 if ((Peb
->ProcessParameters
== NULL
) ||
428 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
430 DPRINT1("Failed to access the process parameter block\n");
431 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
434 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
435 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
436 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
437 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
439 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
440 &ExeModule
->BaseDllName
,
441 &ExeModule
->FullDllName
);
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;
449 NTHeaders
= RtlImageNtHeader (ExeModule
->DllBase
);
450 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
451 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
453 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
454 &ExeModule
->InLoadOrderModuleList
);
458 #if defined(DBG) || defined(KDBG)
460 LdrpLoadUserModuleSymbols(ExeModule
);
462 #endif /* DBG || KDBG */
464 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
465 ExeModule
->EntryPoint
= EntryPoint
;
467 /* all required dlls are loaded now */
468 Peb
->Ldr
->Initialized
= TRUE
;
470 /* Check before returning that we can run the image safely. */
471 if (EntryPoint
== NULL
)
473 DPRINT1("Failed to initialize image\n");
474 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
477 /* attach the thread */
478 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
480 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);