- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ex / init.c
index a4a06d7..268c21c 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ex/init.c
- * PURPOSE:         Executive initalization
- *
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) - Added ExpInitializeExecutive
- *                                                    and optimized/cleaned it.
- *                  Eric Kohl (ekohl@abo.rhein-zeitung.de)
+ * PURPOSE:         Executive Initialization Code
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Eric Kohl (ekohl@rz-online.de)
  */
 
+/* INCLUDES ******************************************************************/
+
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
+//#include <ntoskrnl/cm/newcm.h>
+#include "ntoskrnl/cm/cm.h"
+#include <ntverp.h>
 
 /* DATA **********************************************************************/
 
-extern ULONG MmCoreDumpType;
-extern CHAR KiTimerSystemAuditing;
-extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
-extern ADDRESS_RANGE KeMemoryMap[64];
-extern ULONG KeMemoryMapRangeCount;
-extern ULONG_PTR FirstKrnlPhysAddr;
-extern ULONG_PTR LastKrnlPhysAddr;
-extern ULONG_PTR LastKernelAddress;
-extern LOADER_MODULE KeLoaderModules[64];
-extern PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
-extern LIST_ENTRY KiProfileListHead;
-extern LIST_ENTRY KiProfileSourceListHead;
-extern KSPIN_LOCK KiProfileLock;
-BOOLEAN SetupMode = TRUE;
-
-VOID PspPostInitSystemProcess(VOID);
-
-static VOID INIT_FUNCTION InitSystemSharedUserPage (PCSZ ParameterLine);
-VOID INIT_FUNCTION ExpDisplayNotice(VOID);
-INIT_FUNCTION NTSTATUS ExpLoadInitialProcess(PHANDLE ProcessHandle, PHANDLE ThreadHandle);
-
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, InitSystemSharedUserPage)
-#pragma alloc_text(INIT, ExpDisplayNotice)
-#pragma alloc_text(INIT, ExpLoadInitialProcess)
-#pragma alloc_text(INIT, ExpInitializeExecutive)
-#pragma alloc_text(INIT, ExInit2)
+/* NT Version Info */
+ULONG NtMajorVersion = VER_PRODUCTMAJORVERSION;
+ULONG NtMinorVersion = VER_PRODUCTMINORVERSION;
+#if DBG
+ULONG NtBuildNumber = VER_PRODUCTBUILD | 0xC0000000;
+#else
+ULONG NtBuildNumber = VER_PRODUCTBUILD;
 #endif
 
+/* NT System Info */
+ULONG NtGlobalFlag;
+ULONG ExSuiteMask;
+
+/* Cm Version Info */
+ULONG CmNtSpBuildNumber;
+ULONG CmNtCSDVersion;
+ULONG CmNtCSDReleaseType;
+UNICODE_STRING CmVersionString;
+UNICODE_STRING CmCSDVersionString;
+CHAR NtBuildLab[] = KERNEL_VERSION_BUILD_STR;
+
+/* Init flags and settings */
+ULONG ExpInitializationPhase;
+BOOLEAN ExpInTextModeSetup;
+BOOLEAN IoRemoteBootClient;
+ULONG InitSafeBootMode;
+BOOLEAN InitIsWinPEMode, InitWinPEModeType;
+
+/* NT Boot Path */
+UNICODE_STRING NtSystemRoot;
+
+/* NT Initial User Application */
+WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
+ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) -
+                                         sizeof(WCHAR);
+ULONG NtInitialUserProcessBufferType = REG_SZ;
+
+/* Boot NLS information */
+PVOID ExpNlsTableBase;
+ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
+ULONG ExpUnicodeCaseTableDataOffset;
+NLSTABLEINFO ExpNlsTableInfo;
+ULONG ExpNlsTableSize;
+PVOID ExpNlsSectionPointer;
+
+/* CMOS Timer Sanity */
+BOOLEAN ExCmosClockIsSane = TRUE;
+
 /* FUNCTIONS ****************************************************************/
 
-static
-VOID
-INIT_FUNCTION
-InitSystemSharedUserPage (PCSZ ParameterLine)
+NTSTATUS
+NTAPI
+ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    UNICODE_STRING ArcDeviceName;
-    UNICODE_STRING ArcName;
-    UNICODE_STRING BootPath;
-    UNICODE_STRING DriveDeviceName;
-    UNICODE_STRING DriveName;
-    WCHAR DriveNameBuffer[20];
-    PCHAR ParamBuffer;
-    PWCHAR ArcNameBuffer;
-    PCHAR p;
-    NTSTATUS Status;
-    ULONG Length;
+    UNICODE_STRING LinkName;
     OBJECT_ATTRIBUTES ObjectAttributes;
-    HANDLE Handle;
-    ULONG i;
-    BOOLEAN BootDriveFound = FALSE;
-
-   /*
-    * NOTE:
-    *   The shared user page has been zeroed-out right after creation.
-    *   There is NO need to do this again.
-    */
-    Ki386SetProcessorFeatures();
-
-    /* Set the Version Data */
-    SharedUserData->NtProductType = NtProductWinNt;
-    SharedUserData->ProductTypeIsValid = TRUE;
-    SharedUserData->NtMajorVersion = 5;
-    SharedUserData->NtMinorVersion = 0;
-
-    /*
-     * Retrieve the current dos system path
-     * (e.g.: C:\reactos) from the given arc path
-     * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
-     * Format: "<arc_name>\<path> [options...]"
-     */
-
-    /* Create local parameter line copy */
-    ParamBuffer = ExAllocatePool(PagedPool, 256);
-    strcpy (ParamBuffer, (const char *)ParameterLine);
-    DPRINT("%s\n", ParamBuffer);
-
-    /* Cut options off */
-    p = strchr (ParamBuffer, ' ');
-    if (p) *p = 0;
-    DPRINT("%s\n", ParamBuffer);
-
-    /* Extract path */
-    p = strchr (ParamBuffer, '\\');
-    if (p) {
-
-        DPRINT("Boot path: %s\n", p);
-        RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
-        *p = 0;
-
-    } else {
-
-        DPRINT("Boot path: %s\n", "\\");
-        RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
-    }
-    DPRINT("Arc name: %s\n", ParamBuffer);
-
-    /* Only ARC Name left - Build full ARC Name */
-    ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
-    swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer);
-    RtlInitUnicodeString (&ArcName, ArcNameBuffer);
-    DPRINT("Arc name: %wZ\n", &ArcName);
-
-    /* Free ParamBuffer */
-    ExFreePool (ParamBuffer);
-
-    /* Allocate ARC Device Name string */
-    ArcDeviceName.Length = 0;
-    ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
-    ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
-
-    /* Open the Symbolic Link */
+    HANDLE LinkHandle;
+    NTSTATUS Status;
+    ANSI_STRING AnsiName;
+    CHAR Buffer[256];
+    ANSI_STRING TargetString;
+    UNICODE_STRING TargetName;
+
+    /* Initialize the ArcName tree */
+    RtlInitUnicodeString(&LinkName, L"\\ArcName");
     InitializeObjectAttributes(&ObjectAttributes,
-                               &ArcName,
-                               OBJ_OPENLINK,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
                                NULL,
-                               NULL);
-    Status = NtOpenSymbolicLinkObject(&Handle,
-                                      SYMBOLIC_LINK_ALL_ACCESS,
-                                      &ObjectAttributes);
-
-    /* Free the String */
-    ExFreePool(ArcName.Buffer);
-
-    /* Check for Success */
-    if (!NT_SUCCESS(Status)) {
-
-        /* Free the Strings */
-        RtlFreeUnicodeString(&BootPath);
-        ExFreePool(ArcDeviceName.Buffer);
-        CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n", Status);
-        KEBUGCHECK(0);
-    }
-
-    /* Query the Link */
-    Status = NtQuerySymbolicLinkObject(Handle,
-                                       &ArcDeviceName,
-                                       &Length);
-    NtClose (Handle);
-
-    /* Check for Success */
-    if (!NT_SUCCESS(Status)) {
-
-        /* Free the Strings */
-        RtlFreeUnicodeString(&BootPath);
-        ExFreePool(ArcDeviceName.Buffer);
-        CPRINT("NtQuerySymbolicLinkObject() failed (Status %x)\n", Status);
-        KEBUGCHECK(0);
-    }
-    DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
-
-    /* Allocate Device Name string */
-    DriveDeviceName.Length = 0;
-    DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
-    DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
-
-    /* Loop Drives */
-    for (i = 0; i < 26; i++)  {
-
-        /* Setup the String */
-        swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
-        RtlInitUnicodeString(&DriveName,
-                             DriveNameBuffer);
-
-        /* Open the Symbolic Link */
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &DriveName,
-                                   OBJ_OPENLINK,
-                                   NULL,
-                                   NULL);
-        Status = NtOpenSymbolicLinkObject(&Handle,
-                                          SYMBOLIC_LINK_ALL_ACCESS,
-                                          &ObjectAttributes);
-
-        /* If it failed, skip to the next drive */
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to open link %wZ\n", &DriveName);
-            continue;
-        }
+                               SePublicDefaultUnrestrictedSd);
 
-        /* Query it */
-        Status = NtQuerySymbolicLinkObject(Handle,
-                                           &DriveDeviceName,
-                                           &Length);
+    /* Create it */
+    Status = NtCreateDirectoryObject(&LinkHandle,
+                                     DIRECTORY_ALL_ACCESS,
+                                     &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 1, 0, 0);
+    }
 
-        /* If it failed, skip to the next drive */
-        if (!NT_SUCCESS(Status)) {
-            DPRINT("Failed to query link %wZ\n", &DriveName);
-            continue;
-        }
-        DPRINT("Opened link: %wZ ==> %wZ\n", &DriveName, &DriveDeviceName);
+    /* Close the LinkHandle */
+    NtClose(LinkHandle);
 
-        /* See if we've found the boot drive */
-        if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE)) {
+    /* Initialize the Device tree */
+    RtlInitUnicodeString(&LinkName, L"\\Device");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+                               NULL,
+                               SePublicDefaultUnrestrictedSd);
 
-            DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
-            swprintf(SharedUserData->NtSystemRoot, L"%C:%wZ", 'A' + i, &BootPath);
-            BootDriveFound = TRUE;
-        }
+    /* Create it */
+    Status = NtCreateDirectoryObject(&LinkHandle,
+                                     DIRECTORY_ALL_ACCESS,
+                                     &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 2, 0, 0);
+    }
+
+    /* Close the LinkHandle */
+    ObCloseHandle(LinkHandle, KernelMode);
+
+    /* Create the system root symlink name */
+    RtlInitAnsiString(&AnsiName, "\\SystemRoot");
+    Status = RtlAnsiStringToUnicodeString(&LinkName, &AnsiName, TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 3, 0, 0);
+    }
 
-        /* Close this Link */
-        NtClose (Handle);
+    /* Initialize the attributes for the link */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+                               NULL,
+                               SePublicDefaultUnrestrictedSd);
+
+    /* Build the ARC name */
+    sprintf(Buffer,
+            "\\ArcName\\%s%s",
+            LoaderBlock->ArcBootDeviceName,
+            LoaderBlock->NtBootPathName);
+    Buffer[strlen(Buffer) - 1] = ANSI_NULL;
+
+    /* Convert it to Unicode */
+    RtlInitString(&TargetString, Buffer);
+    Status = RtlAnsiStringToUnicodeString(&TargetName,
+                                          &TargetString,
+                                          TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* We failed, bugcheck */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 4, 0, 0);
     }
 
-    /* Free all the Strings we have in memory */
-    RtlFreeUnicodeString (&BootPath);
-    ExFreePool(DriveDeviceName.Buffer);
-    ExFreePool(ArcDeviceName.Buffer);
+    /* Create it */
+    Status = NtCreateSymbolicLinkObject(&LinkHandle,
+                                        SYMBOLIC_LINK_ALL_ACCESS,
+                                        &ObjectAttributes,
+                                        &TargetName);
 
-    /* Make sure we found the Boot Drive */
-    if (BootDriveFound == FALSE) {
+    /* Free the strings */
+    RtlFreeUnicodeString(&LinkName);
+    RtlFreeUnicodeString(&TargetName);
 
-        DbgPrint("No system drive found!\n");
-        KEBUGCHECK (NO_BOOT_DEVICE);
+    /* Check if creating the link failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 5, 0, 0);
     }
-}
 
-__inline
-VOID
-STDCALL
-ExecuteRuntimeAsserts(VOID)
-{
-    /*
-     * Fail at runtime if someone has changed various structures without
-     * updating the offsets used for the assembler code.
-     */
-    ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCall) == 0x300);
-    ASSERT(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
-    ASSERT(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
-    ASSERT(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
-    ASSERT(FIELD_OFFSET(KTHREAD, NpxState) == KTHREAD_NPX_STATE);
-    ASSERT(FIELD_OFFSET(KTHREAD, ServiceTable) == KTHREAD_SERVICE_TABLE);
-    ASSERT(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
-    ASSERT(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
-    ASSERT(FIELD_OFFSET(KTHREAD, CallbackStack) == KTHREAD_CALLBACK_STACK);
-    ASSERT(FIELD_OFFSET(KTHREAD, ApcState.Process) == KTHREAD_APCSTATE_PROCESS);
-    ASSERT(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == KPROCESS_DIRECTORY_TABLE_BASE);
-    ASSERT(FIELD_OFFSET(KPROCESS, IopmOffset) == KPROCESS_IOPM_OFFSET);
-    ASSERT(FIELD_OFFSET(KPROCESS, LdtDescriptor) == KPROCESS_LDT_DESCRIPTOR0);
-    ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, SavedExceptionStack) == TF_SAVED_EXCEPTION_STACK);
-    ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
-    ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
-    ASSERT(FIELD_OFFSET(KPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST);
-    ASSERT(FIELD_OFFSET(KPCR, Self) == KPCR_SELF);
-    ASSERT(FIELD_OFFSET(KIPCR, PrcbData) + FIELD_OFFSET(KPRCB, CurrentThread) == KPCR_CURRENT_THREAD);
-    ASSERT(FIELD_OFFSET(KIPCR, PrcbData) + FIELD_OFFSET(KPRCB, NpxThread) == KPCR_NPX_THREAD);
-    ASSERT(FIELD_OFFSET(KTSS, Esp0) == KTSS_ESP0);
-    ASSERT(FIELD_OFFSET(KTSS, IoMapBase) == KTSS_IOMAPBASE);
-    ASSERT(sizeof(FX_SAVE_AREA) == SIZEOF_FX_SAVE_AREA);
+    /* Close the handle and return success */
+    ObCloseHandle(LinkHandle, KernelMode);
+    return STATUS_SUCCESS;
 }
 
-__inline
 VOID
-STDCALL
-ParseAndCacheLoadedModules(VOID)
+NTAPI
+ExpInitNls(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    ULONG i;
-    PCHAR Name;
+    LARGE_INTEGER SectionSize;
+    NTSTATUS Status;
+    HANDLE NlsSection;
+    PVOID SectionBase = NULL;
+    ULONG ViewSize = 0;
+    LARGE_INTEGER SectionOffset = {{0}};
+    PLIST_ENTRY ListHead, NextEntry;
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+
+    /* Check if this is boot-time phase 0 initialization */
+    if (!ExpInitializationPhase)
+    {
+        /* Loop the memory descriptors */
+        ListHead = &LoaderBlock->MemoryDescriptorListHead;
+        NextEntry = ListHead->Flink;
+        while (NextEntry != ListHead)
+        {
+            /* Get the current block */
+            MdBlock = CONTAINING_RECORD(NextEntry,
+                                        MEMORY_ALLOCATION_DESCRIPTOR,
+                                        ListEntry);
+
+            /* Check if this is an NLS block */
+            if (MdBlock->MemoryType == LoaderNlsData)
+            {
+                /* Increase the table size */
+                ExpNlsTableSize += MdBlock->PageCount * PAGE_SIZE;
+            }
 
-    /* Loop the Module List and get the modules we want */
-    for (i = 1; i < KeLoaderBlock.ModsCount; i++) {
+            /* Go to the next block */
+            NextEntry = MdBlock->ListEntry.Flink;
+        }
 
-        /* Get the Name of this Module */
-        if (!(Name = strrchr((PCHAR)KeLoaderModules[i].String, '\\'))) {
+        /*
+         * In NT, the memory blocks are contiguous, but in ReactOS they aren't,
+         * so unless someone fixes FreeLdr, we'll have to use this icky hack.
+         */
+        ExpNlsTableSize += 2 * PAGE_SIZE; // BIAS FOR FREELDR. HACK!
+
+        /* Allocate the a new buffer since loader memory will be freed */
+        ExpNlsTableBase = ExAllocatePoolWithTag(NonPagedPool,
+                                                ExpNlsTableSize,
+                                                TAG('R', 't', 'l', 'i'));
+        if (!ExpNlsTableBase) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
+
+        /* Copy the codepage data in its new location. */
+        RtlCopyMemory(ExpNlsTableBase,
+                      LoaderBlock->NlsData->AnsiCodePageData,
+                      ExpNlsTableSize);
+
+        /* Initialize and reset the NLS TAbles */
+        RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
+                                 ExpAnsiCodePageDataOffset),
+                         (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                                 ExpOemCodePageDataOffset),
+                         (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                                 ExpUnicodeCaseTableDataOffset),
+                         &ExpNlsTableInfo);
+        RtlResetRtlTranslations(&ExpNlsTableInfo);
+        return;
+    }
 
-            /* Save the name */
-            Name = (PCHAR)KeLoaderModules[i].String;
+    /* Set the section size */
+    SectionSize.QuadPart = ExpNlsTableSize;
+
+    /* Create the NLS Section */
+    Status = ZwCreateSection(&NlsSection,
+                             SECTION_ALL_ACCESS,
+                             NULL,
+                             &SectionSize,
+                             PAGE_READWRITE,
+                             SEC_COMMIT,
+                             NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 1, 0, 0);
+    }
 
-        } else {
+    /* Get a pointer to the section */
+    Status = ObReferenceObjectByHandle(NlsSection,
+                                       SECTION_ALL_ACCESS,
+                                       MmSectionObjectType,
+                                       KernelMode,
+                                       &ExpNlsSectionPointer,
+                                       NULL);
+    ZwClose(NlsSection);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 2, 0, 0);
+    }
 
-            /* No name, skip */
-            Name++;
-        }
+    /* Map the NLS Section in system space */
+    Status = MmMapViewInSystemSpace(ExpNlsSectionPointer,
+                                    &SectionBase,
+                                    &ExpNlsTableSize);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 3, 0, 0);
+    }
 
-        /* Now check for any of the modules we will need later */
-        if (!_stricmp(Name, "ansi.nls")) {
+    /* Copy the codepage data in its new location. */
+    RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
+
+    /* Free the previously allocated buffer and set the new location */
+    ExFreePool(ExpNlsTableBase);
+    ExpNlsTableBase = SectionBase;
+
+    /* Initialize the NLS Tables */
+    RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpAnsiCodePageDataOffset),
+                     (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpOemCodePageDataOffset),
+                     (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpUnicodeCaseTableDataOffset),
+                     &ExpNlsTableInfo);
+    RtlResetRtlTranslations(&ExpNlsTableInfo);
+
+    /* Reset the base to 0 */
+    SectionBase = NULL;
+
+    /* Map the section in the system process */
+    Status = MmMapViewOfSection(ExpNlsSectionPointer,
+                                PsGetCurrentProcess(),
+                                &SectionBase,
+                                0L,
+                                0L,
+                                &SectionOffset,
+                                &ViewSize,
+                                ViewShare,
+                                0L,
+                                PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 5, 0, 0);
+    }
 
-            CachedModules[AnsiCodepage] = &KeLoaderModules[i];
+    /* Copy the table into the system process and set this as the base */
+    RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
+    ExpNlsTableBase = SectionBase;
+}
 
-        } else if (!_stricmp(Name, "oem.nls")) {
+NTSTATUS
+NTAPI
+ExpLoadInitialProcess(IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation)
+{
+    PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
+    NTSTATUS Status;
+    ULONG Size;
+    PWSTR p;
+    UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
+    UNICODE_STRING SmssName, Environment, SystemDriveString;
+    PVOID EnvironmentPtr = NULL;
+
+    /* Allocate memory for the process parameters */
+    Size = sizeof(RTL_USER_PROCESS_PARAMETERS) +
+           ((MAX_PATH * 6) * sizeof(WCHAR));
+    Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+                                     (PVOID)&ProcessParameters,
+                                     0,
+                                     &Size,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SESSION1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
 
-            CachedModules[OemCodepage] = &KeLoaderModules[i];
+    /* Setup the basic header, and give the process the low 1MB to itself */
+    ProcessParameters->Length = Size;
+    ProcessParameters->MaximumLength = Size;
+    ProcessParameters->Flags = RTL_USER_PROCESS_PARAMETERS_NORMALIZED |
+                               RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
+
+    /* Allocate a page for the environment */
+    Size = PAGE_SIZE;
+    Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+                                     &EnvironmentPtr,
+                                     0,
+                                     &Size,
+                                     MEM_COMMIT,
+                                     PAGE_READWRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SESSION2_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
 
-        } else if (!_stricmp(Name, "casemap.nls")) {
+    /* Write the pointer */
+    ProcessParameters->Environment = EnvironmentPtr;
+
+    /* Make a buffer for the DOS path */
+    p = (PWSTR)(ProcessParameters + 1);
+    ProcessParameters->CurrentDirectory.DosPath.Buffer = p;
+    ProcessParameters->
+        CurrentDirectory.DosPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+    /* Copy the DOS path */
+    RtlCopyUnicodeString(&ProcessParameters->CurrentDirectory.DosPath,
+                         &NtSystemRoot);
+
+    /* Make a buffer for the DLL Path */
+    p = (PWSTR)((PCHAR)ProcessParameters->CurrentDirectory.DosPath.Buffer +
+                ProcessParameters->CurrentDirectory.DosPath.MaximumLength);
+    ProcessParameters->DllPath.Buffer = p;
+    ProcessParameters->DllPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+    /* Copy the DLL path and append the system32 directory */
+    RtlCopyUnicodeString(&ProcessParameters->DllPath,
+                         &ProcessParameters->CurrentDirectory.DosPath);
+    RtlAppendUnicodeToString(&ProcessParameters->DllPath, L"\\System32");
+
+    /* Make a buffer for the image name */
+    p = (PWSTR)((PCHAR)ProcessParameters->DllPath.Buffer +
+                ProcessParameters->DllPath.MaximumLength);
+    ProcessParameters->ImagePathName.Buffer = p;
+    ProcessParameters->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+    /* Make sure the buffer is a valid string which within the given length */
+    if ((NtInitialUserProcessBufferType != REG_SZ) ||
+        ((NtInitialUserProcessBufferLength != -1) &&
+         ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) ||
+          (NtInitialUserProcessBufferLength >
+           sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))))
+    {
+        /* Invalid initial process string, bugcheck */
+        KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,
+                     (ULONG_PTR)STATUS_INVALID_PARAMETER,
+                     NtInitialUserProcessBufferType,
+                     NtInitialUserProcessBufferLength,
+                     sizeof(NtInitialUserProcessBuffer));
+    }
 
-            CachedModules[UnicodeCasemap] = &KeLoaderModules[i];
+    /* Cut out anything after a space */
+    p = NtInitialUserProcessBuffer;
+    while (*p && *p != L' ') p++;
+
+    /* Set the image path length */
+    ProcessParameters->ImagePathName.Length =
+        (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer);
+
+    /* Copy the actual buffer */
+    RtlCopyMemory(ProcessParameters->ImagePathName.Buffer,
+                  NtInitialUserProcessBuffer,
+                  ProcessParameters->ImagePathName.Length);
+
+    /* Null-terminate it */
+    ProcessParameters->
+        ImagePathName.Buffer[ProcessParameters->ImagePathName.Length /
+                             sizeof(WCHAR)] = UNICODE_NULL;
+
+    /* Make a buffer for the command line */
+    p = (PWSTR)((PCHAR)ProcessParameters->ImagePathName.Buffer +
+                ProcessParameters->ImagePathName.MaximumLength);
+    ProcessParameters->CommandLine.Buffer = p;
+    ProcessParameters->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR);
+
+    /* Add the image name to the command line */
+    RtlAppendUnicodeToString(&ProcessParameters->CommandLine,
+                             NtInitialUserProcessBuffer);
+
+    /* Create the environment string */
+    RtlInitEmptyUnicodeString(&Environment,
+                              ProcessParameters->Environment,
+                              (USHORT)Size);
+
+    /* Append the DLL path to it */
+    RtlAppendUnicodeToString(&Environment, L"Path=" );
+    RtlAppendUnicodeStringToString(&Environment, &ProcessParameters->DllPath);
+    RtlAppendUnicodeStringToString(&Environment, &NullString );
+
+    /* Create the system drive string */
+    SystemDriveString = NtSystemRoot;
+    SystemDriveString.Length = 2 * sizeof(WCHAR);
+
+    /* Append it to the environment */
+    RtlAppendUnicodeToString(&Environment, L"SystemDrive=");
+    RtlAppendUnicodeStringToString(&Environment, &SystemDriveString);
+    RtlAppendUnicodeStringToString(&Environment, &NullString);
+
+    /* Append the system root to the environment */
+    RtlAppendUnicodeToString(&Environment, L"SystemRoot=");
+    RtlAppendUnicodeStringToString(&Environment, &NtSystemRoot);
+    RtlAppendUnicodeStringToString(&Environment, &NullString);
+
+    /* Create SMSS process */
+    SmssName = ProcessParameters->ImagePathName;
+    Status = RtlCreateUserProcess(&SmssName,
+                                  OBJ_CASE_INSENSITIVE,
+                                  RtlDeNormalizeProcessParams(
+                                  ProcessParameters),
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  FALSE,
+                                  NULL,
+                                  NULL,
+                                  ProcessInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SESSION3_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
 
-        } else if (!_stricmp(Name, "system") || !_stricmp(Name, "system.hiv")) {
+    /* Resume the thread */
+    Status = ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed */
+        KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
 
-            CachedModules[SystemRegistry] = &KeLoaderModules[i];
-            SetupMode = FALSE;
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+ULONG
+NTAPI
+ExComputeTickCountMultiplier(IN ULONG ClockIncrement)
+{
+    ULONG MsRemainder = 0, MsIncrement;
+    ULONG IncrementRemainder;
+    ULONG i;
 
-        } else if (!_stricmp(Name, "hardware") || !_stricmp(Name, "hardware.hiv")) {
+    /* Count the number of milliseconds for each clock interrupt */
+    MsIncrement = ClockIncrement / (10 * 1000);
 
-            CachedModules[HardwareRegistry] = &KeLoaderModules[i];
+    /* Count the remainder from the division above, with 24-bit precision */
+    IncrementRemainder = ClockIncrement - (MsIncrement * (10 * 1000));
+    for (i= 0; i < 24; i++)
+    {
+        /* Shift the remainders */
+        MsRemainder <<= 1;
+        IncrementRemainder <<= 1;
+
+        /* Check if we've went past 1 ms */
+        if (IncrementRemainder >= (10 * 1000))
+        {
+            /* Increase the remainder by one, and substract from increment */
+            IncrementRemainder -= (10 * 1000);
+            MsRemainder |= 1;
         }
     }
+
+    /* Return the increment */
+    return (MsIncrement << 24) | MsRemainder;
 }
 
-__inline
-VOID
-STDCALL
-ParseCommandLine(PULONG MaxMem,
-                 PBOOLEAN NoGuiBoot,
-                 PBOOLEAN BootLog,
-                 PBOOLEAN ForceAcpiDisable)
+BOOLEAN
+NTAPI
+ExpInitSystemPhase0(VOID)
 {
-    PCHAR p1, p2;
+    /* Initialize EXRESOURCE Support */
+    ExpResourceInitialization();
 
-    p1 = (PCHAR)KeLoaderBlock.CommandLine;
-    while(*p1 && (p2 = strchr(p1, '/'))) {
+    /* Initialize the environment lock */
+    ExInitializeFastMutex(&ExpEnvironmentLock);
 
-        p2++;
-        if (!_strnicmp(p2, "MAXMEM", 6)) {
+    /* Initialize the lookaside lists and locks */
+    ExpInitLookasideLists();
 
-            p2 += 6;
-            while (isspace(*p2)) p2++;
+    /* Initialize the Firmware Table resource and listhead */
+    InitializeListHead(&ExpFirmwareTableProviderListHead);
+    ExInitializeResourceLite(&ExpFirmwareTableResource);
 
-            if (*p2 == '=') {
+    /* Set the suite mask to maximum and return */
+    ExSuiteMask = 0xFFFFFFFF;
+    return TRUE;
+}
 
-                p2++;
+BOOLEAN
+NTAPI
+ExpInitSystemPhase1(VOID)
+{
+    /* Initialize worker threads */
+    ExpInitializeWorkerThreads();
 
-                while(isspace(*p2)) p2++;
+    /* Initialize pushlocks */
+    ExpInitializePushLocks();
 
-                if (isdigit(*p2)) {
-                    while (isdigit(*p2)) {
-                        *MaxMem = *MaxMem * 10 + *p2 - '0';
-                        p2++;
-                    }
-                    break;
-                }
-            }
-        } else if (!_strnicmp(p2, "NOGUIBOOT", 9)) {
+    /* Initialize events and event pairs */
+    ExpInitializeEventImplementation();
+    ExpInitializeEventPairImplementation();
 
-            p2 += 9;
-            *NoGuiBoot = TRUE;
+    /* Initialize callbacks */
+    ExpInitializeCallbacks();
 
-        } else if (!_strnicmp(p2, "CRASHDUMP", 9)) {
+    /* Initialize mutants */
+    ExpInitializeMutantImplementation();
 
-            p2 += 9;
-            if (*p2 == ':') {
+    /* Initialize semaphores */
+    ExpInitializeSemaphoreImplementation();
 
-                p2++;
-                if (!_strnicmp(p2, "FULL", 4)) {
+    /* Initialize timers */
+    ExpInitializeTimerImplementation();
 
-                    MmCoreDumpType = MM_CORE_DUMP_TYPE_FULL;
+    /* Initialize profiling */
+    ExpInitializeProfileImplementation();
 
-                } else {
+    /* Initialize UUIDs */
+    ExpInitUuids();
 
-                    MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE;
-                }
-            }
-        } else if (!_strnicmp(p2, "BOOTLOG", 7)) {
+    /* Initialize Win32K */
+    ExpWin32kInit();
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+ExInitSystem(VOID)
+{
+    /* Check the initialization phase */
+    switch (ExpInitializationPhase)
+    {
+        case 0:
 
-            p2 += 7;
-            *BootLog = TRUE;
-        } else if (!_strnicmp(p2, "NOACPI", 6)) {
+            /* Do Phase 0 */
+            return ExpInitSystemPhase0();
 
-            p2 += 6;
-            *ForceAcpiDisable = TRUE;
-        }
+        case 1:
+
+            /* Do Phase 1 */
+            return ExpInitSystemPhase1();
 
-        p1 = p2;
+        default:
+
+            /* Don't know any other phase! Bugcheck! */
+            KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
+            return FALSE;
     }
 }
-   
+
+BOOLEAN
+NTAPI
+ExpIsLoaderValid(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PLOADER_PARAMETER_EXTENSION Extension;
+
+    /* Get the loader extension */
+    Extension = LoaderBlock->Extension;
+
+    /* Validate the size (larger structures are OK, we'll just ignore them) */
+    if (Extension->Size < sizeof(LOADER_PARAMETER_EXTENSION)) return FALSE;
+
+    /* Don't validate upper versions */
+    if (Extension->MajorVersion > 5) return TRUE;
+
+    /* Fail if this is NT 4 */
+    if (Extension->MajorVersion < 5) return FALSE;
+
+    /* Fail if this is XP */
+    if (Extension->MinorVersion < 2) return FALSE;
+
+    /* This is 2003 or newer, approve it */
+    return TRUE;
+}
+
 VOID
-INIT_FUNCTION
-ExpDisplayNotice(VOID)
+NTAPI
+ExpLoadBootSymbols(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    CHAR str[50];
-   
-    if (SetupMode)
-    {
-        HalDisplayString(
-        "\n\n\n     ReactOS " KERNEL_VERSION_STR " Setup \n");
-        HalDisplayString(
-        "    \xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD");
-        HalDisplayString(
-        "\xCD\xCD\n");
-        return;
+    ULONG i = 0;
+    PLIST_ENTRY NextEntry;
+    ULONG Count, Length;
+    PWCHAR Name;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    BOOLEAN OverFlow = FALSE;
+    CHAR NameBuffer[256];
+    ANSI_STRING SymbolString;
+
+    /* Loop the driver list */
+    NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+    while (NextEntry != &LoaderBlock->LoadOrderListHead)
+    {
+        /* Skip the first two images */
+        if (i >= 2)
+        {
+            /* Get the entry */
+            LdrEntry = CONTAINING_RECORD(NextEntry,
+                                         LDR_DATA_TABLE_ENTRY,
+                                         InLoadOrderLinks);
+            if (LdrEntry->FullDllName.Buffer[0] == L'\\')
+            {
+                /* We have a name, read its data */
+                Name = LdrEntry->FullDllName.Buffer;
+                Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
+
+                /* Check if our buffer can hold it */
+                if (sizeof(NameBuffer) < Length + sizeof(ANSI_NULL))
+                {
+                    /* It's too long */
+                    OverFlow = TRUE;
+                }
+                else
+                {
+                    /* Copy the name */
+                    Count = 0;
+                    do
+                    {
+                        /* Copy the character */
+                        NameBuffer[Count++] = (CHAR)*Name++;
+                    } while (Count < Length);
+
+                    /* Null-terminate */
+                    NameBuffer[Count] = ANSI_NULL;
+                }
+            }
+            else
+            {
+                /* This should be a driver, check if it fits */
+                if (sizeof(NameBuffer) <
+                    (sizeof("\\System32\\Drivers\\") +
+                     NtSystemRoot.Length / sizeof(WCHAR) - sizeof(UNICODE_NULL) +
+                     LdrEntry->BaseDllName.Length / sizeof(WCHAR) +
+                     sizeof(ANSI_NULL)))
+                {
+                    /* Buffer too small */
+                    OverFlow = TRUE;
+                    while (TRUE);
+                }
+                else
+                {
+                    /* Otherwise build the name. HACKED for GCC :( */
+                    sprintf(NameBuffer,
+                            "%S\\System32\\Drivers\\%S",
+                            &SharedUserData->NtSystemRoot[2],
+                            LdrEntry->BaseDllName.Buffer);
+                }
+            }
+
+            /* Check if the buffer was ok */
+            if (!OverFlow)
+            {
+                /* Initialize the ANSI_STRING for the debugger */
+                RtlInitString(&SymbolString, NameBuffer);
+
+                /* Load the symbols */
+                DbgLoadImageSymbols(&SymbolString,
+                                    LdrEntry->DllBase,
+                                    0xFFFFFFFF);
+            }
+        }
+
+        /* Go to the next entry */
+        i++;
+        NextEntry = NextEntry->Flink;
     }
-    
-    HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build "
-                     KERNEL_VERSION_BUILD_STR")\n");
-    HalDisplayString(RES_STR_LEGAL_COPYRIGHT);
-    HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
-                     "Public License, and you\n");
-    HalDisplayString("are welcome to change it and/or distribute copies of it "
-                     "under certain\n");
-    HalDisplayString("conditions. There is absolutely no warranty for "
-                      "ReactOS.\n\n");
-
-    /* Display number of Processors */
-    sprintf(str,
-            "Found %x system processor(s). [%lu MB Memory]\n",
-            (int)KeNumberProcessors,
-            (KeLoaderBlock.MemHigher + 1088)/ 1024);
-    HalDisplayString(str);
-    
+
+    /* Check if we should break after symbol load */
+    if (KdBreakAfterSymbolLoad) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
 }
 
-INIT_FUNCTION
-NTSTATUS
-ExpLoadInitialProcess(PHANDLE ProcessHandle,
-                      PHANDLE ThreadHandle)
+VOID
+NTAPI
+ExpInitializeExecutive(IN ULONG Cpu,
+                       IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    UNICODE_STRING ImagePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\smss.exe");
-    HANDLE SystemProcessHandle;
+    PNLS_DATA_BLOCK NlsData;
+    CHAR Buffer[256];
+    ANSI_STRING AnsiPath;
     NTSTATUS Status;
-    PRTL_USER_PROCESS_PARAMETERS Params=NULL;
-    RTL_USER_PROCESS_INFORMATION Info;
-
-    /* Create a handle to the process */
-    Status = ObpCreateHandle(PsGetCurrentProcess(),
-                             PsInitialSystemProcess,
-                             PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION,
-                             FALSE,
-                             &SystemProcessHandle);
-    if(!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to create a handle for the system process!\n");
-        return Status;
-    }
-
-    /* Create the Parameters */
-    Status = RtlCreateProcessParameters(&Params,
-                                        &ImagePath,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        NULL);
-    if(!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to create ppb!\n");
-        ZwClose(SystemProcessHandle);
-        return Status;
-    }
-
-    DPRINT("Creating process\n");
-    Status = RtlCreateUserProcess(&ImagePath,
-                                  OBJ_CASE_INSENSITIVE,
-                                  Params,
-                                  NULL,
-                                  NULL,
-                                  SystemProcessHandle,
-                                  FALSE,
-                                  NULL,
-                                  NULL,
-                                  &Info);
-    
-    /* Close the handle and free the params */
-    ZwClose(SystemProcessHandle);
-    RtlDestroyProcessParameters(Params);
+    PCHAR CommandLine, PerfMem;
+    ULONG PerfMemUsed;
 
-    if (!NT_SUCCESS(Status))
+    /* Validate Loader */
+    if (!ExpIsLoaderValid(LoaderBlock))
     {
-        DPRINT1("NtCreateProcess() failed (Status %lx)\n", Status);
-        return(Status);
+        /* Invalid loader version */
+        KeBugCheckEx(MISMATCHED_HAL,
+                     3,
+                     LoaderBlock->Extension->Size,
+                     LoaderBlock->Extension->MajorVersion,
+                     LoaderBlock->Extension->MinorVersion);
     }
 
-    /* Start it up */
-    ZwResumeThread(Info.ThreadHandle, NULL);
+    /* Initialize PRCB pool lookaside pointers */
+    ExInitPoolLookasidePointers();
 
-    /* Return Handles */
-    *ProcessHandle = Info.ProcessHandle;
-    *ThreadHandle = Info.ThreadHandle;
-    DPRINT("Process created successfully\n");
-    return STATUS_SUCCESS;
-}
-   
-VOID
-INIT_FUNCTION
-STDCALL
-ExpInitializeExecutive(VOID)
-{
-    UNICODE_STRING EventName;
-    HANDLE InitDoneEventHandle;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    BOOLEAN NoGuiBoot = FALSE;
-    BOOLEAN BootLog = FALSE;
-    ULONG MaxMem = 0;
-    BOOLEAN ForceAcpiDisable = FALSE;
-    LARGE_INTEGER Timeout;
-    HANDLE ProcessHandle;
-    HANDLE ThreadHandle;
-    NTSTATUS Status;
+    /* Check if this is an application CPU */
+    if (Cpu)
+    {
+        /* Then simply initialize it with HAL */
+        if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
+        {
+            /* Initialization failed */
+            KeBugCheck(HAL_INITIALIZATION_FAILED);
+        }
+
+        /* We're done */
+        return;
+    }
 
-    /* Check if the structures match the ASM offset constants */
-    ExecuteRuntimeAsserts();
+    /* Assume no text-mode or remote boot */
+    ExpInTextModeSetup = FALSE;
+    IoRemoteBootClient = FALSE;
 
-    /* Sets up the Text Sections of the Kernel and HAL for debugging */
-    LdrInit1();
+    /* Check if we have a setup loader block */
+    if (LoaderBlock->SetupLdrBlock)
+    {
+        /* Check if this is text-mode setup */
+        if (LoaderBlock->SetupLdrBlock->Flags & 1) ExpInTextModeSetup = TRUE;
 
-    /* Lower the IRQL to Dispatch Level */
-    KeLowerIrql(DISPATCH_LEVEL);
+        /* Check if this is network boot */
+        if (LoaderBlock->SetupLdrBlock->Flags & 2)
+        {
+            /* Set variable */
+            IoRemoteBootClient = TRUE;
 
-    /* Sets up the VDM Data */
-    NtEarlyInitVdm();
+            /* Make sure we're actually booting off the network */
+            ASSERT(!_memicmp(LoaderBlock->ArcBootDeviceName, "net(0)", 6));
+        }
+    }
 
-    /* Parse Command Line Settings */
-    ParseCommandLine(&MaxMem, &NoGuiBoot, &BootLog, &ForceAcpiDisable);
+    /* Set phase to 0 */
+    ExpInitializationPhase = 0;
 
-    /* Initialize Kernel Memory Address Space */
-    MmInit1(FirstKrnlPhysAddr,
-            LastKrnlPhysAddr,
-            LastKernelAddress,
-            (PADDRESS_RANGE)&KeMemoryMap,
-            KeMemoryMapRangeCount,
-            MaxMem > 8 ? MaxMem : 4096);
+    /* Get boot command line */
+    CommandLine = LoaderBlock->LoadOptions;
+    if (CommandLine)
+    {
+        /* Upcase it for comparison and check if we're in performance mode */
+        _strupr(CommandLine);
+        PerfMem = strstr(CommandLine, "PERFMEM");
+        if (PerfMem)
+        {
+            /* Check if the user gave a number of bytes to use */
+            PerfMem = strstr(PerfMem, "=");
+            if (PerfMem)
+            {
+                /* Read the number of pages we'll use */
+                PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
+                if (PerfMem)
+                {
+                    /* FIXME: TODO */
+                    DPRINT1("BBT performance mode not yet supported."
+                            "/PERFMEM option ignored.\n");
+                }
+            }
+        }
 
-    /* Parse the Loaded Modules (by FreeLoader) and cache the ones we'll need */
-    ParseAndCacheLoadedModules();
+        /* Check if we're burning memory */
+        PerfMem = strstr(CommandLine, "BURNMEMORY");
+        if (PerfMem)
+        {
+            /* Check if the user gave a number of bytes to use */
+            PerfMem = strstr(PerfMem, "=");
+            if (PerfMem)
+            {
+                /* Read the number of pages we'll use */
+                PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
+                if (PerfMem)
+                {
+                    /* FIXME: TODO */
+                    DPRINT1("Burnable memory support not yet present."
+                            "/BURNMEM option ignored.\n");
+                }
+            }
+        }
+    }
 
+    /* Setup NLS Base and offsets */
+    NlsData = LoaderBlock->NlsData;
+    ExpNlsTableBase = NlsData->AnsiCodePageData;
+    ExpAnsiCodePageDataOffset = 0;
+    ExpOemCodePageDataOffset = ((ULONG_PTR)NlsData->OemCodePageData -
+                                (ULONG_PTR)NlsData->AnsiCodePageData);
+    ExpUnicodeCaseTableDataOffset = ((ULONG_PTR)NlsData->UnicodeCodePageData -
+                                     (ULONG_PTR)NlsData->AnsiCodePageData);
+
+    /* Initialize the NLS Tables */
+    RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpAnsiCodePageDataOffset),
+                     (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpOemCodePageDataOffset),
+                     (PVOID)((ULONG_PTR)ExpNlsTableBase +
+                             ExpUnicodeCaseTableDataOffset),
+                     &ExpNlsTableInfo);
+    RtlResetRtlTranslations(&ExpNlsTableInfo);
+
+    /* Now initialize the HAL */
+    if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
+    {
+        /* HAL failed to initialize, bugcheck */
+        KeBugCheck(HAL_INITIALIZATION_FAILED);
+    }
 
-    /* Initialize the Dispatcher, Clock and Bug Check Mechanisms. */
-    KeInit2();
+    /* Make sure interrupts are active now */
+    _enable();
 
-    /* Bring back the IRQL to Passive */
-    KeLowerIrql(PASSIVE_LEVEL);
+    /* Clear the crypto exponent */
+    SharedUserData->CryptoExponent = 0;
 
-    /* Initialize Profiling */
-    InitializeListHead(&KiProfileListHead);
-    InitializeListHead(&KiProfileSourceListHead);
-    KeInitializeSpinLock(&KiProfileLock);
+    /* Set global flags for the checked build */
+#if DBG
+    NtGlobalFlag |= FLG_ENABLE_CLOSE_EXCEPTIONS |
+                    FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
+#endif
 
-    /* Load basic Security for other Managers */
-    if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
+    /* Setup NT System Root Path */
+    sprintf(Buffer, "C:%s", LoaderBlock->NtBootPathName);
 
-    /* Create the Basic Object Manager Types to allow new Object Types */
-    ObInit();
+    /* Convert to ANSI_STRING and null-terminate it */
+    RtlInitString(&AnsiPath, Buffer );
+    Buffer[--AnsiPath.Length] = ANSI_NULL;
 
-    /* Initialize Lookaside Lists */
-    ExpInitLookasideLists();
+    /* Get the string from KUSER_SHARED_DATA's buffer */
+    RtlInitEmptyUnicodeString(&NtSystemRoot,
+                              SharedUserData->NtSystemRoot,
+                              sizeof(SharedUserData->NtSystemRoot));
 
-    /* Set up Region Maps, Sections and the Paging File */
-    MmInit2();
+    /* Now fill it in */
+    Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE);
+    if (!NT_SUCCESS(Status)) KEBUGCHECK(SESSION3_INITIALIZATION_FAILED);
 
-    /* Initialize Tokens now that the Object Manager is ready */
-    if (!SeInit2()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
+    /* Setup bugcheck messages */
+    KiInitializeBugCheck();
 
-    /* Set 1 CPU for now, we'll increment this later */
-    KeNumberProcessors = 1;
-    
-    /* Initalize the Process Manager */
-    PiInitProcessManager();
-    
-    /* Break into the Debugger if requested */
-    if (KdPollBreakIn()) DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
+    /* Setup initial system settings (FIXME: Needs Cm Rewrite) */
+    CmGetSystemControlValues(LoaderBlock->RegistryBase, CmControlVector);
 
-    /* Initialize all processors */
-    while (!HalAllProcessorsStarted()) {
+    /* Initialize the executive at phase 0 */
+    if (!ExInitSystem()) KEBUGCHECK(PHASE0_INITIALIZATION_FAILED);
+
+    /* Initialize the memory manager at phase 0 */
+    if (!MmInitSystem(0, LoaderBlock)) KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
 
-        PVOID ProcessorStack;
+    /* Load boot symbols */
+    ExpLoadBootSymbols(LoaderBlock);
 
-        /* Set up the Kernel and Process Manager for this CPU */
-        KePrepareForApplicationProcessorInit(KeNumberProcessors);
-        KeCreateApplicationProcessorIdleThread(KeNumberProcessors);
+    /* Set system ranges */
+    SharedUserData->Reserved1 = (ULONG_PTR)MmHighestUserAddress;
+    SharedUserData->Reserved3 = (ULONG_PTR)MmSystemRangeStart;
 
-        /* Allocate a stack for use when booting the processor */
-        ProcessorStack = RVA(Ki386InitialStackArray[((int)KeNumberProcessors)], MM_STACK_SIZE);
+    /* Make a copy of the NLS Tables */
+    ExpInitNls(LoaderBlock);
 
-        /* Tell HAL a new CPU is being started */
-        HalStartNextProcessor(0, (ULONG)ProcessorStack - 2*sizeof(FX_SAVE_AREA));
-        KeNumberProcessors++;
+    /* Check if the user wants a kernel stack trace database */
+    if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB)
+    {
+        /* FIXME: TODO */
+        DPRINT1("Kernel-mode stack trace support not yet present."
+                "FLG_KERNEL_STACK_TRACE_DB flag ignored.\n");
     }
 
-    /* Do Phase 1 HAL Initalization */
-    HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+    /* Check if he wanted exception logging */
+    if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
+    {
+        /* FIXME: TODO */
+        DPRINT1("Kernel-mode exception logging support not yet present."
+                "FLG_ENABLE_EXCEPTION_LOGGING flag ignored.\n");
+    }
 
-    /* Initialize Basic System Objects and Worker Threads */
-    ExInit2();
+    /* Initialize the Handle Table */
+    ExpInitializeHandleTables();
 
-    /* Create the system handle table, assign it to the system process, create
-       the client id table and assign a PID for the system process. This needs
-       to be done before the worker threads are initialized so the system
-       process gets the first PID (4) */
-    PspPostInitSystemProcess();
+#if DBG
+    /* On checked builds, allocate the system call count table */
+    KeServiceDescriptorTable[0].Count =
+        ExAllocatePoolWithTag(NonPagedPool,
+                              KiServiceLimit * sizeof(ULONG),
+                              TAG('C', 'a', 'l', 'l'));
 
-    /* initialize the worker threads */
-    ExpInitializeWorkerThreads();
+    /* Use it for the shadow table too */
+    KeServiceDescriptorTableShadow[0].Count = KeServiceDescriptorTable[0].Count;
 
-    /* initialize callbacks */
-    ExpInitializeCallbacks();
+    /* Make sure allocation succeeded */
+    if (KeServiceDescriptorTable[0].Count)
+    {
+        /* Zero the call counts to 0 */
+        RtlZeroMemory(KeServiceDescriptorTable[0].Count,
+                      KiServiceLimit * sizeof(ULONG));
+    }
+#endif
 
-    /* Call KD Providers at Phase 1 */
-    KdInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+    /* Create the Basic Object Manager Types to allow new Object Types */
+    if (!ObInit()) KEBUGCHECK(OBJECT_INITIALIZATION_FAILED);
 
-    /* Initialize I/O Objects, Filesystems, Error Logging and Shutdown */
-    IoInit();
+    /* Load basic Security for other Managers */
+    if (!SeInit()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
+
+    /* Initialize the Process Manager */
+    if (!PsInitSystem(LoaderBlock)) KEBUGCHECK(PROCESS_INITIALIZATION_FAILED);
+
+    /* Initialize the PnP Manager */
+    if (!PpInitSystem()) KEBUGCHECK(PP0_INITIALIZATION_FAILED);
+
+    /* Initialize the User-Mode Debugging Subsystem */
+    DbgkInitialize();
+
+    /* Calculate the tick count multiplier */
+    ExpTickCountMultiplier = ExComputeTickCountMultiplier(KeMaximumIncrement);
+    SharedUserData->TickCountMultiplier = ExpTickCountMultiplier;
+
+    /* Set the OS Version */
+    SharedUserData->NtMajorVersion = NtMajorVersion;
+    SharedUserData->NtMinorVersion = NtMinorVersion;
+
+    /* Set the machine type */
+#if defined(_X86_)
+    SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_I386;
+    SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_I386;
+#elif defined(_PPC_) // <3 Arty
+    SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_POWERPC;
+    SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_POWERPC;
+#elif
+#error "Unsupported ReactOS Target"
+#endif
+}
 
-    /* TBD */
-    PoInit((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock, ForceAcpiDisable);
+VOID
+NTAPI
+Phase1InitializationDiscard(PVOID Context)
+{
+    PLOADER_PARAMETER_BLOCK LoaderBlock = Context;
+    PCHAR CommandLine, Y2KHackRequired;
+    LARGE_INTEGER Timeout;
+    NTSTATUS Status;
+    TIME_FIELDS TimeFields;
+    LARGE_INTEGER SystemBootTime, UniversalBootTime, OldTime;
+    PRTL_USER_PROCESS_INFORMATION ProcessInfo;
+    BOOLEAN SosEnabled, NoGuiBoot;
+    ULONG YearHack = 0;
+
+    /* Allocate initial process information */
+    ProcessInfo = ExAllocatePoolWithTag(NonPagedPool,
+                                        sizeof(RTL_USER_PROCESS_INFORMATION),
+                                        TAG('I', 'n', 'i', 't'));
+    if (!ProcessInfo)
+    {
+        /* Bugcheck */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 8, 0, 0);
+    }
 
-    /* Initialize the Registry (Hives are NOT yet loaded!) */
-    CmInitializeRegistry();
+    /* Set to phase 1 */
+    ExpInitializationPhase = 1;
 
-    /* Unmap Low memory, initialize the Page Zeroing and the Balancer Thread */
-    MmInit3();
+    /* Set us at maximum priority */
+    KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
 
-    /* Initialize Cache Views */
-    CcInit();
+    /* Do Phase 1 HAL Initialization */
+    if (!HalInitSystem(1, LoaderBlock)) KeBugCheck(HAL1_INITIALIZATION_FAILED);
 
-    /* Initialize File Locking */
-    FsRtlpInitFileLockingImplementation();
+    /* Get the command line and upcase it */
+    CommandLine = _strupr(LoaderBlock->LoadOptions);
 
-    /* Report all resources used by hal */
-    HalReportResourceUsage();
+    /* Check if GUI Boot is enabled */
+    NoGuiBoot = (strstr(CommandLine, "NOGUIBOOT")) ? TRUE: FALSE;
 
-    /* Clear the screen to blue */
-    HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+    /* Get the SOS setting */
+    SosEnabled = strstr(CommandLine, "SOS") ? TRUE: FALSE;
 
-    /* Display version number and copyright/warranty message */
-    ExpDisplayNotice();
+    /* Setup the boot driver */
+    InbvEnableBootDriver(!NoGuiBoot);
+    InbvDriverInitialize(LoaderBlock, 18);
 
-    /* Call KD Providers at Phase 2 */
-    KdInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+    /* Check if GUI boot is enabled */
+    if (!NoGuiBoot)
+    {
+        /* It is, display the boot logo and enable printing strings */
+        InbvEnableDisplayString(SosEnabled);
+        DisplayBootBitmap(SosEnabled);
+    }
+    else
+    {
+        /* Release display ownership if not using GUI boot */
+        InbvNotifyDisplayOwnershipLost(NULL);
 
-    /* Import and create NLS Data and Sections */
-    RtlpInitNls();
+        /* Don't allow boot-time strings */
+        InbvEnableDisplayString(FALSE);
+    }
 
-    /* Import and Load Registry Hives */
-    CmInitHives(SetupMode);
+    /* Check if this is LiveCD (WinPE) mode */
+    if (strstr(CommandLine, "MININT"))
+    {
+        /* Setup WinPE Settings */
+        InitIsWinPEMode = TRUE;
+        InitWinPEModeType |= (strstr(CommandLine, "INRAM")) ? 0x80000000 : 1;
+    }
 
-    /* Initialize the time zone information from the registry */
-    ExpInitTimeZoneInfo();
+    /* FIXME: Print product name, version, and build */
 
-    /* Enter the kernel debugger before starting up the boot drivers */
-    if (KdDebuggerEnabled && KdpEarlyBreak)
-        DbgBreakPoint();
+    /* Initialize Power Subsystem in Phase 0 */
+    if (!PoInitSystem(0, AcpiTableDetected)) KeBugCheck(INTERNAL_POWER_ERROR);
 
-    /* Setup Drivers and Root Device Node */
-    IoInit2(BootLog);
+    /* Check for Y2K hack */
+    Y2KHackRequired = strstr(CommandLine, "YEAR");
+    if (Y2KHackRequired) Y2KHackRequired = strstr(Y2KHackRequired, "=");
+    if (Y2KHackRequired) YearHack = atol(Y2KHackRequired + 1);
 
-    /* Display the boot screen image if not disabled */
-    if (!NoGuiBoot) InbvEnableBootDriver(TRUE);
+    /* Query the clock */
+    if ((ExCmosClockIsSane) && (HalQueryRealTimeClock(&TimeFields)))
+    {
+        /* Check if we're using the Y2K hack */
+        if (Y2KHackRequired) TimeFields.Year = (CSHORT)YearHack;
+
+        /* Convert to time fields */
+        RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
+        UniversalBootTime = SystemBootTime;
+
+#if 0 // FIXME: Won't work until we can read registry data here
+        /* FIXME: This assumes that the RTC is not already in GMT */
+        ExpTimeZoneBias.QuadPart = Int32x32To64(ExpLastTimeZoneBias * 60,
+                                                10000000);
+
+        /* Set the boot time-zone bias */
+        SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
+        SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
+        SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
+
+        /* Convert the boot time to local time, and set it */
+        UniversalBootTime.QuadPart = SystemBootTime.QuadPart +
+                                     ExpTimeZoneBias.QuadPart;
+#endif
 
-    /* Create ARC Names, SystemRoot SymLink, Load Drivers and Assign Letters */
-    IoInit3();
+        /* Update the system time */
+        KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
 
-    /* Load the System DLL and its Entrypoints */
-    PsLocateSystemDll();
+        /* Remember this as the boot time */
+        KeBootTime = UniversalBootTime;
+        KeBootTimeBias = 0;
+    }
 
-    /* Initialize the Default Locale */
-    PiInitDefaultLocale();
+    /* Initialize all processors */
+    if (!HalAllProcessorsStarted()) KeBugCheck(HAL1_INITIALIZATION_FAILED);
 
-    /* Initialize shared user page. Set dos system path, dos device map, etc. */
-    InitSystemSharedUserPage ((PCHAR)KeLoaderBlock.CommandLine);
+    /* FIXME: Print CPU and Memory */
 
-    /* Create 'ReactOSInitDone' event */
-    RtlInitUnicodeString(&EventName, L"\\ReactOSInitDone");
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &EventName,
-                               0,
-                               NULL,
-                               NULL);
-    Status = ZwCreateEvent(&InitDoneEventHandle,
-                           EVENT_ALL_ACCESS,
-                           &ObjectAttributes,
-                           SynchronizationEvent,
-                           FALSE);
+    /* Update the progress bar */
+    InbvUpdateProgressBar(5);
 
-    /* Check for Success */
-    if (!NT_SUCCESS(Status)) {
+    /* Call OB initialization again */
+    if (!ObInit()) KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
 
-        DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status);
-        InitDoneEventHandle = INVALID_HANDLE_VALUE;
+    /* Initialize Basic System Objects and Worker Threads */
+    if (!ExInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 1, 0);
+
+    /* Initialize the later stages of the kernel */
+    if (!KeInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 2, 0);
+
+    /* Call KD Providers at Phase 1 */
+    if (!KdInitSystem(ExpInitializationPhase, KeLoaderBlock))
+    {
+        /* Failed, bugcheck */
+        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 3, 0);
     }
 
-    /* Launch initial process */
-    Status = ExpLoadInitialProcess(&ProcessHandle,
-                                   &ThreadHandle);
+    /* Initialize the SRM in Phase 1 */
+    if (!SeInit()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
 
-    /* Check for success, Bugcheck if we failed */
-    if (!NT_SUCCESS(Status)) {
+    /* Update the progress bar */
+    InbvUpdateProgressBar(10);
 
-        KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    /* Create SystemRoot Link */
+    Status = ExpCreateSystemRootLink(LoaderBlock);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed to create the system root link */
+        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 0, 0, 0);
     }
 
-    /* Wait on the Completion Event */
-    if (InitDoneEventHandle != INVALID_HANDLE_VALUE) {
+    /* Set up Region Maps, Sections and the Paging File */
+    if (!MmInitSystem(1, LoaderBlock)) KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
+
+    /* Create NLS section */
+    ExpInitNls(KeLoaderBlock);
+
+    /* Initialize Cache Views */
+    if (!CcInitializeCacheManager()) KeBugCheck(CACHE_INITIALIZATION_FAILED);
+
+    /* Initialize the Registry */
+    if (!CmInitSystem1()) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
 
-        HANDLE Handles[2]; /* Init event, Initial process */
+    /* Update progress bar */
+    InbvUpdateProgressBar(15);
 
-        /* Setup the Handles to wait on */
-        Handles[0] = InitDoneEventHandle;
-        Handles[1] = ProcessHandle;
+    /* Update timezone information */
+    ExRefreshTimeZoneInformation(&SystemBootTime);
 
-        /* Wait for the system to be initialized */
-        Timeout.QuadPart = (LONGLONG)-1200000000;  /* 120 second timeout */
-        Status = ZwWaitForMultipleObjects(2,
-                                          Handles,
-                                          WaitAny,
-                                          FALSE,
-                                          &Timeout);
-        if (!NT_SUCCESS(Status)) {
+    /* Initialize the File System Runtime Library */
+    if (!FsRtlInitSystem()) KeBugCheck(FILE_INITIALIZATION_FAILED);
 
-            DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status);
+    /* Report all resources used by HAL */
+    HalReportResourceUsage();
 
-        } else if (Status == STATUS_TIMEOUT) {
+    /* Call the debugger DLL once we have KD64 6.0 support */
+    //KdDebuggerInitialize1(LoaderBlock);
 
-            DPRINT1("WARNING: System not initialized after 120 seconds.\n");
+    /* Setup PnP Manager in phase 1 */
+    if (!PpInitSystem()) KeBugCheck(PP1_INITIALIZATION_FAILED);
 
-        } else if (Status == STATUS_WAIT_0 + 1) {
+    /* Update progress bar */
+    InbvUpdateProgressBar(20);
 
-            /* Crash the system if the initial process was terminated. */
-            KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
-        }
+    /* Initialize LPC */
+    if (!LpcInitSystem()) KeBugCheck(LPC_INITIALIZATION_FAILED);
 
-        /* Disable the Boot Logo */
-        if (!NoGuiBoot) InbvEnableBootDriver(FALSE);
+    /* Initialize the I/O Subsystem */
+    if (!IoInitSystem(KeLoaderBlock)) KeBugCheck(IO1_INITIALIZATION_FAILED);
 
-        /* Signal the Event and close the handle */
-        ZwSetEvent(InitDoneEventHandle, NULL);
-        ZwClose(InitDoneEventHandle);
+    /* Unmap Low memory, and initialize the MPW and Balancer Thread */
+    MmInitSystem(2, LoaderBlock);
 
-    } else {
+    /* Update progress bar */
+    InbvUpdateProgressBar(80);
+
+    /* Initialize VDM support */
+    KeI386VdmInitialize();
+
+    /* Initialize Power Subsystem in Phase 1*/
+    if (!PoInitSystem(1, AcpiTableDetected)) KeBugCheck(INTERNAL_POWER_ERROR);
+
+    /* Initialize the Process Manager at Phase 1 */
+    if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
+
+    /* Update progress bar */
+    InbvUpdateProgressBar(85);
+
+    /* Make sure nobody touches the loader block again */
+    if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
+    LoaderBlock = Context = NULL;
+
+    /* Update progress bar */
+    InbvUpdateProgressBar(90);
+
+    /* Launch initial process */
+    Status = ExpLoadInitialProcess(ProcessInfo);
 
-        /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */
-        if (!NoGuiBoot) InbvEnableBootDriver(FALSE);
+    /* Update progress bar */
+    InbvUpdateProgressBar(100);
 
-        /* Crash the system if the initial process terminates within 5 seconds. */
-        Timeout.QuadPart = (LONGLONG)-50000000;  /* 5 second timeout */
-        Status = ZwWaitForSingleObject(ProcessHandle,
-                                       FALSE,
-                                       &Timeout);
+    /* Allow strings to be displayed */
+    InbvEnableDisplayString(TRUE);
 
-        /* Check for timeout, crash if the initial process didn't initalize */
-        if (Status != STATUS_TIMEOUT) KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 1, 0, 0);
+    /* Wait 5 seconds for it to initialize */
+    Timeout.QuadPart = Int32x32To64(5, -10000000);
+    Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
+    if (InbvBootDriverInstalled) FinalizeBootLogo();
+
+    if (Status == STATUS_SUCCESS)
+    {
+        /* Bugcheck the system if SMSS couldn't initialize */
+        KeBugCheck(SESSION5_INITIALIZATION_FAILED);
     }
 
-    /* Enable the Clock, close remaining handles */
-    KiTimerSystemAuditing = 1;
-    ZwClose(ThreadHandle);
-    ZwClose(ProcessHandle);
+    /* Close process handles */
+    ZwClose(ProcessInfo->ThreadHandle);
+    ZwClose(ProcessInfo->ProcessHandle);
+
+    /* FIXME: We should free the initial process' memory!*/
+
+    /* Increase init phase */
+    ExpInitializationPhase += 1;
+
+    /* Free the process information */
+    ExFreePool(ProcessInfo);
 }
 
 VOID
-STDCALL
-INIT_FUNCTION
-ExInit2(VOID)
+NTAPI
+Phase1Initialization(IN PVOID Context)
 {
-    ExpInitializeEventImplementation();
-    ExpInitializeEventPairImplementation();
-    ExpInitializeMutantImplementation();
-    ExpInitializeSemaphoreImplementation();
-    ExpInitializeTimerImplementation();
-    LpcpInitSystem();
-    ExpInitializeProfileImplementation();
-    ExpWin32kInit();
-    ExpInitUuids();
-    ExpInitializeHandleTables();
+    /* Do the .INIT part of Phase 1 which we can free later */
+    Phase1InitializationDiscard(Context);
+
+    /* Jump into zero page thread */
+    MmZeroPageThreadMain(NULL);
 }
 
-/* EOF */