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