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