xref: /reactos/ntoskrnl/ex/init.c (revision 8c2e9189)
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 NTSTATUS
95 NTAPI
96 INIT_FUNCTION
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 VOID
207 NTAPI
208 INIT_FUNCTION
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 VOID
383 NTAPI
384 INIT_FUNCTION
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 ULONG
600 NTAPI
601 INIT_FUNCTION
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 BOOLEAN
633 NTAPI
634 INIT_FUNCTION
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 BOOLEAN
656 NTAPI
657 INIT_FUNCTION
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     ExpInitUuids();
715 
716     /* Initialize keyed events */
717     if (ExpInitializeKeyedEventImplementation() == FALSE)
718     {
719         DPRINT1("Executive: Keyed event initialization failed\n");
720         return FALSE;
721     }
722 
723     /* Initialize Win32K */
724     if (ExpWin32kInit() == FALSE)
725     {
726         DPRINT1("Executive: Win32 initialization failed\n");
727         return FALSE;
728     }
729     return TRUE;
730 }
731 
732 BOOLEAN
733 NTAPI
734 INIT_FUNCTION
735 ExInitSystem(VOID)
736 {
737     /* Check the initialization phase */
738     switch (ExpInitializationPhase)
739     {
740         case 0:
741 
742             /* Do Phase 0 */
743             return ExpInitSystemPhase0();
744 
745         case 1:
746 
747             /* Do Phase 1 */
748             return ExpInitSystemPhase1();
749 
750         default:
751 
752             /* Don't know any other phase! Bugcheck! */
753             KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
754             return FALSE;
755     }
756 }
757 
758 BOOLEAN
759 NTAPI
760 INIT_FUNCTION
761 ExpIsLoaderValid(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
762 {
763     PLOADER_PARAMETER_EXTENSION Extension;
764 
765     /* Get the loader extension */
766     Extension = LoaderBlock->Extension;
767 
768     /* Validate the size (Windows 2003 loader doesn't provide more) */
769     if (Extension->Size < LOADER_PARAMETER_EXTENSION_MIN_SIZE) return FALSE;
770 
771     /* Don't validate upper versions */
772     if (Extension->MajorVersion > VER_PRODUCTMAJORVERSION) return TRUE;
773 
774     /* Fail if this is NT 4 */
775     if (Extension->MajorVersion < VER_PRODUCTMAJORVERSION) return FALSE;
776 
777     /* Fail if this is XP */
778     if (Extension->MinorVersion < VER_PRODUCTMINORVERSION) return FALSE;
779 
780     /* This is 2003 or newer, approve it */
781     return TRUE;
782 }
783 
784 VOID
785 NTAPI
786 INIT_FUNCTION
787 ExpLoadBootSymbols(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
788 {
789     ULONG i = 0;
790     PLIST_ENTRY NextEntry;
791     ULONG Count, Length;
792     PWCHAR Name;
793     PLDR_DATA_TABLE_ENTRY LdrEntry;
794     CHAR NameBuffer[256];
795     STRING SymbolString;
796     NTSTATUS Status;
797 
798     /* Loop the driver list */
799     NextEntry = LoaderBlock->LoadOrderListHead.Flink;
800     while (NextEntry != &LoaderBlock->LoadOrderListHead)
801     {
802         /* Skip the first two images */
803         if (i >= 2)
804         {
805             /* Get the entry */
806             LdrEntry = CONTAINING_RECORD(NextEntry,
807                                          LDR_DATA_TABLE_ENTRY,
808                                          InLoadOrderLinks);
809             if (LdrEntry->FullDllName.Buffer[0] == L'\\')
810             {
811                 /* We have a name, read its data */
812                 Name = LdrEntry->FullDllName.Buffer;
813                 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
814 
815                 /* Check if our buffer can hold it */
816                 if (sizeof(NameBuffer) < Length + sizeof(ANSI_NULL))
817                 {
818                     /* It's too long */
819                     Status = STATUS_BUFFER_OVERFLOW;
820                 }
821                 else
822                 {
823                     /* Copy the name */
824                     Count = 0;
825                     do
826                     {
827                         /* Copy the character */
828                         NameBuffer[Count++] = (CHAR)*Name++;
829                     } while (Count < Length);
830 
831                     /* Null-terminate */
832                     NameBuffer[Count] = ANSI_NULL;
833                     Status = STATUS_SUCCESS;
834                 }
835             }
836             else
837             {
838                 /* Safely print the string into our buffer */
839                 Status = RtlStringCbPrintfA(NameBuffer,
840                                             sizeof(NameBuffer),
841                                             "%S\\System32\\Drivers\\%wZ",
842                                             &SharedUserData->NtSystemRoot[2],
843                                             &LdrEntry->BaseDllName);
844             }
845 
846             /* Check if the buffer was ok */
847             if (NT_SUCCESS(Status))
848             {
849                 /* Initialize the STRING for the debugger */
850                 RtlInitString(&SymbolString, NameBuffer);
851 
852                 /* Load the symbols */
853                 DbgLoadImageSymbols(&SymbolString,
854                                     LdrEntry->DllBase,
855                                     (ULONG_PTR)PsGetCurrentProcessId());
856             }
857         }
858 
859         /* Go to the next entry */
860         i++;
861         NextEntry = NextEntry->Flink;
862     }
863 }
864 
865 VOID
866 NTAPI
867 INIT_FUNCTION
868 ExBurnMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
869              IN ULONG_PTR PagesToDestroy,
870              IN TYPE_OF_MEMORY MemoryType)
871 {
872     PLIST_ENTRY ListEntry;
873     PMEMORY_ALLOCATION_DESCRIPTOR MemDescriptor;
874 
875     DPRINT1("Burn RAM amount: %lu pages\n", PagesToDestroy);
876 
877     /* Loop the memory descriptors, beginning at the end */
878     for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Blink;
879          ListEntry != &LoaderBlock->MemoryDescriptorListHead;
880          ListEntry = ListEntry->Blink)
881     {
882         /* Get the memory descriptor structure */
883         MemDescriptor = CONTAINING_RECORD(ListEntry,
884                                           MEMORY_ALLOCATION_DESCRIPTOR,
885                                           ListEntry);
886 
887         /* Is memory free there or is it temporary? */
888         if (MemDescriptor->MemoryType == LoaderFree ||
889             MemDescriptor->MemoryType == LoaderFirmwareTemporary)
890         {
891             /* Check if the descriptor has more pages than we want */
892             if (MemDescriptor->PageCount > PagesToDestroy)
893             {
894                 /* Change block's page count, ntoskrnl doesn't care much */
895                 MemDescriptor->PageCount -= PagesToDestroy;
896                 break;
897             }
898             else
899             {
900                 /* Change block type */
901                 MemDescriptor->MemoryType = MemoryType;
902                 PagesToDestroy -= MemDescriptor->PageCount;
903 
904                 /* Check if we are done */
905                 if (PagesToDestroy == 0) break;
906             }
907         }
908     }
909 }
910 
911 VOID
912 NTAPI
913 INIT_FUNCTION
914 ExpInitializeExecutive(IN ULONG Cpu,
915                        IN PLOADER_PARAMETER_BLOCK LoaderBlock)
916 {
917     PNLS_DATA_BLOCK NlsData;
918     CHAR Buffer[256];
919     ANSI_STRING AnsiPath;
920     NTSTATUS Status;
921     PCHAR CommandLine, PerfMem;
922     ULONG PerfMemUsed;
923     PLDR_DATA_TABLE_ENTRY NtosEntry;
924     PMESSAGE_RESOURCE_ENTRY MsgEntry;
925     ANSI_STRING CSDString;
926     size_t Remaining = 0;
927     PCHAR RcEnd = NULL;
928     CHAR VersionBuffer[65];
929 
930     /* Validate Loader */
931     if (!ExpIsLoaderValid(LoaderBlock))
932     {
933         /* Invalid loader version */
934         KeBugCheckEx(MISMATCHED_HAL,
935                      3,
936                      LoaderBlock->Extension->Size,
937                      LoaderBlock->Extension->MajorVersion,
938                      LoaderBlock->Extension->MinorVersion);
939     }
940 
941     /* Initialize PRCB pool lookaside pointers */
942     ExInitPoolLookasidePointers();
943 
944     /* Check if this is an application CPU */
945     if (Cpu)
946     {
947         /* Then simply initialize it with HAL */
948         if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
949         {
950             /* Initialization failed */
951             KeBugCheck(HAL_INITIALIZATION_FAILED);
952         }
953 
954         /* We're done */
955         return;
956     }
957 
958     /* Assume no text-mode or remote boot */
959     ExpInTextModeSetup = FALSE;
960     IoRemoteBootClient = FALSE;
961 
962     /* Check if we have a setup loader block */
963     if (LoaderBlock->SetupLdrBlock)
964     {
965         /* Check if this is text-mode setup */
966         if (LoaderBlock->SetupLdrBlock->Flags & SETUPLDR_TEXT_MODE) ExpInTextModeSetup = TRUE;
967 
968         /* Check if this is network boot */
969         if (LoaderBlock->SetupLdrBlock->Flags & SETUPLDR_REMOTE_BOOT)
970         {
971             /* Set variable */
972             IoRemoteBootClient = TRUE;
973 
974             /* Make sure we're actually booting off the network */
975             ASSERT(!_memicmp(LoaderBlock->ArcBootDeviceName, "net(0)", 6));
976         }
977     }
978 
979     /* Set phase to 0 */
980     ExpInitializationPhase = 0;
981 
982     /* Get boot command line */
983     CommandLine = LoaderBlock->LoadOptions;
984     if (CommandLine)
985     {
986         /* Upcase it for comparison and check if we're in performance mode */
987         _strupr(CommandLine);
988         PerfMem = strstr(CommandLine, "PERFMEM");
989         if (PerfMem)
990         {
991             /* Check if the user gave a number of bytes to use */
992             PerfMem = strstr(PerfMem, "=");
993             if (PerfMem)
994             {
995                 /* Read the number of pages we'll use */
996                 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
997                 if (PerfMem)
998                 {
999                     /* FIXME: TODO */
1000                     DPRINT1("BBT performance mode not yet supported."
1001                             "/PERFMEM option ignored.\n");
1002                 }
1003             }
1004         }
1005 
1006         /* Check if we're burning memory */
1007         PerfMem = strstr(CommandLine, "BURNMEMORY");
1008         if (PerfMem)
1009         {
1010             /* Check if the user gave a number of bytes to use */
1011             PerfMem = strstr(PerfMem, "=");
1012             if (PerfMem)
1013             {
1014                 /* Read the number of pages we'll use */
1015                 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
1016                 if (PerfMemUsed) ExBurnMemory(LoaderBlock, PerfMemUsed, LoaderBad);
1017             }
1018         }
1019     }
1020 
1021     /* Setup NLS Base and offsets */
1022     NlsData = LoaderBlock->NlsData;
1023     ExpNlsTableBase = NlsData->AnsiCodePageData;
1024     ExpAnsiCodePageDataOffset = 0;
1025     ExpOemCodePageDataOffset = (ULONG)((ULONG_PTR)NlsData->OemCodePageData -
1026                                        (ULONG_PTR)NlsData->AnsiCodePageData);
1027     ExpUnicodeCaseTableDataOffset = (ULONG)((ULONG_PTR)NlsData->UnicodeCodePageData -
1028                                             (ULONG_PTR)NlsData->AnsiCodePageData);
1029 
1030     /* Initialize the NLS Tables */
1031     RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
1032                              ExpAnsiCodePageDataOffset),
1033                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
1034                              ExpOemCodePageDataOffset),
1035                      (PVOID)((ULONG_PTR)ExpNlsTableBase +
1036                              ExpUnicodeCaseTableDataOffset),
1037                      &ExpNlsTableInfo);
1038     RtlResetRtlTranslations(&ExpNlsTableInfo);
1039 
1040     /* Now initialize the HAL */
1041     if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
1042     {
1043         /* HAL failed to initialize, bugcheck */
1044         KeBugCheck(HAL_INITIALIZATION_FAILED);
1045     }
1046 
1047     /* Make sure interrupts are active now */
1048     _enable();
1049 
1050     /* Clear the crypto exponent */
1051     SharedUserData->CryptoExponent = 0;
1052 
1053     /* Set global flags for the checked build */
1054 #if DBG
1055     NtGlobalFlag |= FLG_ENABLE_CLOSE_EXCEPTIONS |
1056                     FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
1057 #endif
1058 
1059     /* Setup NT System Root Path */
1060     sprintf(Buffer, "C:%s", LoaderBlock->NtBootPathName);
1061 
1062     /* Convert to ANSI_STRING and null-terminate it */
1063     RtlInitString(&AnsiPath, Buffer);
1064     Buffer[--AnsiPath.Length] = ANSI_NULL;
1065 
1066     /* Get the string from KUSER_SHARED_DATA's buffer */
1067     RtlInitEmptyUnicodeString(&NtSystemRoot,
1068                               SharedUserData->NtSystemRoot,
1069                               sizeof(SharedUserData->NtSystemRoot));
1070 
1071     /* Now fill it in */
1072     Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE);
1073     if (!NT_SUCCESS(Status)) KeBugCheck(SESSION3_INITIALIZATION_FAILED);
1074 
1075     /* Setup bugcheck messages */
1076     KiInitializeBugCheck();
1077 
1078     /* Setup initial system settings */
1079     CmGetSystemControlValues(LoaderBlock->RegistryBase, CmControlVector);
1080 
1081     /* Set the Service Pack Number and add it to the CSD Version number if needed */
1082     CmNtSpBuildNumber = VER_PRODUCTBUILD_QFE;
1083     if (((CmNtCSDVersion & 0xFFFF0000) == 0) && (CmNtCSDReleaseType == 1))
1084     {
1085         CmNtCSDVersion |= (VER_PRODUCTBUILD_QFE << 16);
1086     }
1087 
1088     /* Add loaded CmNtGlobalFlag value */
1089     NtGlobalFlag |= CmNtGlobalFlag;
1090 
1091     /* Initialize the executive at phase 0 */
1092     if (!ExInitSystem()) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
1093 
1094     /* Initialize the memory manager at phase 0 */
1095     if (!MmArmInitSystem(0, LoaderBlock)) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
1096 
1097     /* Load boot symbols */
1098     ExpLoadBootSymbols(LoaderBlock);
1099 
1100     /* Check if we should break after symbol load */
1101     if (KdBreakAfterSymbolLoad) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
1102 
1103     /* Check if this loader is compatible with NT 5.2 */
1104     if (LoaderBlock->Extension->Size >= sizeof(LOADER_PARAMETER_EXTENSION))
1105     {
1106         /* Setup headless terminal settings */
1107         HeadlessInit(LoaderBlock);
1108     }
1109 
1110     /* Set system ranges */
1111 #ifdef _M_AMD64
1112     SharedUserData->Reserved1 = MM_HIGHEST_USER_ADDRESS_WOW64;
1113     SharedUserData->Reserved3 = MM_SYSTEM_RANGE_START_WOW64;
1114 #else
1115     SharedUserData->Reserved1 = (ULONG_PTR)MmHighestUserAddress;
1116     SharedUserData->Reserved3 = (ULONG_PTR)MmSystemRangeStart;
1117 #endif
1118 
1119     /* Make a copy of the NLS Tables */
1120     ExpInitNls(LoaderBlock);
1121 
1122     /* Get the kernel's load entry */
1123     NtosEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
1124                                   LDR_DATA_TABLE_ENTRY,
1125                                   InLoadOrderLinks);
1126 
1127     /* Check if this is a service pack */
1128     if (CmNtCSDVersion & 0xFFFF)
1129     {
1130         /* Get the service pack string */
1131         Status = RtlFindMessage(NtosEntry->DllBase,
1132                                 11,
1133                                 0,
1134                                 WINDOWS_NT_CSD_STRING,
1135                                 &MsgEntry);
1136         if (NT_SUCCESS(Status))
1137         {
1138             /* Setup the string */
1139             RtlInitAnsiString(&CSDString, (PCHAR)MsgEntry->Text);
1140 
1141             /* Remove trailing newline */
1142             while ((CSDString.Length > 0) &&
1143                    ((CSDString.Buffer[CSDString.Length - 1] == '\r') ||
1144                     (CSDString.Buffer[CSDString.Length - 1] == '\n')))
1145             {
1146                 /* Skip the trailing character */
1147                 CSDString.Length--;
1148             }
1149 
1150             /* Fill the buffer with version information */
1151             Status = RtlStringCbPrintfA(Buffer,
1152                                         sizeof(Buffer),
1153                                         "%Z %u%c",
1154                                         &CSDString,
1155                                         (CmNtCSDVersion & 0xFF00) >> 8,
1156                                         (CmNtCSDVersion & 0xFF) ?
1157                                         'A' + (CmNtCSDVersion & 0xFF) - 1 :
1158                                         ANSI_NULL);
1159         }
1160         else
1161         {
1162             /* Build default string */
1163             Status = RtlStringCbPrintfA(Buffer,
1164                                         sizeof(Buffer),
1165                                         "CSD %04x",
1166                                         CmNtCSDVersion);
1167         }
1168 
1169         /* Check for success */
1170         if (!NT_SUCCESS(Status))
1171         {
1172             /* Fail */
1173             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1174         }
1175     }
1176     else
1177     {
1178         /* Then this is a beta */
1179         Status = RtlStringCbCopyExA(Buffer,
1180                                     sizeof(Buffer),
1181                                     VER_PRODUCTBETA_STR,
1182                                     NULL,
1183                                     &Remaining,
1184                                     0);
1185         if (!NT_SUCCESS(Status))
1186         {
1187             /* Fail */
1188             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1189         }
1190 
1191         /* Update length */
1192         CmCSDVersionString.MaximumLength = sizeof(Buffer) - (USHORT)Remaining;
1193     }
1194 
1195     /* Check if we have an RC number */
1196     if ((CmNtCSDVersion & 0xFFFF0000) && (CmNtCSDReleaseType == 1))
1197     {
1198         /* Check if we have no version data yet */
1199         if (!(*Buffer))
1200         {
1201             /* Set defaults */
1202             Remaining = sizeof(Buffer);
1203             RcEnd = Buffer;
1204         }
1205         else
1206         {
1207             /* Add comma and space */
1208             Status = RtlStringCbCatExA(Buffer,
1209                                        sizeof(Buffer),
1210                                        ", ",
1211                                        &RcEnd,
1212                                        &Remaining,
1213                                        0);
1214             if (!NT_SUCCESS(Status))
1215             {
1216                 /* Fail */
1217                 KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1218             }
1219         }
1220 
1221         /* Add the version format string */
1222         Status = RtlStringCbPrintfA(RcEnd,
1223                                     Remaining,
1224                                     "v.%u",
1225                                     (CmNtCSDVersion & 0xFFFF0000) >> 16);
1226         if (!NT_SUCCESS(Status))
1227         {
1228             /* Fail */
1229             KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1230         }
1231     }
1232 
1233     /* Now setup the final string */
1234     RtlInitAnsiString(&CSDString, Buffer);
1235     Status = RtlAnsiStringToUnicodeString(&CmCSDVersionString,
1236                                           &CSDString,
1237                                           TRUE);
1238     if (!NT_SUCCESS(Status))
1239     {
1240         /* Fail */
1241         KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1242     }
1243 
1244     /* Add our version */
1245     Status = RtlStringCbPrintfA(VersionBuffer,
1246                                 sizeof(VersionBuffer),
1247                                 "%u.%u",
1248                                 VER_PRODUCTMAJORVERSION,
1249                                 VER_PRODUCTMINORVERSION);
1250     if (!NT_SUCCESS(Status))
1251     {
1252         /* Fail */
1253         KeBugCheckEx(PHASE0_INITIALIZATION_FAILED, Status, 0, 0, 0);
1254     }
1255 
1256     /* Build the final version string */
1257     RtlCreateUnicodeStringFromAsciiz(&CmVersionString, VersionBuffer);
1258 
1259     /* Check if the user wants a kernel stack trace database */
1260     if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB)
1261     {
1262         /* FIXME: TODO */
1263         DPRINT1("Kernel-mode stack trace support not yet present."
1264                 "FLG_KERNEL_STACK_TRACE_DB flag ignored.\n");
1265     }
1266 
1267     /* Check if he wanted exception logging */
1268     if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
1269     {
1270         /* FIXME: TODO */
1271         DPRINT1("Kernel-mode exception logging support not yet present."
1272                 "FLG_ENABLE_EXCEPTION_LOGGING flag ignored.\n");
1273     }
1274 
1275     /* Initialize the Handle Table */
1276     ExpInitializeHandleTables();
1277 
1278 #if DBG
1279     /* On checked builds, allocate the system call count table */
1280     KeServiceDescriptorTable[0].Count =
1281         ExAllocatePoolWithTag(NonPagedPool,
1282                               KiServiceLimit * sizeof(ULONG),
1283                               'llaC');
1284 
1285     /* Use it for the shadow table too */
1286     KeServiceDescriptorTableShadow[0].Count = KeServiceDescriptorTable[0].Count;
1287 
1288     /* Make sure allocation succeeded */
1289     if (KeServiceDescriptorTable[0].Count)
1290     {
1291         /* Zero the call counts to 0 */
1292         RtlZeroMemory(KeServiceDescriptorTable[0].Count,
1293                       KiServiceLimit * sizeof(ULONG));
1294     }
1295 #endif
1296 
1297     /* Create the Basic Object Manager Types to allow new Object Types */
1298     if (!ObInitSystem()) KeBugCheck(OBJECT_INITIALIZATION_FAILED);
1299 
1300     /* Load basic Security for other Managers */
1301     if (!SeInitSystem()) KeBugCheck(SECURITY_INITIALIZATION_FAILED);
1302 
1303     /* Initialize the Process Manager */
1304     if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS_INITIALIZATION_FAILED);
1305 
1306     /* Initialize the PnP Manager */
1307     if (!PpInitSystem()) KeBugCheck(PP0_INITIALIZATION_FAILED);
1308 
1309     /* Initialize the User-Mode Debugging Subsystem */
1310     DbgkInitialize();
1311 
1312     /* Calculate the tick count multiplier */
1313     ExpTickCountMultiplier = ExComputeTickCountMultiplier(KeMaximumIncrement);
1314     SharedUserData->TickCountMultiplier = ExpTickCountMultiplier;
1315 
1316     /* Set the OS Version */
1317     SharedUserData->NtMajorVersion = NtMajorVersion;
1318     SharedUserData->NtMinorVersion = NtMinorVersion;
1319 
1320     /* Set the machine type */
1321     SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_NATIVE;
1322     SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_NATIVE;
1323 }
1324 
1325 VOID
1326 NTAPI
1327 MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock);
1328 
1329 VOID
1330 NTAPI
1331 INIT_FUNCTION
1332 Phase1InitializationDiscard(IN PVOID Context)
1333 {
1334     PLOADER_PARAMETER_BLOCK LoaderBlock = Context;
1335     NTSTATUS Status, MsgStatus;
1336     TIME_FIELDS TimeFields;
1337     LARGE_INTEGER SystemBootTime, UniversalBootTime, OldTime, Timeout;
1338     BOOLEAN SosEnabled, NoGuiBoot, ResetBias = FALSE, AlternateShell = FALSE;
1339     PLDR_DATA_TABLE_ENTRY NtosEntry;
1340     PMESSAGE_RESOURCE_ENTRY MsgEntry;
1341     PCHAR CommandLine, Y2KHackRequired, SafeBoot, Environment;
1342     PCHAR StringBuffer, EndBuffer, BeginBuffer, MpString = "";
1343     PINIT_BUFFER InitBuffer;
1344     ANSI_STRING TempString;
1345     ULONG LastTzBias, Length, YearHack = 0, Disposition, MessageCode = 0;
1346     SIZE_T Size;
1347     size_t Remaining;
1348     PRTL_USER_PROCESS_INFORMATION ProcessInfo;
1349     KEY_VALUE_PARTIAL_INFORMATION KeyPartialInfo;
1350     UNICODE_STRING KeyName;
1351     OBJECT_ATTRIBUTES ObjectAttributes;
1352     HANDLE KeyHandle, OptionHandle;
1353     PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
1354 
1355     /* Allocate the initialization buffer */
1356     InitBuffer = ExAllocatePoolWithTag(NonPagedPool,
1357                                        sizeof(INIT_BUFFER),
1358                                        TAG_INIT);
1359     if (!InitBuffer)
1360     {
1361         /* Bugcheck */
1362         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 8, 0, 0);
1363     }
1364 
1365     /* Set to phase 1 */
1366     ExpInitializationPhase = 1;
1367 
1368     /* Set us at maximum priority */
1369     KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
1370 
1371     /* Do Phase 1 HAL Initialization */
1372     if (!HalInitSystem(1, LoaderBlock)) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1373 
1374     /* Get the command line and upcase it */
1375     CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL);
1376 
1377     /* Check if GUI Boot is enabled */
1378     NoGuiBoot = (CommandLine && strstr(CommandLine, "NOGUIBOOT") != NULL);
1379 
1380     /* Get the SOS setting */
1381     SosEnabled = (CommandLine && strstr(CommandLine, "SOS") != NULL);
1382 
1383     /* Setup the boot driver */
1384     InbvEnableBootDriver(!NoGuiBoot);
1385     InbvDriverInitialize(LoaderBlock, IDB_MAX_RESOURCE);
1386 
1387     /* Check if GUI boot is enabled */
1388     if (!NoGuiBoot)
1389     {
1390         /* It is, display the boot logo and enable printing strings */
1391         InbvEnableDisplayString(SosEnabled);
1392         DisplayBootBitmap(SosEnabled);
1393     }
1394     else
1395     {
1396         /* Release display ownership if not using GUI boot */
1397         InbvNotifyDisplayOwnershipLost(NULL);
1398 
1399         /* Don't allow boot-time strings */
1400         InbvEnableDisplayString(FALSE);
1401     }
1402 
1403     /* Check if this is LiveCD (WinPE) mode */
1404     if (CommandLine && strstr(CommandLine, "MININT") != NULL)
1405     {
1406         /* Setup WinPE Settings */
1407         InitIsWinPEMode = TRUE;
1408         InitWinPEModeType |= (strstr(CommandLine, "INRAM") != NULL) ? 0x80000000 : 0x00000001;
1409     }
1410 
1411     /* Get the kernel's load entry */
1412     NtosEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
1413                                   LDR_DATA_TABLE_ENTRY,
1414                                   InLoadOrderLinks);
1415 
1416     /* Find the banner message */
1417     MsgStatus = RtlFindMessage(NtosEntry->DllBase,
1418                                11,
1419                                0,
1420                                WINDOWS_NT_BANNER,
1421                                &MsgEntry);
1422 
1423     /* Setup defaults and check if we have a version string */
1424     StringBuffer = InitBuffer->VersionBuffer;
1425     BeginBuffer = StringBuffer;
1426     EndBuffer = StringBuffer;
1427     Remaining = sizeof(InitBuffer->VersionBuffer);
1428     if (CmCSDVersionString.Length)
1429     {
1430         /* Print the version string */
1431         Status = RtlStringCbPrintfExA(StringBuffer,
1432                                       Remaining,
1433                                       &EndBuffer,
1434                                       &Remaining,
1435                                       0,
1436                                       ": %wZ",
1437                                       &CmCSDVersionString);
1438         if (!NT_SUCCESS(Status))
1439         {
1440             /* Bugcheck */
1441             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1442         }
1443     }
1444     else
1445     {
1446         /* No version */
1447         *EndBuffer = ANSI_NULL; /* Null-terminate the string */
1448     }
1449 
1450     /* Skip over the null-terminator to start a new string */
1451     ++EndBuffer;
1452     --Remaining;
1453 
1454     /* Build the version number */
1455     StringBuffer = InitBuffer->VersionNumber;
1456     Status = RtlStringCbPrintfA(StringBuffer,
1457                                 sizeof(InitBuffer->VersionNumber),
1458                                 "%u.%u",
1459                                 VER_PRODUCTMAJORVERSION,
1460                                 VER_PRODUCTMINORVERSION);
1461     if (!NT_SUCCESS(Status))
1462     {
1463         /* Bugcheck */
1464         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1465     }
1466 
1467     /* Check if we had found a banner message */
1468     if (NT_SUCCESS(MsgStatus))
1469     {
1470         /* Create the banner message */
1471         /* ReactOS specific: Report ReactOS version, NtBuildLab information and reported NT kernel version */
1472         Status = RtlStringCbPrintfA(EndBuffer,
1473                                     Remaining,
1474                                     (PCHAR)MsgEntry->Text,
1475                                     KERNEL_VERSION_STR,
1476                                     NtBuildLab,
1477                                     StringBuffer,
1478                                     NtBuildNumber & 0xFFFF,
1479                                     BeginBuffer);
1480         if (!NT_SUCCESS(Status))
1481         {
1482             /* Bugcheck */
1483             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1484         }
1485     }
1486     else
1487     {
1488         /* Use hard-coded banner message */
1489         Status = RtlStringCbCopyA(EndBuffer, Remaining, "REACTOS (R)\r\n");
1490         if (!NT_SUCCESS(Status))
1491         {
1492             /* Bugcheck */
1493             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 7, 0, 0);
1494         }
1495     }
1496 
1497     /* Display the version string on-screen */
1498     InbvDisplayString(EndBuffer);
1499 
1500     /* Initialize Power Subsystem in Phase 0 */
1501     if (!PoInitSystem(0)) KeBugCheck(INTERNAL_POWER_ERROR);
1502 
1503     /* Check for Y2K hack */
1504     Y2KHackRequired = CommandLine ? strstr(CommandLine, "YEAR") : NULL;
1505     if (Y2KHackRequired) Y2KHackRequired = strstr(Y2KHackRequired, "=");
1506     if (Y2KHackRequired) YearHack = atol(Y2KHackRequired + 1);
1507 
1508     /* Query the clock */
1509     if ((ExCmosClockIsSane) && (HalQueryRealTimeClock(&TimeFields)))
1510     {
1511         /* Check if we're using the Y2K hack */
1512         if (Y2KHackRequired) TimeFields.Year = (CSHORT)YearHack;
1513 
1514         /* Convert to time fields */
1515         RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
1516         UniversalBootTime = SystemBootTime;
1517 
1518         /* Check if real time is GMT */
1519         if (!ExpRealTimeIsUniversal)
1520         {
1521             /* Check if we don't have a valid bias */
1522             if (ExpLastTimeZoneBias == MAXULONG)
1523             {
1524                 /* Reset */
1525                 ResetBias = TRUE;
1526                 ExpLastTimeZoneBias = ExpAltTimeZoneBias;
1527             }
1528 
1529             /* Calculate the bias in seconds */
1530             ExpTimeZoneBias.QuadPart = Int32x32To64(ExpLastTimeZoneBias * 60,
1531                                                     10000000);
1532 
1533             /* Set the boot time-zone bias */
1534             SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
1535             SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
1536             SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
1537 
1538             /* Convert the boot time to local time, and set it */
1539             UniversalBootTime.QuadPart = SystemBootTime.QuadPart +
1540                                          ExpTimeZoneBias.QuadPart;
1541         }
1542 
1543         /* Update the system time */
1544         KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
1545 
1546         /* Do system callback */
1547         PoNotifySystemTimeSet();
1548 
1549         /* Remember this as the boot time */
1550         KeBootTime = UniversalBootTime;
1551         KeBootTimeBias = 0;
1552     }
1553 
1554     /* Initialize all processors */
1555     if (!HalAllProcessorsStarted()) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1556 
1557 #ifdef CONFIG_SMP
1558     /* HACK: We should use RtlFindMessage and not only fallback to this */
1559     MpString = "MultiProcessor Kernel\r\n";
1560 #endif
1561 
1562     /* Setup the "MP" String */
1563     RtlInitAnsiString(&TempString, MpString);
1564 
1565     /* Make sure to remove the \r\n if we actually have a string */
1566     while ((TempString.Length > 0) &&
1567            ((TempString.Buffer[TempString.Length - 1] == '\r') ||
1568             (TempString.Buffer[TempString.Length - 1] == '\n')))
1569     {
1570         /* Skip the trailing character */
1571         TempString.Length--;
1572     }
1573 
1574     /* Get the information string from our resource file */
1575     MsgStatus = RtlFindMessage(NtosEntry->DllBase,
1576                                11,
1577                                0,
1578                                KeNumberProcessors > 1 ?
1579                                WINDOWS_NT_INFO_STRING_PLURAL :
1580                                WINDOWS_NT_INFO_STRING,
1581                                &MsgEntry);
1582 
1583     /* Get total RAM size */
1584     Size = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
1585 
1586     /* Create the string */
1587     StringBuffer = InitBuffer->VersionBuffer;
1588     Status = RtlStringCbPrintfA(StringBuffer,
1589                                 sizeof(InitBuffer->VersionBuffer),
1590                                 NT_SUCCESS(MsgStatus) ?
1591                                 (PCHAR)MsgEntry->Text :
1592                                 "%u System Processor [%u MB Memory] %Z\r\n",
1593                                 KeNumberProcessors,
1594                                 Size,
1595                                 &TempString);
1596     if (!NT_SUCCESS(Status))
1597     {
1598         /* Bugcheck */
1599         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 4, 0, 0);
1600     }
1601 
1602     /* Display RAM and CPU count */
1603     InbvDisplayString(StringBuffer);
1604 
1605     /* Update the progress bar */
1606     InbvUpdateProgressBar(5);
1607 
1608     /* Call OB initialization again */
1609     if (!ObInitSystem()) KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
1610 
1611     /* Initialize Basic System Objects and Worker Threads */
1612     if (!ExInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 1, 0);
1613 
1614     /* Initialize the later stages of the kernel */
1615     if (!KeInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 2, 0);
1616 
1617     /* Call KD Providers at Phase 1 */
1618     if (!KdInitSystem(ExpInitializationPhase, KeLoaderBlock))
1619     {
1620         /* Failed, bugcheck */
1621         KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 3, 0);
1622     }
1623 
1624     /* Initialize the SRM in Phase 1 */
1625     if (!SeInitSystem()) KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
1626 
1627     /* Update the progress bar */
1628     InbvUpdateProgressBar(10);
1629 
1630     /* Create SystemRoot Link */
1631     Status = ExpCreateSystemRootLink(LoaderBlock);
1632     if (!NT_SUCCESS(Status))
1633     {
1634         /* Failed to create the system root link */
1635         KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 0, 0, 0);
1636     }
1637 
1638     /* Set up Region Maps, Sections and the Paging File */
1639     if (!MmInitSystem(1, LoaderBlock)) KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
1640 
1641     /* Create NLS section */
1642     ExpInitNls(LoaderBlock);
1643 
1644     /* Initialize Cache Views */
1645     if (!CcInitializeCacheManager()) KeBugCheck(CACHE_INITIALIZATION_FAILED);
1646 
1647     /* Initialize the Registry */
1648     if (!CmInitSystem1()) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
1649 
1650     /* Initialize Prefetcher */
1651     CcPfInitializePrefetcher();
1652 
1653     /* Update progress bar */
1654     InbvUpdateProgressBar(15);
1655 
1656     /* Update timezone information */
1657     LastTzBias = ExpLastTimeZoneBias;
1658     ExRefreshTimeZoneInformation(&SystemBootTime);
1659 
1660     /* Check if we're resetting timezone data */
1661     if (ResetBias)
1662     {
1663         /* Convert the local time to system time */
1664         ExLocalTimeToSystemTime(&SystemBootTime, &UniversalBootTime);
1665         KeBootTime = UniversalBootTime;
1666         KeBootTimeBias = 0;
1667 
1668         /* Set the new time */
1669         KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
1670     }
1671     else
1672     {
1673         /* Check if the timezone switched and update the time */
1674         if (LastTzBias != ExpLastTimeZoneBias) ZwSetSystemTime(NULL, NULL);
1675     }
1676 
1677     /* Initialize the File System Runtime Library */
1678     if (!FsRtlInitSystem()) KeBugCheck(FILE_INITIALIZATION_FAILED);
1679 
1680     /* Initialize range lists */
1681     RtlInitializeRangeListPackage();
1682 
1683     /* Report all resources used by HAL */
1684     HalReportResourceUsage();
1685 
1686     /* Call the debugger DLL */
1687     KdDebuggerInitialize1(LoaderBlock);
1688 
1689     /* Setup PnP Manager in phase 1 */
1690     if (!PpInitSystem()) KeBugCheck(PP1_INITIALIZATION_FAILED);
1691 
1692     /* Update progress bar */
1693     InbvUpdateProgressBar(20);
1694 
1695     /* Initialize LPC */
1696     if (!LpcInitSystem()) KeBugCheck(LPC_INITIALIZATION_FAILED);
1697 
1698     /* Make sure we have a command line */
1699     if (CommandLine)
1700     {
1701         /* Check if this is a safe mode boot */
1702         SafeBoot = strstr(CommandLine, "SAFEBOOT:");
1703         if (SafeBoot)
1704         {
1705             /* Check what kind of boot this is */
1706             SafeBoot += 9;
1707             if (!strncmp(SafeBoot, "MINIMAL", 7))
1708             {
1709                 /* Minimal mode */
1710                 InitSafeBootMode = 1;
1711                 SafeBoot += 7;
1712                 MessageCode = BOOTING_IN_SAFEMODE_MINIMAL;
1713             }
1714             else if (!strncmp(SafeBoot, "NETWORK", 7))
1715             {
1716                 /* With Networking */
1717                 InitSafeBootMode = 2;
1718                 SafeBoot += 7;
1719                 MessageCode = BOOTING_IN_SAFEMODE_NETWORK;
1720             }
1721             else if (!strncmp(SafeBoot, "DSREPAIR", 8))
1722             {
1723                 /* Domain Server Repair */
1724                 InitSafeBootMode = 3;
1725                 SafeBoot += 8;
1726                 MessageCode = BOOTING_IN_SAFEMODE_DSREPAIR;
1727 
1728             }
1729             else
1730             {
1731                 /* Invalid */
1732                 InitSafeBootMode = 0;
1733             }
1734 
1735             /* Check if there's any settings left */
1736             if (*SafeBoot)
1737             {
1738                 /* Check if an alternate shell was requested */
1739                 if (!strncmp(SafeBoot, "(ALTERNATESHELL)", 16))
1740                 {
1741                     /* Remember this for later */
1742                     AlternateShell = TRUE;
1743                 }
1744             }
1745 
1746             /* Find the message to print out */
1747             Status = RtlFindMessage(NtosEntry->DllBase,
1748                                     11,
1749                                     0,
1750                                     MessageCode,
1751                                     &MsgEntry);
1752             if (NT_SUCCESS(Status))
1753             {
1754                 /* Display it */
1755                 InbvDisplayString((PCHAR)MsgEntry->Text);
1756             }
1757         }
1758     }
1759 
1760     /* Make sure we have a command line */
1761     if (CommandLine)
1762     {
1763         /* Check if bootlogging is enabled */
1764         if (strstr(CommandLine, "BOOTLOG"))
1765         {
1766             /* Find the message to print out */
1767             Status = RtlFindMessage(NtosEntry->DllBase,
1768                                     11,
1769                                     0,
1770                                     BOOTLOG_ENABLED,
1771                                     &MsgEntry);
1772             if (NT_SUCCESS(Status))
1773             {
1774                 /* Display it */
1775                 InbvDisplayString((PCHAR)MsgEntry->Text);
1776             }
1777 
1778             /* Setup boot logging */
1779             //IopInitializeBootLogging(LoaderBlock, InitBuffer->BootlogHeader);
1780         }
1781     }
1782 
1783     /* Setup the Executive in Phase 2 */
1784     //ExInitSystemPhase2();
1785 
1786     /* Update progress bar */
1787     InbvUpdateProgressBar(25);
1788 
1789 #ifdef _WINKD_
1790     /* No KD Time Slip is pending */
1791     KdpTimeSlipPending = 0;
1792 #endif
1793 
1794     /* Initialize in-place execution support */
1795     XIPInit(LoaderBlock);
1796 
1797     /* Set maximum update to 75% */
1798     InbvSetProgressBarSubset(25, 75);
1799 
1800     /* Initialize the I/O Subsystem */
1801     if (!IoInitSystem(LoaderBlock)) KeBugCheck(IO1_INITIALIZATION_FAILED);
1802 
1803     /* Set maximum update to 100% */
1804     InbvSetProgressBarSubset(0, 100);
1805 
1806     /* Are we in safe mode? */
1807     if (InitSafeBootMode)
1808     {
1809         /* Open the safe boot key */
1810         RtlInitUnicodeString(&KeyName,
1811                              L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"
1812                              L"\\CONTROL\\SAFEBOOT");
1813         InitializeObjectAttributes(&ObjectAttributes,
1814                                    &KeyName,
1815                                    OBJ_CASE_INSENSITIVE,
1816                                    NULL,
1817                                    NULL);
1818         Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
1819         if (NT_SUCCESS(Status))
1820         {
1821             /* First check if we have an alternate shell */
1822             if (AlternateShell)
1823             {
1824                 /* Make sure that the registry has one setup */
1825                 RtlInitUnicodeString(&KeyName, L"AlternateShell");
1826                 Status = NtQueryValueKey(KeyHandle,
1827                                          &KeyName,
1828                                          KeyValuePartialInformation,
1829                                          &KeyPartialInfo,
1830                                          sizeof(KeyPartialInfo),
1831                                          &Length);
1832                 if (!(NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW))
1833                 {
1834                     AlternateShell = FALSE;
1835                 }
1836             }
1837 
1838             /* Create the option key */
1839             RtlInitUnicodeString(&KeyName, L"Option");
1840             InitializeObjectAttributes(&ObjectAttributes,
1841                                        &KeyName,
1842                                        OBJ_CASE_INSENSITIVE,
1843                                        KeyHandle,
1844                                        NULL);
1845             Status = ZwCreateKey(&OptionHandle,
1846                                  KEY_ALL_ACCESS,
1847                                  &ObjectAttributes,
1848                                  0,
1849                                  NULL,
1850                                  REG_OPTION_VOLATILE,
1851                                  &Disposition);
1852             NtClose(KeyHandle);
1853 
1854             /* Check if the key create worked */
1855             if (NT_SUCCESS(Status))
1856             {
1857                 /* Write the safe boot type */
1858                 RtlInitUnicodeString(&KeyName, L"OptionValue");
1859                 NtSetValueKey(OptionHandle,
1860                               &KeyName,
1861                               0,
1862                               REG_DWORD,
1863                               &InitSafeBootMode,
1864                               sizeof(InitSafeBootMode));
1865 
1866                 /* Check if we have to use an alternate shell */
1867                 if (AlternateShell)
1868                 {
1869                     /* Remember this for later */
1870                     Disposition = TRUE;
1871                     RtlInitUnicodeString(&KeyName, L"UseAlternateShell");
1872                     NtSetValueKey(OptionHandle,
1873                                   &KeyName,
1874                                   0,
1875                                   REG_DWORD,
1876                                   &Disposition,
1877                                   sizeof(Disposition));
1878                 }
1879 
1880                 /* Close the options key handle */
1881                 NtClose(OptionHandle);
1882             }
1883         }
1884     }
1885 
1886     /* Are we in Win PE mode? */
1887     if (InitIsWinPEMode)
1888     {
1889         /* Open the safe control key */
1890         RtlInitUnicodeString(&KeyName,
1891                              L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"
1892                              L"\\CONTROL");
1893         InitializeObjectAttributes(&ObjectAttributes,
1894                                    &KeyName,
1895                                    OBJ_CASE_INSENSITIVE,
1896                                    NULL,
1897                                    NULL);
1898         Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
1899         if (!NT_SUCCESS(Status))
1900         {
1901             /* Bugcheck */
1902             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 6, 0, 0);
1903         }
1904 
1905         /* Create the MiniNT key */
1906         RtlInitUnicodeString(&KeyName, L"MiniNT");
1907         InitializeObjectAttributes(&ObjectAttributes,
1908                                    &KeyName,
1909                                    OBJ_CASE_INSENSITIVE,
1910                                    KeyHandle,
1911                                    NULL);
1912         Status = ZwCreateKey(&OptionHandle,
1913                              KEY_ALL_ACCESS,
1914                              &ObjectAttributes,
1915                              0,
1916                              NULL,
1917                              REG_OPTION_VOLATILE,
1918                              &Disposition);
1919         if (!NT_SUCCESS(Status))
1920         {
1921             /* Bugcheck */
1922             KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 6, 0, 0);
1923         }
1924 
1925         /* Close the handles */
1926         NtClose(KeyHandle);
1927         NtClose(OptionHandle);
1928     }
1929 
1930     /* FIXME: This doesn't do anything for now */
1931     MmArmInitSystem(2, LoaderBlock);
1932 
1933     /* Update progress bar */
1934     InbvUpdateProgressBar(80);
1935 
1936     /* Initialize VDM support */
1937 #if defined(_M_IX86)
1938     KeI386VdmInitialize();
1939 #endif
1940 
1941     /* Initialize Power Subsystem in Phase 1*/
1942     if (!PoInitSystem(1)) KeBugCheck(INTERNAL_POWER_ERROR);
1943 
1944     /* Update progress bar */
1945     InbvUpdateProgressBar(90);
1946 
1947     /* Initialize the Process Manager at Phase 1 */
1948     if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
1949 
1950     /* Make sure nobody touches the loader block again */
1951     if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
1952     MmFreeLoaderBlock(LoaderBlock);
1953     LoaderBlock = Context = NULL;
1954 
1955     /* Initialize the SRM in phase 1 */
1956     if (!SeRmInitPhase1()) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
1957 
1958     /* Update progress bar */
1959     InbvUpdateProgressBar(100);
1960 
1961     /* Clear the screen */
1962     if (InbvBootDriverInstalled) FinalizeBootLogo();
1963 
1964     /* Allow strings to be displayed */
1965     InbvEnableDisplayString(TRUE);
1966 
1967     /* Launch initial process */
1968     DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed);
1969     ProcessInfo = &InitBuffer->ProcessInfo;
1970     ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
1971 
1972     /* Wait 5 seconds for initial process to initialize */
1973     Timeout.QuadPart = Int32x32To64(5, -10000000);
1974     Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
1975     if (Status == STATUS_SUCCESS)
1976     {
1977         /* Failed, display error */
1978         DPRINT1("INIT: Session Manager terminated.\n");
1979 
1980         /* Bugcheck the system if SMSS couldn't initialize */
1981         KeBugCheck(SESSION5_INITIALIZATION_FAILED);
1982     }
1983 
1984     /* Close process handles */
1985     ZwClose(ProcessInfo->ThreadHandle);
1986     ZwClose(ProcessInfo->ProcessHandle);
1987 
1988     /* Free the initial process environment */
1989     Size = 0;
1990     ZwFreeVirtualMemory(NtCurrentProcess(),
1991                         (PVOID*)&Environment,
1992                         &Size,
1993                         MEM_RELEASE);
1994 
1995     /* Free the initial process parameters */
1996     Size = 0;
1997     ZwFreeVirtualMemory(NtCurrentProcess(),
1998                         (PVOID*)&ProcessParameters,
1999                         &Size,
2000                         MEM_RELEASE);
2001 
2002     /* Increase init phase */
2003     ExpInitializationPhase++;
2004 
2005     /* Free the boot buffer */
2006     ExFreePoolWithTag(InitBuffer, TAG_INIT);
2007     DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed);
2008 }
2009 
2010 VOID
2011 NTAPI
2012 Phase1Initialization(IN PVOID Context)
2013 {
2014     /* Do the .INIT part of Phase 1 which we can free later */
2015     Phase1InitializationDiscard(Context);
2016 
2017     /* Jump into zero page thread */
2018     MmZeroPageThread();
2019 }
2020