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