xref: /reactos/ntoskrnl/ex/init.c (revision b4af5597)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ex/init.c
5  * PURPOSE:         Executive Initialization Code
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  *                  Eric Kohl
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include <reactos/buildno.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* This is the size that we can expect from the win 2003 loader */
18 #define LOADER_PARAMETER_EXTENSION_MIN_SIZE \
19     RTL_SIZEOF_THROUGH_FIELD(LOADER_PARAMETER_EXTENSION, AcpiTableSize)
20 
21 /* Temporary hack */
22 BOOLEAN
23 NTAPI
24 MmArmInitSystem(
25     IN ULONG Phase,
26     IN PLOADER_PARAMETER_BLOCK LoaderBlock
27 );
28 
29 typedef struct _INIT_BUFFER
30 {
31     WCHAR DebugBuffer[256];
32     CHAR VersionBuffer[256];
33     CHAR BootlogHeader[256];
34     CHAR VersionNumber[24];
35     RTL_USER_PROCESS_INFORMATION ProcessInfo;
36     WCHAR RegistryBuffer[256];
37 } INIT_BUFFER, *PINIT_BUFFER;
38 
39 /* DATA **********************************************************************/
40 
41 /* NT Version Info */
42 ULONG NtMajorVersion = VER_PRODUCTMAJORVERSION;
43 ULONG NtMinorVersion = VER_PRODUCTMINORVERSION;
44 #if DBG /* Checked Build */
45 ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xC0000000;
46 #else   /* Free Build */
47 ULONG NtBuildNumber = VER_PRODUCTBUILD;
48 #endif
49 
50 /* NT System Info */
51 ULONG NtGlobalFlag = 0;
52 ULONG ExSuiteMask;
53 
54 /* Cm Version Info */
55 ULONG CmNtSpBuildNumber;
56 ULONG CmNtCSDVersion;
57 ULONG CmNtCSDReleaseType;
58 UNICODE_STRING CmVersionString;
59 UNICODE_STRING CmCSDVersionString;
60 
61 CHAR NtBuildLab[] = KERNEL_VERSION_BUILD_STR "."
62                     REACTOS_COMPILER_NAME "_" REACTOS_COMPILER_VERSION;
63 
64 /* Init flags and settings */
65 ULONG ExpInitializationPhase;
66 BOOLEAN ExpInTextModeSetup;
67 BOOLEAN IoRemoteBootClient;
68 ULONG InitSafeBootMode;
69 BOOLEAN InitIsWinPEMode, InitWinPEModeType;
70 
71 /* NT Boot Path */
72 UNICODE_STRING NtSystemRoot;
73 
74 /* NT Initial User Application */
75 WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
76 ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) -
77                                          sizeof(WCHAR);
78 ULONG NtInitialUserProcessBufferType = REG_SZ;
79 
80 /* Boot NLS information */
81 PVOID ExpNlsTableBase;
82 ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
83 ULONG ExpUnicodeCaseTableDataOffset;
84 NLSTABLEINFO ExpNlsTableInfo;
85 SIZE_T ExpNlsTableSize;
86 PVOID ExpNlsSectionPointer;
87 
88 /* CMOS Timer Sanity */
89 BOOLEAN ExCmosClockIsSane = TRUE;
90 BOOLEAN ExpRealTimeIsUniversal;
91 
92 /* FUNCTIONS ****************************************************************/
93 
94 INIT_FUNCTION
95 NTSTATUS
96 NTAPI
97 ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
98 {
99     UNICODE_STRING LinkName;
100     OBJECT_ATTRIBUTES ObjectAttributes;
101     HANDLE LinkHandle;
102     NTSTATUS Status;
103     ANSI_STRING AnsiName;
104     CHAR Buffer[256];
105     ANSI_STRING TargetString;
106     UNICODE_STRING TargetName;
107 
108     /* Initialize the ArcName tree */
109     RtlInitUnicodeString(&LinkName, L"\\ArcName");
110     InitializeObjectAttributes(&ObjectAttributes,
111                                &LinkName,
112                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
113                                NULL,
114                                SePublicDefaultUnrestrictedSd);
115 
116     /* Create it */
117     Status = NtCreateDirectoryObject(&LinkHandle,
118                                      DIRECTORY_ALL_ACCESS,
119                                      &ObjectAttributes);
120     if (!NT_SUCCESS(Status))
121     {
122         /* Failed */
123         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 1, 0, 0);
124     }
125 
126     /* Close the LinkHandle */
127     NtClose(LinkHandle);
128 
129     /* Initialize the Device tree */
130     RtlInitUnicodeString(&LinkName, L"\\Device");
131     InitializeObjectAttributes(&ObjectAttributes,
132                                &LinkName,
133                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
134                                NULL,
135                                SePublicDefaultUnrestrictedSd);
136 
137     /* Create it */
138     Status = NtCreateDirectoryObject(&LinkHandle,
139                                      DIRECTORY_ALL_ACCESS,
140                                      &ObjectAttributes);
141     if (!NT_SUCCESS(Status))
142     {
143         /* Failed */
144         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 2, 0, 0);
145     }
146 
147     /* Close the LinkHandle */
148     ObCloseHandle(LinkHandle, KernelMode);
149 
150     /* Create the system root symlink name */
151     RtlInitAnsiString(&AnsiName, "\\SystemRoot");
152     Status = RtlAnsiStringToUnicodeString(&LinkName, &AnsiName, TRUE);
153     if (!NT_SUCCESS(Status))
154     {
155         /* Failed */
156         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 3, 0, 0);
157     }
158 
159     /* Initialize the attributes for the link */
160     InitializeObjectAttributes(&ObjectAttributes,
161                                &LinkName,
162                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
163                                NULL,
164                                SePublicDefaultUnrestrictedSd);
165 
166     /* Build the ARC name */
167     sprintf(Buffer,
168             "\\ArcName\\%s%s",
169             LoaderBlock->ArcBootDeviceName,
170             LoaderBlock->NtBootPathName);
171     Buffer[strlen(Buffer) - 1] = ANSI_NULL;
172 
173     /* Convert it to Unicode */
174     RtlInitString(&TargetString, Buffer);
175     Status = RtlAnsiStringToUnicodeString(&TargetName,
176                                           &TargetString,
177                                           TRUE);
178     if (!NT_SUCCESS(Status))
179     {
180         /* We failed, bugcheck */
181         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 4, 0, 0);
182     }
183 
184     /* Create it */
185     Status = NtCreateSymbolicLinkObject(&LinkHandle,
186                                         SYMBOLIC_LINK_ALL_ACCESS,
187                                         &ObjectAttributes,
188                                         &TargetName);
189 
190     /* Free the strings */
191     RtlFreeUnicodeString(&LinkName);
192     RtlFreeUnicodeString(&TargetName);
193 
194     /* Check if creating the link failed */
195     if (!NT_SUCCESS(Status))
196     {
197         /* Failed */
198         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 5, 0, 0);
199     }
200 
201     /* Close the handle and return success */
202     ObCloseHandle(LinkHandle, KernelMode);
203     return STATUS_SUCCESS;
204 }
205 
206 INIT_FUNCTION
207 VOID
208 NTAPI
209 ExpInitNls(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
210 {
211     LARGE_INTEGER SectionSize;
212     NTSTATUS Status;
213     HANDLE NlsSection;
214     PVOID SectionBase = NULL;
215     SIZE_T ViewSize = 0;
216     LARGE_INTEGER SectionOffset = {{0, 0}};
217     PLIST_ENTRY ListHead, NextEntry;
218     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
219     ULONG NlsTablesEncountered = 0;
220     SIZE_T NlsTableSizes[3] = {0, 0, 0}; /* 3 NLS tables */
221 
222     /* Check if this is boot-time phase 0 initialization */
223     if (!ExpInitializationPhase)
224     {
225         /* Loop the memory descriptors */
226         ListHead = &LoaderBlock->MemoryDescriptorListHead;
227         NextEntry = ListHead->Flink;
228         while (NextEntry != ListHead)
229         {
230             /* Get the current block */
231             MdBlock = CONTAINING_RECORD(NextEntry,
232                                         MEMORY_ALLOCATION_DESCRIPTOR,
233                                         ListEntry);
234 
235             /* Check if this is an NLS block */
236             if (MdBlock->MemoryType == LoaderNlsData)
237             {
238                 /* Increase the table size */
239                 ExpNlsTableSize += MdBlock->PageCount * PAGE_SIZE;
240 
241                 /* FreeLdr-specific */
242                 NlsTableSizes[NlsTablesEncountered] = MdBlock->PageCount * PAGE_SIZE;
243                 NlsTablesEncountered++;
244                 ASSERT(NlsTablesEncountered < 4);
245             }
246 
247             /* Go to the next block */
248             NextEntry = MdBlock->ListEntry.Flink;
249         }
250 
251         /* Allocate the a new buffer since loader memory will be freed */
252         ExpNlsTableBase = ExAllocatePoolWithTag(NonPagedPool,
253                                                 ExpNlsTableSize,
254                                                 TAG_RTLI);
255         if (!ExpNlsTableBase) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
256 
257         /* Copy the codepage data in its new location. */
258         if (NlsTablesEncountered == 1)
259         {
260             /* Ntldr-way boot process */
261             RtlCopyMemory(ExpNlsTableBase,
262                           LoaderBlock->NlsData->AnsiCodePageData,
263                           ExpNlsTableSize);
264         }
265         else
266         {
267             /*
268             * In NT, the memory blocks are contiguous, but in ReactOS they aren't,
269             * so unless someone fixes FreeLdr, we'll have to use this icky hack.
270             */
271             RtlCopyMemory(ExpNlsTableBase,
272                           LoaderBlock->NlsData->AnsiCodePageData,
273                           NlsTableSizes[0]);
274 
275             RtlCopyMemory((PVOID)((ULONG_PTR)ExpNlsTableBase + NlsTableSizes[0]),
276                           LoaderBlock->NlsData->OemCodePageData,
277                           NlsTableSizes[1]);
278 
279             RtlCopyMemory((PVOID)((ULONG_PTR)ExpNlsTableBase + NlsTableSizes[0] +
280                           NlsTableSizes[1]),
281                           LoaderBlock->NlsData->UnicodeCodePageData,
282                           NlsTableSizes[2]);
283             /* End of Hack */
284         }
285 
286         /* Initialize and reset the NLS TAbles */
287         RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
288                                  ExpAnsiCodePageDataOffset),
289                          (PVOID)((ULONG_PTR)ExpNlsTableBase +
290                                  ExpOemCodePageDataOffset),
291                          (PVOID)((ULONG_PTR)ExpNlsTableBase +
292                                  ExpUnicodeCaseTableDataOffset),
293                          &ExpNlsTableInfo);
294         RtlResetRtlTranslations(&ExpNlsTableInfo);
295         return;
296     }
297 
298     /* Set the section size */
299     SectionSize.QuadPart = ExpNlsTableSize;
300 
301     /* Create the NLS Section */
302     Status = ZwCreateSection(&NlsSection,
303                              SECTION_ALL_ACCESS,
304                              NULL,
305                              &SectionSize,
306                              PAGE_READWRITE,
307                              SEC_COMMIT | 0x1,
308                              NULL);
309     if (!NT_SUCCESS(Status))
310     {
311         /* Failed */
312         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 1, 0, 0);
313     }
314 
315     /* Get a pointer to the section */
316     Status = ObReferenceObjectByHandle(NlsSection,
317                                        SECTION_ALL_ACCESS,
318                                        MmSectionObjectType,
319                                        KernelMode,
320                                        &ExpNlsSectionPointer,
321                                        NULL);
322     ObCloseHandle(NlsSection, KernelMode);
323     if (!NT_SUCCESS(Status))
324     {
325         /* Failed */
326         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 2, 0, 0);
327     }
328 
329     /* Map the NLS Section in system space */
330     Status = MmMapViewInSystemSpace(ExpNlsSectionPointer,
331                                     &SectionBase,
332                                     &ExpNlsTableSize);
333     if (!NT_SUCCESS(Status))
334     {
335         /* Failed */
336         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 3, 0, 0);
337     }
338 
339     /* Copy the codepage data in its new location. */
340     ASSERT(SectionBase >= MmSystemRangeStart);
341     RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
342 
343     /* Free the previously allocated buffer and set the new location */
344     ExFreePoolWithTag(ExpNlsTableBase, TAG_RTLI);
345     ExpNlsTableBase = SectionBase;
346 
347     /* Initialize the NLS Tables */
348     RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
349                              ExpAnsiCodePageDataOffset),
350                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
351                              ExpOemCodePageDataOffset),
352                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
353                              ExpUnicodeCaseTableDataOffset),
354                      &ExpNlsTableInfo);
355     RtlResetRtlTranslations(&ExpNlsTableInfo);
356 
357     /* Reset the base to 0 */
358     SectionBase = NULL;
359 
360     /* Map the section in the system process */
361     Status = MmMapViewOfSection(ExpNlsSectionPointer,
362                                 PsGetCurrentProcess(),
363                                 &SectionBase,
364                                 0L,
365                                 0L,
366                                 &SectionOffset,
367                                 &ViewSize,
368                                 ViewShare,
369                                 0L,
370                                 PAGE_READWRITE);
371     if (!NT_SUCCESS(Status))
372     {
373         /* Failed */
374         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 5, 0, 0);
375     }
376 
377     /* Copy the table into the system process and set this as the base */
378     RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
379     ExpNlsTableBase = SectionBase;
380 }
381 
382 INIT_FUNCTION
383 VOID
384 NTAPI
385 ExpLoadInitialProcess(IN PINIT_BUFFER InitBuffer,
386                       OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
387                       OUT PCHAR *ProcessEnvironment)
388 {
389     NTSTATUS Status;
390     SIZE_T Size;
391     PWSTR p;
392     UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
393     UNICODE_STRING SmssName, Environment, SystemDriveString, DebugString;
394     PVOID EnvironmentPtr = NULL;
395     PRTL_USER_PROCESS_INFORMATION ProcessInformation;
396     PRTL_USER_PROCESS_PARAMETERS ProcessParams = NULL;
397 
398     NullString.Length = sizeof(WCHAR);
399 
400     /* Use the initial buffer, after the strings */
401     ProcessInformation = &InitBuffer->ProcessInfo;
402 
403     /* Allocate memory for the process parameters */
404     Size = sizeof(*ProcessParams) + ((MAX_PATH * 6) * sizeof(WCHAR));
405     Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
406                                      (PVOID*)&ProcessParams,
407                                      0,
408                                      &Size,
409                                      MEM_RESERVE | MEM_COMMIT,
410                                      PAGE_READWRITE);
411     if (!NT_SUCCESS(Status))
412     {
413         /* Failed, display error */
414         _snwprintf(InitBuffer->DebugBuffer,
415                    sizeof(InitBuffer->DebugBuffer)/sizeof(WCHAR),
416                    L"INIT: Unable to allocate Process Parameters. 0x%lx",
417                    Status);
418         RtlInitUnicodeString(&DebugString, InitBuffer->DebugBuffer);
419         ZwDisplayString(&DebugString);
420 
421         /* Bugcheck the system */
422         KeBugCheckEx(SESSION1_INITIALIZATION_FAILED, Status, 0, 0, 0);
423     }
424 
425     /* Setup the basic header, and give the process the low 1MB to itself */
426     ProcessParams->Length = (ULONG)Size;
427     ProcessParams->MaximumLength = (ULONG)Size;
428     ProcessParams->Flags = RTL_USER_PROCESS_PARAMETERS_NORMALIZED |
429                            RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
430 
431     /* Allocate a page for the environment */
432     Size = PAGE_SIZE;
433     Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
434                                      &EnvironmentPtr,
435                                      0,
436                                      &Size,
437                                      MEM_RESERVE | MEM_COMMIT,
438                                      PAGE_READWRITE);
439     if (!NT_SUCCESS(Status))
440     {
441         /* Failed, display error */
442         _snwprintf(InitBuffer->DebugBuffer,
443                    sizeof(InitBuffer->DebugBuffer)/sizeof(WCHAR),
444                    L"INIT: Unable to allocate Process Environment. 0x%lx",
445                    Status);
446         RtlInitUnicodeString(&DebugString, InitBuffer->DebugBuffer);
447         ZwDisplayString(&DebugString);
448 
449         /* Bugcheck the system */
450         KeBugCheckEx(SESSION2_INITIALIZATION_FAILED, Status, 0, 0, 0);
451     }
452 
453     /* Write the pointer */
454     ProcessParams->Environment = EnvironmentPtr;
455 
456     /* Make a buffer for the DOS path */
457     p = (PWSTR)(ProcessParams + 1);
458     ProcessParams->CurrentDirectory.DosPath.Buffer = p;
459     ProcessParams->CurrentDirectory.DosPath.MaximumLength = MAX_PATH *
460                                                             sizeof(WCHAR);
461 
462     /* Copy the DOS path */
463     RtlCopyUnicodeString(&ProcessParams->CurrentDirectory.DosPath,
464                          &NtSystemRoot);
465 
466     /* Make a buffer for the DLL Path */
467     p = (PWSTR)((PCHAR)ProcessParams->CurrentDirectory.DosPath.Buffer +
468                 ProcessParams->CurrentDirectory.DosPath.MaximumLength);
469     ProcessParams->DllPath.Buffer = p;
470     ProcessParams->DllPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
471 
472     /* Copy the DLL path and append the system32 directory */
473     RtlCopyUnicodeString(&ProcessParams->DllPath,
474                          &ProcessParams->CurrentDirectory.DosPath);
475     RtlAppendUnicodeToString(&ProcessParams->DllPath, L"\\System32");
476 
477     /* Make a buffer for the image name */
478     p = (PWSTR)((PCHAR)ProcessParams->DllPath.Buffer +
479                 ProcessParams->DllPath.MaximumLength);
480     ProcessParams->ImagePathName.Buffer = p;
481     ProcessParams->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR);
482 
483     /* Make sure the buffer is a valid string which within the given length */
484     if ((NtInitialUserProcessBufferType != REG_SZ) ||
485         ((NtInitialUserProcessBufferLength != MAXULONG) &&
486          ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) ||
487           (NtInitialUserProcessBufferLength >
488            sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))))
489     {
490         /* Invalid initial process string, bugcheck */
491         KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,
492                      STATUS_INVALID_PARAMETER,
493                      NtInitialUserProcessBufferType,
494                      NtInitialUserProcessBufferLength,
495                      sizeof(NtInitialUserProcessBuffer));
496     }
497 
498     /* Cut out anything after a space */
499     p = NtInitialUserProcessBuffer;
500     while ((*p) && (*p != L' ')) p++;
501 
502     /* Set the image path length */
503     ProcessParams->ImagePathName.Length =
504         (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer);
505 
506     /* Copy the actual buffer */
507     RtlCopyMemory(ProcessParams->ImagePathName.Buffer,
508                   NtInitialUserProcessBuffer,
509                   ProcessParams->ImagePathName.Length);
510 
511     /* Null-terminate it */
512     ProcessParams->ImagePathName.Buffer[ProcessParams->ImagePathName.Length /
513                                         sizeof(WCHAR)] = UNICODE_NULL;
514 
515     /* Make a buffer for the command line */
516     p = (PWSTR)((PCHAR)ProcessParams->ImagePathName.Buffer +
517                 ProcessParams->ImagePathName.MaximumLength);
518     ProcessParams->CommandLine.Buffer = p;
519     ProcessParams->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR);
520 
521     /* Add the image name to the command line */
522     RtlAppendUnicodeToString(&ProcessParams->CommandLine,
523                              NtInitialUserProcessBuffer);
524 
525     /* Create the environment string */
526     RtlInitEmptyUnicodeString(&Environment,
527                               ProcessParams->Environment,
528                               (USHORT)Size);
529 
530     /* Append the DLL path to it */
531     RtlAppendUnicodeToString(&Environment, L"Path=");
532     RtlAppendUnicodeStringToString(&Environment, &ProcessParams->DllPath);
533     RtlAppendUnicodeStringToString(&Environment, &NullString);
534 
535     /* Create the system drive string */
536     SystemDriveString = NtSystemRoot;
537     SystemDriveString.Length = 2 * sizeof(WCHAR);
538 
539     /* Append it to the environment */
540     RtlAppendUnicodeToString(&Environment, L"SystemDrive=");
541     RtlAppendUnicodeStringToString(&Environment, &SystemDriveString);
542     RtlAppendUnicodeStringToString(&Environment, &NullString);
543 
544     /* Append the system root to the environment */
545     RtlAppendUnicodeToString(&Environment, L"SystemRoot=");
546     RtlAppendUnicodeStringToString(&Environment, &NtSystemRoot);
547     RtlAppendUnicodeStringToString(&Environment, &NullString);
548 
549     /* Prepare the prefetcher */
550     //CcPfBeginBootPhase(150);
551 
552     /* Create SMSS process */
553     SmssName = ProcessParams->ImagePathName;
554     Status = RtlCreateUserProcess(&SmssName,
555                                   OBJ_CASE_INSENSITIVE,
556                                   RtlDeNormalizeProcessParams(ProcessParams),
557                                   NULL,
558                                   NULL,
559                                   NULL,
560                                   FALSE,
561                                   NULL,
562                                   NULL,
563                                   ProcessInformation);
564     if (!NT_SUCCESS(Status))
565     {
566         /* Failed, display error */
567         _snwprintf(InitBuffer->DebugBuffer,
568                    sizeof(InitBuffer->DebugBuffer)/sizeof(WCHAR),
569                    L"INIT: Unable to create Session Manager. 0x%lx",
570                    Status);
571         RtlInitUnicodeString(&DebugString, InitBuffer->DebugBuffer);
572         ZwDisplayString(&DebugString);
573 
574         /* Bugcheck the system */
575         KeBugCheckEx(SESSION3_INITIALIZATION_FAILED, Status, 0, 0, 0);
576     }
577 
578     /* Resume the thread */
579     Status = ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
580     if (!NT_SUCCESS(Status))
581     {
582         /* Failed, display error */
583         _snwprintf(InitBuffer->DebugBuffer,
584                    sizeof(InitBuffer->DebugBuffer)/sizeof(WCHAR),
585                    L"INIT: Unable to resume Session Manager. 0x%lx",
586                    Status);
587         RtlInitUnicodeString(&DebugString, InitBuffer->DebugBuffer);
588         ZwDisplayString(&DebugString);
589 
590         /* Bugcheck the system */
591         KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
592     }
593 
594     /* Return success */
595     *ProcessParameters = ProcessParams;
596     *ProcessEnvironment = EnvironmentPtr;
597 }
598 
599 INIT_FUNCTION
600 ULONG
601 NTAPI
602 ExComputeTickCountMultiplier(IN ULONG ClockIncrement)
603 {
604     ULONG MsRemainder = 0, MsIncrement;
605     ULONG IncrementRemainder;
606     ULONG i;
607 
608     /* Count the number of milliseconds for each clock interrupt */
609     MsIncrement = ClockIncrement / (10 * 1000);
610 
611     /* Count the remainder from the division above, with 24-bit precision */
612     IncrementRemainder = ClockIncrement - (MsIncrement * (10 * 1000));
613     for (i= 0; i < 24; i++)
614     {
615         /* Shift the remainders */
616         MsRemainder <<= 1;
617         IncrementRemainder <<= 1;
618 
619         /* Check if we've went past 1 ms */
620         if (IncrementRemainder >= (10 * 1000))
621         {
622             /* Increase the remainder by one, and substract from increment */
623             IncrementRemainder -= (10 * 1000);
624             MsRemainder |= 1;
625         }
626     }
627 
628     /* Return the increment */
629     return (MsIncrement << 24) | MsRemainder;
630 }
631 
632 INIT_FUNCTION
633 BOOLEAN
634 NTAPI
635 ExpInitSystemPhase0(VOID)
636 {
637     /* Initialize EXRESOURCE Support */
638     ExpResourceInitialization();
639 
640     /* Initialize the environment lock */
641     ExInitializeFastMutex(&ExpEnvironmentLock);
642 
643     /* Initialize the lookaside lists and locks */
644     ExpInitLookasideLists();
645 
646     /* Initialize the Firmware Table resource and listhead */
647     InitializeListHead(&ExpFirmwareTableProviderListHead);
648     ExInitializeResourceLite(&ExpFirmwareTableResource);
649 
650     /* Set the suite mask to maximum and return */
651     ExSuiteMask = 0xFFFFFFFF;
652     return TRUE;
653 }
654 
655 INIT_FUNCTION
656 BOOLEAN
657 NTAPI
658 ExpInitSystemPhase1(VOID)
659 {
660     /* Initialize worker threads */
661     ExpInitializeWorkerThreads();
662 
663     /* Initialize pushlocks */
664     ExpInitializePushLocks();
665 
666     /* Initialize events and event pairs */
667     if (ExpInitializeEventImplementation() == FALSE)
668     {
669         DPRINT1("Executive: Event initialization failed\n");
670         return FALSE;
671     }
672     if (ExpInitializeEventPairImplementation() == FALSE)
673     {
674         DPRINT1("Executive: Event Pair initialization failed\n");
675         return FALSE;
676     }
677 
678     /* Initialize mutants */
679     if (ExpInitializeMutantImplementation() == FALSE)
680     {
681         DPRINT1("Executive: Mutant initialization failed\n");
682         return FALSE;
683     }
684 
685     /* Initialize callbacks */
686     if (ExpInitializeCallbacks() == FALSE)
687     {
688         DPRINT1("Executive: Callback initialization failed\n");
689         return FALSE;
690     }
691 
692     /* Initialize semaphores */
693     if (ExpInitializeSemaphoreImplementation() == FALSE)
694     {
695         DPRINT1("Executive: Semaphore initialization failed\n");
696         return FALSE;
697     }
698 
699     /* Initialize timers */
700     if (ExpInitializeTimerImplementation() == FALSE)
701     {
702         DPRINT1("Executive: Timer initialization failed\n");
703         return FALSE;
704     }
705 
706     /* Initialize profiling */
707     if (ExpInitializeProfileImplementation() == FALSE)
708     {
709         DPRINT1("Executive: Profile initialization failed\n");
710         return FALSE;
711     }
712 
713     /* Initialize UUIDs */
714     if (ExpUuidInitialization() == FALSE)
715     {
716         DPRINT1("Executive: Uuid initialization failed\n");
717         return FALSE;
718     }
719 
720     /* Initialize keyed events */
721     if (ExpInitializeKeyedEventImplementation() == FALSE)
722     {
723         DPRINT1("Executive: Keyed event initialization failed\n");
724         return FALSE;
725     }
726 
727     /* Initialize Win32K */
728     if (ExpWin32kInit() == FALSE)
729     {
730         DPRINT1("Executive: Win32 initialization failed\n");
731         return FALSE;
732     }
733     return TRUE;
734 }
735 
736 INIT_FUNCTION
737 BOOLEAN
738 NTAPI
739 ExInitSystem(VOID)
740 {
741     /* Check the initialization phase */
742     switch (ExpInitializationPhase)
743     {
744         case 0:
745 
746             /* Do Phase 0 */
747             return ExpInitSystemPhase0();
748 
749         case 1:
750 
751             /* Do Phase 1 */
752             return ExpInitSystemPhase1();
753 
754         default:
755 
756             /* Don't know any other phase! Bugcheck! */
757             KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
758             return FALSE;
759     }
760 }
761 
762 INIT_FUNCTION
763 BOOLEAN
764 NTAPI
765 ExpIsLoaderValid(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
766 {
767     PLOADER_PARAMETER_EXTENSION Extension;
768 
769     /* Get the loader extension */
770     Extension = LoaderBlock->Extension;
771 
772     /* Validate the size (Windows 2003 loader doesn't provide more) */
773     if (Extension->Size < LOADER_PARAMETER_EXTENSION_MIN_SIZE) return FALSE;
774 
775     /* Don't validate upper versions */
776     if (Extension->MajorVersion > VER_PRODUCTMAJORVERSION) return TRUE;
777 
778     /* Fail if this is NT 4 */
779     if (Extension->MajorVersion < VER_PRODUCTMAJORVERSION) return FALSE;
780 
781     /* Fail if this is XP */
782     if (Extension->MinorVersion < VER_PRODUCTMINORVERSION) return FALSE;
783 
784     /* This is 2003 or newer, approve it */
785     return TRUE;
786 }
787 
788 INIT_FUNCTION
789 VOID
790 NTAPI
791 ExpLoadBootSymbols(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
792 {
793     ULONG i = 0;
794     PLIST_ENTRY NextEntry;
795     ULONG Count, Length;
796     PWCHAR Name;
797     PLDR_DATA_TABLE_ENTRY LdrEntry;
798     CHAR NameBuffer[256];
799     STRING SymbolString;
800     NTSTATUS Status;
801 
802     /* Loop the driver list */
803     NextEntry = LoaderBlock->LoadOrderListHead.Flink;
804     while (NextEntry != &LoaderBlock->LoadOrderListHead)
805     {
806         /* Skip the first two images */
807         if (i >= 2)
808         {
809             /* Get the entry */
810             LdrEntry = CONTAINING_RECORD(NextEntry,
811                                          LDR_DATA_TABLE_ENTRY,
812                                          InLoadOrderLinks);
813             if (LdrEntry->FullDllName.Buffer[0] == L'\\')
814             {
815                 /* We have a name, read its data */
816                 Name = LdrEntry->FullDllName.Buffer;
817                 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
818 
819                 /* Check if our buffer can hold it */
820                 if (sizeof(NameBuffer) < Length + sizeof(ANSI_NULL))
821                 {
822                     /* It's too long */
823                     Status = STATUS_BUFFER_OVERFLOW;
824                 }
825                 else
826                 {
827                     /* Copy the name */
828                     Count = 0;
829                     do
830                     {
831                         /* Copy the character */
832                         NameBuffer[Count++] = (CHAR)*Name++;
833                     } while (Count < Length);
834 
835                     /* Null-terminate */
836                     NameBuffer[Count] = ANSI_NULL;
837                     Status = STATUS_SUCCESS;
838                 }
839             }
840             else
841             {
842                 /* Safely print the string into our buffer */
843                 Status = RtlStringCbPrintfA(NameBuffer,
844                                             sizeof(NameBuffer),
845                                             "%S\\System32\\Drivers\\%wZ",
846                                             &SharedUserData->NtSystemRoot[2],
847                                             &LdrEntry->BaseDllName);
848             }
849 
850             /* Check if the buffer was ok */
851             if (NT_SUCCESS(Status))
852             {
853                 /* Initialize the STRING for the debugger */
854                 RtlInitString(&SymbolString, NameBuffer);
855 
856                 /* Load the symbols */
857                 DbgLoadImageSymbols(&SymbolString,
858                                     LdrEntry->DllBase,
859                                     (ULONG_PTR)PsGetCurrentProcessId());
860             }
861         }
862 
863         /* Go to the next entry */
864         i++;
865         NextEntry = NextEntry->Flink;
866     }
867 }
868 
869 INIT_FUNCTION
870 VOID
871 NTAPI
872 ExBurnMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
873              IN ULONG_PTR PagesToDestroy,
874              IN TYPE_OF_MEMORY MemoryType)
875 {
876     PLIST_ENTRY ListEntry;
877     PMEMORY_ALLOCATION_DESCRIPTOR MemDescriptor;
878 
879     DPRINT1("Burn RAM amount: %lu pages\n", PagesToDestroy);
880 
881     /* Loop the memory descriptors, beginning at the end */
882     for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Blink;
883          ListEntry != &LoaderBlock->MemoryDescriptorListHead;
884          ListEntry = ListEntry->Blink)
885     {
886         /* Get the memory descriptor structure */
887         MemDescriptor = CONTAINING_RECORD(ListEntry,
888                                           MEMORY_ALLOCATION_DESCRIPTOR,
889                                           ListEntry);
890 
891         /* Is memory free there or is it temporary? */
892         if (MemDescriptor->MemoryType == LoaderFree ||
893             MemDescriptor->MemoryType == LoaderFirmwareTemporary)
894         {
895             /* Check if the descriptor has more pages than we want */
896             if (MemDescriptor->PageCount > PagesToDestroy)
897             {
898                 /* Change block's page count, ntoskrnl doesn't care much */
899                 MemDescriptor->PageCount -= PagesToDestroy;
900                 break;
901             }
902             else
903             {
904                 /* Change block type */
905                 MemDescriptor->MemoryType = MemoryType;
906                 PagesToDestroy -= MemDescriptor->PageCount;
907 
908                 /* Check if we are done */
909                 if (PagesToDestroy == 0) break;
910             }
911         }
912     }
913 }
914 
915 INIT_FUNCTION
916 VOID
917 NTAPI
918 ExpInitializeExecutive(IN ULONG Cpu,
919                        IN PLOADER_PARAMETER_BLOCK LoaderBlock)
920 {
921     PNLS_DATA_BLOCK NlsData;
922     CHAR Buffer[256];
923     ANSI_STRING AnsiPath;
924     NTSTATUS Status;
925     PCHAR CommandLine, PerfMem;
926     ULONG PerfMemUsed;
927     PLDR_DATA_TABLE_ENTRY NtosEntry;
928     PMESSAGE_RESOURCE_ENTRY MsgEntry;
929     ANSI_STRING CSDString;
930     size_t Remaining = 0;
931     PCHAR RcEnd = NULL;
932     CHAR VersionBuffer[65];
933 
934     /* Validate Loader */
935     if (!ExpIsLoaderValid(LoaderBlock))
936     {
937         /* Invalid loader version */
938         KeBugCheckEx(MISMATCHED_HAL,
939                      3,
940                      LoaderBlock->Extension->Size,
941                      LoaderBlock->Extension->MajorVersion,
942                      LoaderBlock->Extension->MinorVersion);
943     }
944 
945     /* Initialize PRCB pool lookaside pointers */
946     ExInitPoolLookasidePointers();
947 
948     /* Check if this is an application CPU */
949     if (Cpu)
950     {
951         /* Then simply initialize it with HAL */
952         if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
953         {
954             /* Initialization failed */
955             KeBugCheck(HAL_INITIALIZATION_FAILED);
956         }
957 
958         /* We're done */
959         return;
960     }
961 
962     /* Assume no text-mode or remote boot */
963     ExpInTextModeSetup = FALSE;
964     IoRemoteBootClient = FALSE;
965 
966     /* Check if we have a setup loader block */
967     if (LoaderBlock->SetupLdrBlock)
968     {
969         /* Check if this is text-mode setup */
970         if (LoaderBlock->SetupLdrBlock->Flags & SETUPLDR_TEXT_MODE)
971             ExpInTextModeSetup = TRUE;
972 
973         /* Check if this is network boot */
974         if (LoaderBlock->SetupLdrBlock->Flags & SETUPLDR_REMOTE_BOOT)
975         {
976             /* Set variable */
977             IoRemoteBootClient = TRUE;
978 
979             /* Make sure we're actually booting off the network */
980             ASSERT(!_memicmp(LoaderBlock->ArcBootDeviceName, "net(0)", 6));
981         }
982     }
983 
984     /* Set phase to 0 */
985     ExpInitializationPhase = 0;
986 
987     /* Get boot command line */
988     CommandLine = LoaderBlock->LoadOptions;
989     if (CommandLine)
990     {
991         /* Upcase it for comparison and check if we're in performance mode */
992         _strupr(CommandLine);
993         PerfMem = strstr(CommandLine, "PERFMEM");
994         if (PerfMem)
995         {
996             /* Check if the user gave a number of bytes to use */
997             PerfMem = strstr(PerfMem, "=");
998             if (PerfMem)
999             {
1000                 /* Read the number of pages we'll use */
1001                 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
1002                 if (PerfMem)
1003                 {
1004                     /* FIXME: TODO */
1005                     DPRINT1("BBT performance mode not yet supported."
1006                             "/PERFMEM option ignored.\n");
1007                 }
1008             }
1009         }
1010 
1011         /* Check if we're burning memory */
1012         PerfMem = strstr(CommandLine, "BURNMEMORY");
1013         if (PerfMem)
1014         {
1015             /* Check if the user gave a number of bytes to use */
1016             PerfMem = strstr(PerfMem, "=");
1017             if (PerfMem)
1018             {
1019                 /* Read the number of pages we'll use */
1020                 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
1021                 if (PerfMemUsed) ExBurnMemory(LoaderBlock, PerfMemUsed, LoaderBad);
1022             }
1023         }
1024     }
1025 
1026     /* Setup NLS Base and offsets */
1027     NlsData = LoaderBlock->NlsData;
1028     ExpNlsTableBase = NlsData->AnsiCodePageData;
1029     ExpAnsiCodePageDataOffset = 0;
1030     ExpOemCodePageDataOffset = (ULONG)((ULONG_PTR)NlsData->OemCodePageData -
1031                                        (ULONG_PTR)NlsData->AnsiCodePageData);
1032     ExpUnicodeCaseTableDataOffset = (ULONG)((ULONG_PTR)NlsData->UnicodeCodePageData -
1033                                             (ULONG_PTR)NlsData->AnsiCodePageData);
1034 
1035     /* Initialize the NLS Tables */
1036     RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
1037                              ExpAnsiCodePageDataOffset),
1038                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
1039                              ExpOemCodePageDataOffset),
1040                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
1041                              ExpUnicodeCaseTableDataOffset),
1042                      &ExpNlsTableInfo);
1043     RtlResetRtlTranslations(&ExpNlsTableInfo);
1044 
1045     /* Now initialize the HAL */
1046     if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
1047     {
1048         /* HAL failed to initialize, bugcheck */
1049         KeBugCheck(HAL_INITIALIZATION_FAILED);
1050     }
1051 
1052     /* Make sure interrupts are active now */
1053     _enable();
1054 
1055     /* Clear the crypto exponent */
1056     SharedUserData->CryptoExponent = 0;
1057 
1058     /* Set global flags for the checked build */
1059 #if DBG
1060     NtGlobalFlag |= FLG_ENABLE_CLOSE_EXCEPTIONS |
1061                     FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
1062 #endif
1063 
1064     /* Setup NT System Root Path */
1065     sprintf(Buffer, "C:%s", LoaderBlock->NtBootPathName);
1066 
1067     /* Convert to ANSI_STRING and null-terminate it */
1068     RtlInitString(&AnsiPath, Buffer);
1069     Buffer[--AnsiPath.Length] = ANSI_NULL;
1070 
1071     /* Get the string from KUSER_SHARED_DATA's buffer */
1072     RtlInitEmptyUnicodeString(&NtSystemRoot,
1073                               SharedUserData->NtSystemRoot,
1074                               sizeof(SharedUserData->NtSystemRoot));
1075 
1076     /* Now fill it in */
1077     Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE);
1078     if (!NT_SUCCESS(Status)) KeBugCheck(SESSION3_INITIALIZATION_FAILED);
1079 
1080     /* Setup bugcheck messages */
1081     KiInitializeBugCheck();
1082 
1083     /* Setup initial system settings */
1084     CmGetSystemControlValues(LoaderBlock->RegistryBase, CmControlVector);
1085 
1086     /* Set the Service Pack Number and add it to the CSD Version number if needed */
1087     CmNtSpBuildNumber = VER_PRODUCTBUILD_QFE;
1088     if (((CmNtCSDVersion & 0xFFFF0000) == 0) && (CmNtCSDReleaseType == 1))
1089     {
1090         CmNtCSDVersion |= (VER_PRODUCTBUILD_QFE << 16);
1091     }
1092 
1093     /* Add loaded CmNtGlobalFlag value */
1094     NtGlobalFlag |= CmNtGlobalFlag;
1095 
1096     /* Initialize the executive at phase 0 */
1097     if (!ExInitSystem()) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
1098 
1099     /* Initialize the memory manager at phase 0 */
1100     if (!MmArmInitSystem(0, LoaderBlock)) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
1101 
1102     /* Load boot symbols */
1103     ExpLoadBootSymbols(LoaderBlock);
1104 
1105     /* Check if we should break after symbol load */
1106     if (KdBreakAfterSymbolLoad) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
1107 
1108     /* Check if this loader is compatible with NT 5.2 */
1109     if (LoaderBlock->Extension->Size >= sizeof(LOADER_PARAMETER_EXTENSION))
1110     {
1111         /* Setup headless terminal settings */
1112         HeadlessInit(LoaderBlock);
1113     }
1114 
1115     /* Set system ranges */
1116 #ifdef _M_AMD64
1117     SharedUserData->Reserved1 = MM_HIGHEST_USER_ADDRESS_WOW64;
1118     SharedUserData->Reserved3 = MM_SYSTEM_RANGE_START_WOW64;
1119 #else
1120     SharedUserData->Reserved1 = (ULONG_PTR)MmHighestUserAddress;
1121     SharedUserData->Reserved3 = (ULONG_PTR)MmSystemRangeStart;
1122 #endif
1123 
1124     /* Make a copy of the NLS Tables */
1125     ExpInitNls(LoaderBlock);
1126 
1127     /* Get the kernel's load entry */
1128     NtosEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
1129                                   LDR_DATA_TABLE_ENTRY,
1130                                   InLoadOrderLinks);
1131 
1132     /* Check if this is a service pack */
1133     if (CmNtCSDVersion & 0xFFFF)
1134     {
1135         /* Get the service pack string */
1136         Status = RtlFindMessage(NtosEntry->DllBase,
1137                                 11,
1138                                 0,
1139                                 WINDOWS_NT_CSD_STRING,
1140                                 &MsgEntry);
1141         if (NT_SUCCESS(Status))
1142         {
1143             /* Setup the string */
1144             RtlInitAnsiString(&CSDString, (PCHAR)MsgEntry->Text);
1145 
1146             /* Remove trailing newline */
1147             while ((CSDString.Length > 0) &&
1148                    ((CSDString.Buffer[CSDString.Length - 1] == '\r') ||
1149                     (CSDString.Buffer[CSDString.Length - 1] == '\n')))
1150             {
1151                 /* Skip the trailing character */
1152                 CSDString.Length--;
1153             }
1154 
1155             /* Fill the buffer with version information */
1156             Status = RtlStringCbPrintfA(Buffer,
1157                                         sizeof(Buffer),
1158                                         "%Z %u%c",
1159                                         &CSDString,
1160                                         (CmNtCSDVersion & 0xFF00) >> 8,
1161                                         (CmNtCSDVersion & 0xFF) ?
1162                                         'A' + (CmNtCSDVersion & 0xFF) - 1 :
1163                                         ANSI_NULL);
1164         }
1165         else
1166         {
1167             /* Build default string */
1168             Status = RtlStringCbPrintfA(Buffer,
1169                                         sizeof(Buffer),
1170                                         "CSD %04x",
1171                                         CmNtCSDVersion);
1172         }
1173 
1174         /* Check for success */
1175         if (!NT_SUCCESS(Status))
1176         {
1177             /* Fail */
1178             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1179         }
1180     }
1181     else
1182     {
1183         /* Then this is a beta */
1184         Status = RtlStringCbCopyExA(Buffer,
1185                                     sizeof(Buffer),
1186                                     VER_PRODUCTBETA_STR,
1187                                     NULL,
1188                                     &Remaining,
1189                                     0);
1190         if (!NT_SUCCESS(Status))
1191         {
1192             /* Fail */
1193             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1194         }
1195 
1196         /* Update length */
1197         CmCSDVersionString.MaximumLength = sizeof(Buffer) - (USHORT)Remaining;
1198     }
1199 
1200     /* Check if we have an RC number */
1201     if ((CmNtCSDVersion & 0xFFFF0000) && (CmNtCSDReleaseType == 1))
1202     {
1203         /* Check if we have no version data yet */
1204         if (!(*Buffer))
1205         {
1206             /* Set defaults */
1207             Remaining = sizeof(Buffer);
1208             RcEnd = Buffer;
1209         }
1210         else
1211         {
1212             /* Add comma and space */
1213             Status = RtlStringCbCatExA(Buffer,
1214                                        sizeof(Buffer),
1215                                        ", ",
1216                                        &RcEnd,
1217                                        &Remaining,
1218                                        0);
1219             if (!NT_SUCCESS(Status))
1220             {
1221                 /* Fail */
1222                 KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1223             }
1224         }
1225 
1226         /* Add the version format string */
1227         Status = RtlStringCbPrintfA(RcEnd,
1228                                     Remaining,
1229                                     "v.%u",
1230                                     (CmNtCSDVersion & 0xFFFF0000) >> 16);
1231         if (!NT_SUCCESS(Status))
1232         {
1233             /* Fail */
1234             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1235         }
1236     }
1237 
1238     /* Now setup the final string */
1239     RtlInitAnsiString(&CSDString, Buffer);
1240     Status = RtlAnsiStringToUnicodeString(&CmCSDVersionString,
1241                                           &CSDString,
1242                                           TRUE);
1243     if (!NT_SUCCESS(Status))
1244     {
1245         /* Fail */
1246         KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1247     }
1248 
1249     /* Add our version */
1250     Status = RtlStringCbPrintfA(VersionBuffer,
1251                                 sizeof(VersionBuffer),
1252                                 "%u.%u",
1253                                 VER_PRODUCTMAJORVERSION,
1254                                 VER_PRODUCTMINORVERSION);
1255     if (!NT_SUCCESS(Status))
1256     {
1257         /* Fail */
1258         KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1259     }
1260 
1261     /* Build the final version string */
1262     RtlCreateUnicodeStringFromAsciiz(&CmVersionString, VersionBuffer);
1263 
1264     /* Check if the user wants a kernel stack trace database */
1265     if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB)
1266     {
1267         /* FIXME: TODO */
1268         DPRINT1("Kernel-mode stack trace support not yet present."
1269                 "FLG_KERNEL_STACK_TRACE_DB flag ignored.\n");
1270     }
1271 
1272     /* Check if he wanted exception logging */
1273     if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
1274     {
1275         /* FIXME: TODO */
1276         DPRINT1("Kernel-mode exception logging support not yet present."
1277                 "FLG_ENABLE_EXCEPTION_LOGGING flag ignored.\n");
1278     }
1279 
1280     /* Initialize the Handle Table */
1281     ExpInitializeHandleTables();
1282 
1283 #if DBG
1284     /* On checked builds, allocate the system call count table */
1285     KeServiceDescriptorTable[0].Count =
1286         ExAllocatePoolWithTag(NonPagedPool,
1287                               KiServiceLimit * sizeof(ULONG),
1288                               'llaC');
1289 
1290     /* Use it for the shadow table too */
1291     KeServiceDescriptorTableShadow[0].Count = KeServiceDescriptorTable[0].Count;
1292 
1293     /* Make sure allocation succeeded */
1294     if (KeServiceDescriptorTable[0].Count)
1295     {
1296         /* Zero the call counts to 0 */
1297         RtlZeroMemory(KeServiceDescriptorTable[0].Count,
1298                       KiServiceLimit * sizeof(ULONG));
1299     }
1300 #endif
1301 
1302     /* Create the Basic Object Manager Types to allow new Object Types */
1303     if (!ObInitSystem()) KeBugCheck(OBJECT_INITIALIZATION_FAILED);
1304 
1305     /* Load basic Security for other Managers */
1306     if (!SeInitSystem()) KeBugCheck(SECURITY_INITIALIZATION_FAILED);
1307 
1308     /* Initialize the Process Manager */
1309     if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS_INITIALIZATION_FAILED);
1310 
1311     /* Initialize the PnP Manager */
1312     if (!PpInitSystem()) KeBugCheck(PP0_INITIALIZATION_FAILED);
1313 
1314     /* Initialize the User-Mode Debugging Subsystem */
1315     DbgkInitialize();
1316 
1317     /* Calculate the tick count multiplier */
1318     ExpTickCountMultiplier = ExComputeTickCountMultiplier(KeMaximumIncrement);
1319     SharedUserData->TickCountMultiplier = ExpTickCountMultiplier;
1320 
1321     /* Set the OS Version */
1322     SharedUserData->NtMajorVersion = NtMajorVersion;
1323     SharedUserData->NtMinorVersion = NtMinorVersion;
1324 
1325     /* Set the machine type */
1326     SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_NATIVE;
1327     SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_NATIVE;
1328 }
1329 
1330 VOID
1331 NTAPI
1332 MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
1333 
1334 INIT_FUNCTION
1335 VOID
1336 NTAPI
1337 Phase1InitializationDiscard(IN PVOID Context)
1338 {
1339     PLOADER_PARAMETER_BLOCK LoaderBlock = Context;
1340     NTSTATUS Status, MsgStatus;
1341     TIME_FIELDS TimeFields;
1342     LARGE_INTEGER SystemBootTime, UniversalBootTime, OldTime, Timeout;
1343     BOOLEAN SosEnabled, NoGuiBoot, ResetBias = FALSE, AlternateShell = FALSE;
1344     PLDR_DATA_TABLE_ENTRY NtosEntry;
1345     PMESSAGE_RESOURCE_ENTRY MsgEntry;
1346     PCHAR CommandLine, Y2KHackRequired, SafeBoot, Environment;
1347     PCHAR StringBuffer, EndBuffer, BeginBuffer, MpString = "";
1348     PINIT_BUFFER InitBuffer;
1349     ANSI_STRING TempString;
1350     ULONG LastTzBias, Length, YearHack = 0, Disposition, MessageCode = 0;
1351     SIZE_T Size;
1352     size_t Remaining;
1353     PRTL_USER_PROCESS_INFORMATION ProcessInfo;
1354     KEY_VALUE_PARTIAL_INFORMATION KeyPartialInfo;
1355     UNICODE_STRING KeyName;
1356     OBJECT_ATTRIBUTES ObjectAttributes;
1357     HANDLE KeyHandle, OptionHandle;
1358     PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
1359 
1360     /* Allocate the initialization buffer */
1361     InitBuffer = ExAllocatePoolWithTag(NonPagedPool,
1362                                        sizeof(INIT_BUFFER),
1363                                        TAG_INIT);
1364     if (!InitBuffer)
1365     {
1366         /* Bugcheck */
1367         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 8, 0, 0);
1368     }
1369 
1370     /* Set to phase 1 */
1371     ExpInitializationPhase = 1;
1372 
1373     /* Set us at maximum priority */
1374     KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
1375 
1376     /* Do Phase 1 HAL Initialization */
1377     if (!HalInitSystem(1, LoaderBlock)) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1378 
1379     /* Get the command line and upcase it */
1380     CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL);
1381 
1382     /* Check if GUI Boot is enabled */
1383     NoGuiBoot = (CommandLine && strstr(CommandLine, "NOGUIBOOT") != NULL);
1384 
1385     /* Get the SOS setting */
1386     SosEnabled = (CommandLine && strstr(CommandLine, "SOS") != NULL);
1387 
1388     /* Setup the boot driver */
1389     InbvEnableBootDriver(!NoGuiBoot);
1390     InbvDriverInitialize(LoaderBlock, IDB_MAX_RESOURCE);
1391 
1392     /* Check if GUI boot is enabled */
1393     if (!NoGuiBoot)
1394     {
1395         /* It is, display the boot logo and enable printing strings */
1396         InbvEnableDisplayString(SosEnabled);
1397         DisplayBootBitmap(SosEnabled);
1398     }
1399     else
1400     {
1401         /* Release display ownership if not using GUI boot */
1402         InbvNotifyDisplayOwnershipLost(NULL);
1403 
1404         /* Don't allow boot-time strings */
1405         InbvEnableDisplayString(FALSE);
1406     }
1407 
1408     /* Check if this is LiveCD (WinPE) mode */
1409     if (CommandLine && strstr(CommandLine, "MININT") != NULL)
1410     {
1411         /* Setup WinPE Settings */
1412         InitIsWinPEMode = TRUE;
1413         InitWinPEModeType |= (strstr(CommandLine, "INRAM") != NULL) ? 0x80000000 : 0x00000001;
1414     }
1415 
1416     /* Get the kernel's load entry */
1417     NtosEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
1418                                   LDR_DATA_TABLE_ENTRY,
1419                                   InLoadOrderLinks);
1420 
1421     /* Find the banner message */
1422     MsgStatus = RtlFindMessage(NtosEntry->DllBase,
1423                                11,
1424                                0,
1425                                WINDOWS_NT_BANNER,
1426                                &MsgEntry);
1427 
1428     /* Setup defaults and check if we have a version string */
1429     StringBuffer = InitBuffer->VersionBuffer;
1430     BeginBuffer = StringBuffer;
1431     EndBuffer = StringBuffer;
1432     Remaining = sizeof(InitBuffer->VersionBuffer);
1433     if (CmCSDVersionString.Length)
1434     {
1435         /* Print the version string */
1436         Status = RtlStringCbPrintfExA(StringBuffer,
1437                                       Remaining,
1438                                       &EndBuffer,
1439                                       &Remaining,
1440                                       0,
1441                                       ": %wZ",
1442                                       &CmCSDVersionString);
1443         if (!NT_SUCCESS(Status))
1444         {
1445             /* Bugcheck */
1446             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1447         }
1448     }
1449     else
1450     {
1451         /* No version */
1452         *EndBuffer = ANSI_NULL; /* Null-terminate the string */
1453     }
1454 
1455     /* Skip over the null-terminator to start a new string */
1456     ++EndBuffer;
1457     --Remaining;
1458 
1459     /* Build the version number */
1460     StringBuffer = InitBuffer->VersionNumber;
1461     Status = RtlStringCbPrintfA(StringBuffer,
1462                                 sizeof(InitBuffer->VersionNumber),
1463                                 "%u.%u",
1464                                 VER_PRODUCTMAJORVERSION,
1465                                 VER_PRODUCTMINORVERSION);
1466     if (!NT_SUCCESS(Status))
1467     {
1468         /* Bugcheck */
1469         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1470     }
1471 
1472     /* Check if we had found a banner message */
1473     if (NT_SUCCESS(MsgStatus))
1474     {
1475         /* Create the banner message */
1476         /* ReactOS specific: Report ReactOS version, NtBuildLab information and reported NT kernel version */
1477         Status = RtlStringCbPrintfA(EndBuffer,
1478                                     Remaining,
1479                                     (PCHAR)MsgEntry->Text,
1480                                     KERNEL_VERSION_STR,
1481                                     NtBuildLab,
1482                                     StringBuffer,
1483                                     NtBuildNumber & 0xFFFF,
1484                                     BeginBuffer);
1485         if (!NT_SUCCESS(Status))
1486         {
1487             /* Bugcheck */
1488             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1489         }
1490     }
1491     else
1492     {
1493         /* Use hard-coded banner message */
1494         Status = RtlStringCbCopyA(EndBuffer, Remaining, "REACTOS (R)\r\n");
1495         if (!NT_SUCCESS(Status))
1496         {
1497             /* Bugcheck */
1498             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1499         }
1500     }
1501 
1502     /* Display the version string on-screen */
1503     InbvDisplayString(EndBuffer);
1504 
1505     /* Initialize Power Subsystem in Phase 0 */
1506     if (!PoInitSystem(0)) KeBugCheck(INTERNAL_POWER_ERROR);
1507 
1508     /* Check for Y2K hack */
1509     Y2KHackRequired = CommandLine ? strstr(CommandLine, "YEAR") : NULL;
1510     if (Y2KHackRequired) Y2KHackRequired = strstr(Y2KHackRequired, "=");
1511     if (Y2KHackRequired) YearHack = atol(Y2KHackRequired + 1);
1512 
1513     /* Query the clock */
1514     if ((ExCmosClockIsSane) && (HalQueryRealTimeClock(&TimeFields)))
1515     {
1516         /* Check if we're using the Y2K hack */
1517         if (Y2KHackRequired) TimeFields.Year = (CSHORT)YearHack;
1518 
1519         /* Convert to time fields */
1520         RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
1521         UniversalBootTime = SystemBootTime;
1522 
1523         /* Check if real time is GMT */
1524         if (!ExpRealTimeIsUniversal)
1525         {
1526             /* Check if we don't have a valid bias */
1527             if (ExpLastTimeZoneBias == MAXULONG)
1528             {
1529                 /* Reset */
1530                 ResetBias = TRUE;
1531                 ExpLastTimeZoneBias = ExpAltTimeZoneBias;
1532             }
1533 
1534             /* Calculate the bias in seconds */
1535             ExpTimeZoneBias.QuadPart = Int32x32To64(ExpLastTimeZoneBias * 60,
1536                                                     10000000);
1537 
1538             /* Set the boot time-zone bias */
1539             SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
1540             SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
1541             SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
1542 
1543             /* Convert the boot time to local time, and set it */
1544             UniversalBootTime.QuadPart = SystemBootTime.QuadPart +
1545                                          ExpTimeZoneBias.QuadPart;
1546         }
1547 
1548         /* Update the system time */
1549         KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
1550 
1551         /* Do system callback */
1552         PoNotifySystemTimeSet();
1553 
1554         /* Remember this as the boot time */
1555         KeBootTime = UniversalBootTime;
1556         KeBootTimeBias = 0;
1557     }
1558 
1559     /* Initialize all processors */
1560     if (!HalAllProcessorsStarted()) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1561 
1562 #ifdef CONFIG_SMP
1563     /* HACK: We should use RtlFindMessage and not only fallback to this */
1564     MpString = "MultiProcessor Kernel\r\n";
1565 #endif
1566 
1567     /* Setup the "MP" String */
1568     RtlInitAnsiString(&TempString, MpString);
1569 
1570     /* Make sure to remove the \r\n if we actually have a string */
1571     while ((TempString.Length > 0) &&
1572            ((TempString.Buffer[TempString.Length - 1] == '\r') ||
1573             (TempString.Buffer[TempString.Length - 1] == '\n')))
1574     {
1575         /* Skip the trailing character */
1576         TempString.Length--;
1577     }
1578 
1579     /* Get the information string from our resource file */
1580     MsgStatus = RtlFindMessage(NtosEntry->DllBase,
1581                                11,
1582                                0,
1583                                KeNumberProcessors > 1 ?
1584                                WINDOWS_NT_INFO_STRING_PLURAL :
1585                                WINDOWS_NT_INFO_STRING,
1586                                &MsgEntry);
1587 
1588     /* Get total RAM size, in MiB */
1589     /* Round size up. Assumed to better match actual physical RAM size */
1590     Size = ALIGN_UP_BY(MmNumberOfPhysicalPages * PAGE_SIZE, 1024 * 1024) / (1024 * 1024);
1591 
1592     /* Create the string */
1593     StringBuffer = InitBuffer->VersionBuffer;
1594     Status = RtlStringCbPrintfA(StringBuffer,
1595                                 sizeof(InitBuffer->VersionBuffer),
1596                                 NT_SUCCESS(MsgStatus) ?
1597                                 (PCHAR)MsgEntry->Text :
1598                                 "%u System Processor [%Iu MB Memory] %Z\r\n",
1599                                 KeNumberProcessors,
1600                                 Size,
1601                                 &TempString);
1602     if (!NT_SUCCESS(Status))
1603     {
1604         /* Bugcheck */
1605         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 4, 0, 0);
1606     }
1607 
1608     /* Display RAM and CPU count */
1609     InbvDisplayString(StringBuffer);
1610 
1611     /* Update the progress bar */
1612     InbvUpdateProgressBar(5);
1613 
1614     /* Call OB initialization again */
1615     if (!ObInitSystem()) KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
1616 
1617     /* Initialize Basic System Objects and Worker Threads */
1618     if (!ExInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 1, 0);
1619 
1620     /* Initialize the later stages of the kernel */
1621     if (!KeInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 2, 0);
1622 
1623     /* Call KD Providers at Phase 1 */
1624     if (!KdInitSystem(ExpInitializationPhase, KeLoaderBlock))
1625     {
1626         /* Failed, bugcheck */
1627         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 3, 0);
1628     }
1629 
1630     /* Initialize the SRM in Phase 1 */
1631     if (!SeInitSystem()) KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
1632 
1633     /* Update the progress bar */
1634     InbvUpdateProgressBar(10);
1635 
1636     /* Create SystemRoot Link */
1637     Status = ExpCreateSystemRootLink(LoaderBlock);
1638     if (!NT_SUCCESS(Status))
1639     {
1640         /* Failed to create the system root link */
1641         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 0, 0, 0);
1642     }
1643 
1644     /* Set up Region Maps, Sections and the Paging File */
1645     if (!MmInitSystem(1, LoaderBlock)) KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
1646 
1647     /* Create NLS section */
1648     ExpInitNls(LoaderBlock);
1649 
1650     /* Initialize Cache Views */
1651     if (!CcInitializeCacheManager()) KeBugCheck(CACHE_INITIALIZATION_FAILED);
1652 
1653     /* Initialize the Registry */
1654     if (!CmInitSystem1()) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
1655 
1656     /* Initialize Prefetcher */
1657     CcPfInitializePrefetcher();
1658 
1659     /* Update progress bar */
1660     InbvUpdateProgressBar(15);
1661 
1662     /* Update timezone information */
1663     LastTzBias = ExpLastTimeZoneBias;
1664     ExRefreshTimeZoneInformation(&SystemBootTime);
1665 
1666     /* Check if we're resetting timezone data */
1667     if (ResetBias)
1668     {
1669         /* Convert the local time to system time */
1670         ExLocalTimeToSystemTime(&SystemBootTime, &UniversalBootTime);
1671         KeBootTime = UniversalBootTime;
1672         KeBootTimeBias = 0;
1673 
1674         /* Set the new time */
1675         KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
1676     }
1677     else
1678     {
1679         /* Check if the timezone switched and update the time */
1680         if (LastTzBias != ExpLastTimeZoneBias) ZwSetSystemTime(NULL, NULL);
1681     }
1682 
1683     /* Initialize the File System Runtime Library */
1684     if (!FsRtlInitSystem()) KeBugCheck(FILE_INITIALIZATION_FAILED);
1685 
1686     /* Initialize range lists */
1687     RtlInitializeRangeListPackage();
1688 
1689     /* Report all resources used by HAL */
1690     HalReportResourceUsage();
1691 
1692     /* Call the debugger DLL */
1693     KdDebuggerInitialize1(LoaderBlock);
1694 
1695     /* Setup PnP Manager in phase 1 */
1696     if (!PpInitSystem()) KeBugCheck(PP1_INITIALIZATION_FAILED);
1697 
1698     /* Update progress bar */
1699     InbvUpdateProgressBar(20);
1700 
1701     /* Initialize LPC */
1702     if (!LpcInitSystem()) KeBugCheck(LPC_INITIALIZATION_FAILED);
1703 
1704     /* Make sure we have a command line */
1705     if (CommandLine)
1706     {
1707         /* Check if this is a safe mode boot */
1708         SafeBoot = strstr(CommandLine, "SAFEBOOT:");
1709         if (SafeBoot)
1710         {
1711             /* Check what kind of boot this is */
1712             SafeBoot += 9;
1713             if (!strncmp(SafeBoot, "MINIMAL", 7))
1714             {
1715                 /* Minimal mode */
1716                 InitSafeBootMode = 1;
1717                 SafeBoot += 7;
1718                 MessageCode = BOOTING_IN_SAFEMODE_MINIMAL;
1719             }
1720             else if (!strncmp(SafeBoot, "NETWORK", 7))
1721             {
1722                 /* With Networking */
1723                 InitSafeBootMode = 2;
1724                 SafeBoot += 7;
1725                 MessageCode = BOOTING_IN_SAFEMODE_NETWORK;
1726             }
1727             else if (!strncmp(SafeBoot, "DSREPAIR", 8))
1728             {
1729                 /* Domain Server Repair */
1730                 InitSafeBootMode = 3;
1731                 SafeBoot += 8;
1732                 MessageCode = BOOTING_IN_SAFEMODE_DSREPAIR;
1733 
1734             }
1735             else
1736             {
1737                 /* Invalid */
1738                 InitSafeBootMode = 0;
1739             }
1740 
1741             /* Check if there's any settings left */
1742             if (*SafeBoot)
1743             {
1744                 /* Check if an alternate shell was requested */
1745                 if (!strncmp(SafeBoot, "(ALTERNATESHELL)", 16))
1746                 {
1747                     /* Remember this for later */
1748                     AlternateShell = TRUE;
1749                 }
1750             }
1751 
1752             /* Find the message to print out */
1753             Status = RtlFindMessage(NtosEntry->DllBase,
1754                                     11,
1755                                     0,
1756                                     MessageCode,
1757                                     &MsgEntry);
1758             if (NT_SUCCESS(Status))
1759             {
1760                 /* Display it */
1761                 InbvDisplayString((PCHAR)MsgEntry->Text);
1762             }
1763         }
1764     }
1765 
1766     /* Make sure we have a command line */
1767     if (CommandLine)
1768     {
1769         /* Check if bootlogging is enabled */
1770         if (strstr(CommandLine, "BOOTLOG"))
1771         {
1772             /* Find the message to print out */
1773             Status = RtlFindMessage(NtosEntry->DllBase,
1774                                     11,
1775                                     0,
1776                                     BOOTLOG_ENABLED,
1777                                     &MsgEntry);
1778             if (NT_SUCCESS(Status))
1779             {
1780                 /* Display it */
1781                 InbvDisplayString((PCHAR)MsgEntry->Text);
1782             }
1783 
1784             /* Setup boot logging */
1785             //IopInitializeBootLogging(LoaderBlock, InitBuffer->BootlogHeader);
1786         }
1787     }
1788 
1789     /* Setup the Executive in Phase 2 */
1790     //ExInitSystemPhase2();
1791 
1792     /* Update progress bar */
1793     InbvUpdateProgressBar(25);
1794 
1795     /* No KD Time Slip is pending */
1796     KdpTimeSlipPending = 0;
1797 
1798     /* Initialize in-place execution support */
1799     XIPInit(LoaderBlock);
1800 
1801     /* Set maximum update to 75% */
1802     InbvSetProgressBarSubset(25, 75);
1803 
1804     /* Initialize the I/O Subsystem */
1805     if (!IoInitSystem(LoaderBlock)) KeBugCheck(IO1_INITIALIZATION_FAILED);
1806 
1807     /* Set maximum update to 100% */
1808     InbvSetProgressBarSubset(0, 100);
1809 
1810     /* Are we in safe mode? */
1811     if (InitSafeBootMode)
1812     {
1813         /* Open the safe boot key */
1814         RtlInitUnicodeString(&KeyName,
1815                              L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"
1816                              L"\\CONTROL\\SAFEBOOT");
1817         InitializeObjectAttributes(&ObjectAttributes,
1818                                    &KeyName,
1819                                    OBJ_CASE_INSENSITIVE,
1820                                    NULL,
1821                                    NULL);
1822         Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
1823         if (NT_SUCCESS(Status))
1824         {
1825             /* First check if we have an alternate shell */
1826             if (AlternateShell)
1827             {
1828                 /* Make sure that the registry has one setup */
1829                 RtlInitUnicodeString(&KeyName, L"AlternateShell");
1830                 Status = NtQueryValueKey(KeyHandle,
1831                                          &KeyName,
1832                                          KeyValuePartialInformation,
1833                                          &KeyPartialInfo,
1834                                          sizeof(KeyPartialInfo),
1835                                          &Length);
1836                 if (!(NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW))
1837                 {
1838                     AlternateShell = FALSE;
1839                 }
1840             }
1841 
1842             /* Create the option key */
1843             RtlInitUnicodeString(&KeyName, L"Option");
1844             InitializeObjectAttributes(&ObjectAttributes,
1845                                        &KeyName,
1846                                        OBJ_CASE_INSENSITIVE,
1847                                        KeyHandle,
1848                                        NULL);
1849             Status = ZwCreateKey(&OptionHandle,
1850                                  KEY_ALL_ACCESS,
1851                                  &ObjectAttributes,
1852                                  0,
1853                                  NULL,
1854                                  REG_OPTION_VOLATILE,
1855                                  &Disposition);
1856             NtClose(KeyHandle);
1857 
1858             /* Check if the key create worked */
1859             if (NT_SUCCESS(Status))
1860             {
1861                 /* Write the safe boot type */
1862                 RtlInitUnicodeString(&KeyName, L"OptionValue");
1863                 NtSetValueKey(OptionHandle,
1864                               &KeyName,
1865                               0,
1866                               REG_DWORD,
1867                               &InitSafeBootMode,
1868                               sizeof(InitSafeBootMode));
1869 
1870                 /* Check if we have to use an alternate shell */
1871                 if (AlternateShell)
1872                 {
1873                     /* Remember this for later */
1874                     Disposition = TRUE;
1875                     RtlInitUnicodeString(&KeyName, L"UseAlternateShell");
1876                     NtSetValueKey(OptionHandle,
1877                                   &KeyName,
1878                                   0,
1879                                   REG_DWORD,
1880                                   &Disposition,
1881                                   sizeof(Disposition));
1882                 }
1883 
1884                 /* Close the options key handle */
1885                 NtClose(OptionHandle);
1886             }
1887         }
1888     }
1889 
1890     /* Are we in Win PE mode? */
1891     if (InitIsWinPEMode)
1892     {
1893         /* Open the safe control key */
1894         RtlInitUnicodeString(&KeyName,
1895                              L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"
1896                              L"\\CONTROL");
1897         InitializeObjectAttributes(&ObjectAttributes,
1898                                    &KeyName,
1899                                    OBJ_CASE_INSENSITIVE,
1900                                    NULL,
1901                                    NULL);
1902         Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
1903         if (!NT_SUCCESS(Status))
1904         {
1905             /* Bugcheck */
1906             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 6, 0, 0);
1907         }
1908 
1909         /* Create the MiniNT key */
1910         RtlInitUnicodeString(&KeyName, L"MiniNT");
1911         InitializeObjectAttributes(&ObjectAttributes,
1912                                    &KeyName,
1913                                    OBJ_CASE_INSENSITIVE,
1914                                    KeyHandle,
1915                                    NULL);
1916         Status = ZwCreateKey(&OptionHandle,
1917                              KEY_ALL_ACCESS,
1918                              &ObjectAttributes,
1919                              0,
1920                              NULL,
1921                              REG_OPTION_VOLATILE,
1922                              &Disposition);
1923         if (!NT_SUCCESS(Status))
1924         {
1925             /* Bugcheck */
1926             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 6, 0, 0);
1927         }
1928 
1929         /* Close the handles */
1930         NtClose(KeyHandle);
1931         NtClose(OptionHandle);
1932     }
1933 
1934     /* FIXME: This doesn't do anything for now */
1935     MmArmInitSystem(2, LoaderBlock);
1936 
1937     /* Update progress bar */
1938     InbvUpdateProgressBar(80);
1939 
1940     /* Initialize VDM support */
1941 #if defined(_M_IX86)
1942     KeI386VdmInitialize();
1943 #endif
1944 
1945     /* Initialize Power Subsystem in Phase 1*/
1946     if (!PoInitSystem(1)) KeBugCheck(INTERNAL_POWER_ERROR);
1947 
1948     /* Update progress bar */
1949     InbvUpdateProgressBar(90);
1950 
1951     /* Initialize the Process Manager at Phase 1 */
1952     if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
1953 
1954     /* Make sure nobody touches the loader block again */
1955     if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
1956     MmFreeLoaderBlock(LoaderBlock);
1957     LoaderBlock = Context = NULL;
1958 
1959     /* Initialize the SRM in phase 1 */
1960     if (!SeRmInitPhase1()) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
1961 
1962     /* Update progress bar */
1963     InbvUpdateProgressBar(100);
1964 
1965     /* Clear the screen */
1966     if (InbvBootDriverInstalled) FinalizeBootLogo();
1967 
1968     /* Allow strings to be displayed */
1969     InbvEnableDisplayString(TRUE);
1970 
1971     /* Launch initial process */
1972     DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed);
1973     ProcessInfo = &InitBuffer->ProcessInfo;
1974     ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
1975 
1976     /* Wait 5 seconds for initial process to initialize */
1977     Timeout.QuadPart = Int32x32To64(5, -10000000);
1978     Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
1979     if (Status == STATUS_SUCCESS)
1980     {
1981         /* Failed, display error */
1982         DPRINT1("INIT: Session Manager terminated.\n");
1983 
1984         /* Bugcheck the system if SMSS couldn't initialize */
1985         KeBugCheck(SESSION5_INITIALIZATION_FAILED);
1986     }
1987 
1988     /* Close process handles */
1989     ZwClose(ProcessInfo->ThreadHandle);
1990     ZwClose(ProcessInfo->ProcessHandle);
1991 
1992     /* Free the initial process environment */
1993     Size = 0;
1994     ZwFreeVirtualMemory(NtCurrentProcess(),
1995                         (PVOID*)&Environment,
1996                         &Size,
1997                         MEM_RELEASE);
1998 
1999     /* Free the initial process parameters */
2000     Size = 0;
2001     ZwFreeVirtualMemory(NtCurrentProcess(),
2002                         (PVOID*)&ProcessParameters,
2003                         &Size,
2004                         MEM_RELEASE);
2005 
2006     /* Increase init phase */
2007     ExpInitializationPhase++;
2008 
2009     /* Free the boot buffer */
2010     ExFreePoolWithTag(InitBuffer, TAG_INIT);
2011     DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed);
2012 }
2013 
2014 VOID
2015 NTAPI
2016 Phase1Initialization(IN PVOID Context)
2017 {
2018     /* Do the .INIT part of Phase 1 which we can free later */
2019     Phase1InitializationDiscard(Context);
2020 
2021     /* Jump into zero page thread */
2022     MmZeroPageThread();
2023 }
2024