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