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 NTAPI
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=0x%lx\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
= NtCurrentPeb();
263 DPRINT("Peb %p\n", Peb
);
264 ImageBase
= Peb
->ImageBaseAddress
;
265 DPRINT("ImageBase %p\n", ImageBase
);
266 if (ImageBase
<= (PVOID
)0x1000)
268 DPRINT("ImageBase is null\n");
269 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
272 /* If MZ header exists */
273 PEDosHeader
= (PIMAGE_DOS_HEADER
) ImageBase
;
274 DPRINT("PEDosHeader %p\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_INVALID_IMAGE_FORMAT
);
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 */
298 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
300 sizeof(SYSTEM_BASIC_INFORMATION
),
303 if (!NT_SUCCESS(Status
))
305 ZwTerminateProcess(NtCurrentProcess(), Status
);
308 Peb
->NumberOfProcessors
= SystemInformation
.NumberOfProcessors
;
310 /* Initialize Critical Section Data */
311 RtlpInitDeferedCriticalSection();
313 /* create process heap */
314 RtlInitializeHeapManager();
315 Peb
->ProcessHeap
= RtlCreateHeap(HEAP_GROWABLE
,
317 NTHeaders
->OptionalHeader
.SizeOfHeapReserve
,
318 NTHeaders
->OptionalHeader
.SizeOfHeapCommit
,
321 if (Peb
->ProcessHeap
== 0)
323 DPRINT1("Failed to create process heap\n");
324 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
327 /* initialized vectored exception handling */
328 RtlpInitializeVectoredExceptionHandling();
330 /* initalize peb lock support */
331 RtlInitializeCriticalSection (&PebLock
);
332 Peb
->FastPebLock
= &PebLock
;
333 Peb
->FastPebLockRoutine
= (PPEBLOCKROUTINE
)RtlEnterCriticalSection
;
334 Peb
->FastPebUnlockRoutine
= (PPEBLOCKROUTINE
)RtlLeaveCriticalSection
;
336 /* initialize tls bitmap */
337 RtlInitializeBitMap (&TlsBitMap
,
339 TLS_MINIMUM_AVAILABLE
);
340 Peb
->TlsBitmap
= &TlsBitMap
;
341 Peb
->TlsExpansionCounter
= TLS_MINIMUM_AVAILABLE
;
343 /* Initialize table of callbacks for the kernel. */
344 Peb
->KernelCallbackTable
=
345 RtlAllocateHeap(RtlGetProcessHeap(),
347 sizeof(PVOID
) * (USER32_CALLBACK_MAXIMUM
+ 1));
348 if (Peb
->KernelCallbackTable
== NULL
)
350 DPRINT1("Failed to create callback table\n");
351 ZwTerminateProcess(NtCurrentProcess(),STATUS_INSUFFICIENT_RESOURCES
);
354 /* initalize loader lock */
355 RtlInitializeCriticalSection (&LoaderLock
);
356 Peb
->LoaderLock
= &LoaderLock
;
358 /* create loader information */
359 Peb
->Ldr
= (PPEB_LDR_DATA
)RtlAllocateHeap (Peb
->ProcessHeap
,
361 sizeof(PEB_LDR_DATA
));
362 if (Peb
->Ldr
== NULL
)
364 DPRINT1("Failed to create loader data\n");
365 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
367 Peb
->Ldr
->Length
= sizeof(PEB_LDR_DATA
);
368 Peb
->Ldr
->Initialized
= FALSE
;
369 Peb
->Ldr
->SsHandle
= NULL
;
370 InitializeListHead(&Peb
->Ldr
->InLoadOrderModuleList
);
371 InitializeListHead(&Peb
->Ldr
->InMemoryOrderModuleList
);
372 InitializeListHead(&Peb
->Ldr
->InInitializationOrderModuleList
);
374 /* Load compatibility settings */
375 LoadCompatibilitySettings(Peb
);
377 /* Load execution options */
378 LoadImageFileExecutionOptions(Peb
);
380 /* Initialize the static teb string */
381 NtCurrentTeb()->StaticUnicodeString
.Length
= 0;
382 NtCurrentTeb()->StaticUnicodeString
.MaximumLength
= sizeof(NtCurrentTeb()->StaticUnicodeBuffer
);
383 NtCurrentTeb()->StaticUnicodeString
.Buffer
= NtCurrentTeb()->StaticUnicodeBuffer
;
385 /* build full ntdll path */
386 wcscpy (FullNtDllPath
, SharedUserData
->NtSystemRoot
);
387 wcscat (FullNtDllPath
, L
"\\system32\\ntdll.dll");
389 /* add entry for ntdll */
390 NtModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
392 sizeof(LDR_DATA_TABLE_ENTRY
));
393 if (NtModule
== NULL
)
395 DPRINT1("Failed to create loader module entry (NTDLL)\n");
396 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
398 memset(NtModule
, 0, sizeof(LDR_DATA_TABLE_ENTRY
));
400 NtModule
->DllBase
= (PVOID
)&_image_base__
;
401 NtModule
->EntryPoint
= 0; /* no entry point */
402 RtlCreateUnicodeString (&NtModule
->FullDllName
,
404 RtlCreateUnicodeString (&NtModule
->BaseDllName
,
406 NtModule
->Flags
= LDRP_IMAGE_DLL
|LDRP_ENTRY_PROCESSED
;
408 NtModule
->LoadCount
= -1; /* don't unload */
409 NtModule
->TlsIndex
= -1;
410 NtModule
->SectionPointer
= NULL
;
411 NtModule
->CheckSum
= 0;
413 NTHeaders
= RtlImageNtHeader (NtModule
->DllBase
);
414 NtModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
415 NtModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
417 InsertTailList(&Peb
->Ldr
->InLoadOrderModuleList
,
418 &NtModule
->InLoadOrderLinks
);
419 InsertTailList(&Peb
->Ldr
->InInitializationOrderModuleList
,
420 &NtModule
->InInitializationOrderModuleList
);
422 #if defined(DBG) || defined(KDBG)
424 LdrpLoadUserModuleSymbols(NtModule
);
426 #endif /* DBG || KDBG */
428 /* add entry for executable (becomes first list entry) */
429 ExeModule
= (PLDR_DATA_TABLE_ENTRY
)RtlAllocateHeap (Peb
->ProcessHeap
,
431 sizeof(LDR_DATA_TABLE_ENTRY
));
432 if (ExeModule
== NULL
)
434 DPRINT1("Failed to create loader module infomation\n");
435 ZwTerminateProcess(NtCurrentProcess(), STATUS_INSUFFICIENT_RESOURCES
);
437 ExeModule
->DllBase
= Peb
->ImageBaseAddress
;
439 if ((Peb
->ProcessParameters
== NULL
) ||
440 (Peb
->ProcessParameters
->ImagePathName
.Length
== 0))
442 DPRINT1("Failed to access the process parameter block\n");
443 ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL
);
446 RtlCreateUnicodeString(&ExeModule
->FullDllName
,
447 Peb
->ProcessParameters
->ImagePathName
.Buffer
);
448 RtlCreateUnicodeString(&ExeModule
->BaseDllName
,
449 wcsrchr(ExeModule
->FullDllName
.Buffer
, L
'\\') + 1);
451 DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
452 &ExeModule
->BaseDllName
,
453 &ExeModule
->FullDllName
);
455 ExeModule
->Flags
= LDRP_ENTRY_PROCESSED
;
456 ExeModule
->LoadCount
= -1; /* don't unload */
457 ExeModule
->TlsIndex
= -1;
458 ExeModule
->SectionPointer
= NULL
;
459 ExeModule
->CheckSum
= 0;
461 NTHeaders
= RtlImageNtHeader (ExeModule
->DllBase
);
462 ExeModule
->SizeOfImage
= LdrpGetResidentSize(NTHeaders
);
463 ExeModule
->TimeDateStamp
= NTHeaders
->FileHeader
.TimeDateStamp
;
465 InsertHeadList(&Peb
->Ldr
->InLoadOrderModuleList
,
466 &ExeModule
->InLoadOrderLinks
);
470 #if defined(DBG) || defined(KDBG)
472 LdrpLoadUserModuleSymbols(ExeModule
);
474 #endif /* DBG || KDBG */
476 EntryPoint
= LdrPEStartup((PVOID
)ImageBase
, NULL
, NULL
, NULL
);
477 ExeModule
->EntryPoint
= EntryPoint
;
479 /* all required dlls are loaded now */
480 Peb
->Ldr
->Initialized
= TRUE
;
482 /* Check before returning that we can run the image safely. */
483 if (EntryPoint
== NULL
)
485 DPRINT1("Failed to initialize image\n");
486 ZwTerminateProcess(NtCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
489 /* attach the thread */
490 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
492 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);