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