2003-08-11 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / ke / main.c
index f7be0c3..e23817a 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: main.c,v 1.154 2003/05/15 11:05:20 ekohl Exp $
+/* $Id: main.c,v 1.167 2003/08/11 18:50:12 chorns Exp $
  *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/main.c
@@ -28,7 +28,8 @@
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
+#define NTOS_MODE_KERNEL
+#include <ntos.h>
 #include <internal/ntoskrnl.h>
 #include <reactos/resource.h>
 #include <internal/mm.h>
@@ -49,6 +50,7 @@
 #include <internal/registry.h>
 #include <internal/nls.h>
 #include <reactos/bugcodes.h>
+#include <ntos/bootvid.h>
 
 #ifdef HALDBG
 #include <internal/ntosdbg.h>
@@ -202,7 +204,7 @@ InitSystemSharedUserPage (PCSZ ParameterLine)
        CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n",
                 Status);
 
-       KeBugCheck (0x0);
+       KEBUGCHECK (0x0);
      }
 
    Status = NtQuerySymbolicLinkObject (Handle,
@@ -216,7 +218,7 @@ InitSystemSharedUserPage (PCSZ ParameterLine)
        CPRINT("NtQuerySymbolicObject() failed (Status %x)\n",
                 Status);
 
-       KeBugCheck (0x0);
+       KEBUGCHECK (0x0);
      }
    DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
 
@@ -281,10 +283,23 @@ InitSystemSharedUserPage (PCSZ ParameterLine)
    if (BootDriveFound == FALSE)
      {
        DbgPrint("No system drive found!\n");
-       KeBugCheck (0x0);
+       KEBUGCHECK (0x0);
      }
 }
 
+VOID STATIC
+MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
+{
+  PHYSICAL_ADDRESS Page;
+  ULONG i;
+
+  for (i = 0; i < PAGE_ROUND_UP(Length)/PAGE_SIZE; i++)
+  {
+     Page = MmGetPhysicalAddressForProcess(NULL, StartAddress + i * PAGE_SIZE);
+     MmDeleteVirtualMapping(NULL, StartAddress + i * PAGE_SIZE, FALSE, NULL, NULL);
+     MmDereferencePage(Page);
+  }
+}
 
 VOID
 ExpInitializeExecutive(VOID)
@@ -300,6 +315,12 @@ ExpInitializeExecutive(VOID)
   CHAR str[50];
   NTSTATUS Status;
   BOOLEAN SetupBoot;
+  PCHAR p1, p2;
+  ULONG MaxMem;
+  BOOLEAN NoBootScreen = FALSE;
+  UNICODE_STRING Name;
+  HANDLE InitDoneEventHandle;
+  OBJECT_ATTRIBUTES ObjectAttributes;
 
   /*
    * Fail at runtime if someone has changed various structures without
@@ -308,6 +329,7 @@ ExpInitializeExecutive(VOID)
   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, 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);
@@ -317,26 +339,128 @@ ExpInitializeExecutive(VOID)
   assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
-  
-  assert(FIELD_OFFSET(KPCR, ExceptionList) == KPCR_EXCEPTION_LIST);
+
+  assert(FIELD_OFFSET(KPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST);
   assert(FIELD_OFFSET(KPCR, Self) == KPCR_SELF);
-  assert(FIELD_OFFSET(KPCR, CurrentThread) == KPCR_CURRENT_THREAD);
+  assert(FIELD_OFFSET(IKPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST);
+  assert(FIELD_OFFSET(IKPCR, Self) == KPCR_SELF);
+  assert(FIELD_OFFSET(IKPCR, CurrentThread) == KPCR_CURRENT_THREAD);
 
   LdrInit1();
 
   KeLowerIrql(DISPATCH_LEVEL);
   
   NtEarlyInitVdm();
-  
+
+  p1 = (PCHAR)KeLoaderBlock.CommandLine;
+
+  MaxMem = 0;
+  while(*p1 && (p2 = strchr(p1, '/')))
+  {
+     p2++;
+     if (!_strnicmp(p2, "MAXMEM", 6))
+     {
+        p2 += 6;
+        while (isspace(*p2)) p2++;
+       if (*p2 == '=')
+       {
+          p2++;
+          while(isspace(*p2)) p2++;
+          if (isdigit(*p2))
+          {
+             while (isdigit(*p2))
+             {
+                MaxMem = MaxMem * 10 + *p2 - '0';
+                p2++;
+             }
+             break;
+          }
+       }
+     }
+    else if (!_strnicmp(p2, "NOBOOTSCREEN", 12))
+      {
+        p2 += 12;
+        NoBootScreen = TRUE;
+      }
+     p1 = p2;
+  }
+
   MmInit1(FirstKrnlPhysAddr,
          LastKrnlPhysAddr,
          LastKernelAddress,
          (PADDRESS_RANGE)&KeMemoryMap,
-         KeMemoryMapRangeCount);
-  
-  /* Create default nls tables */
-  RtlpInitNlsTables();
-  
+         KeMemoryMapRangeCount,
+         MaxMem > 8 ? MaxMem : 4096);
+
+  /* Import ANSI code page table */
+  for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+    {
+      start = KeLoaderModules[i].ModStart;
+      length = KeLoaderModules[i].ModEnd - start;
+
+      name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
+      if (name == NULL)
+       {
+         name = (PCHAR)KeLoaderModules[i].String;
+       }
+      else
+       {
+         name++;
+       }
+
+      if (!_stricmp (name, "ansi.nls"))
+       {
+         RtlpImportAnsiCodePage((PUSHORT)start, length);
+       }
+    }
+
+  /* Import OEM code page table */
+  for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+    {
+      start = KeLoaderModules[i].ModStart;
+      length = KeLoaderModules[i].ModEnd - start;
+
+      name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
+      if (name == NULL)
+       {
+         name = (PCHAR)KeLoaderModules[i].String;
+       }
+      else
+       {
+         name++;
+       }
+
+      if (!_stricmp (name, "oem.nls"))
+       {
+         RtlpImportOemCodePage((PUSHORT)start, length);
+       }
+    }
+
+  /* Import Unicode casemap table */
+  for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+    {
+      start = KeLoaderModules[i].ModStart;
+      length = KeLoaderModules[i].ModEnd - start;
+
+      name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
+      if (name == NULL)
+       {
+         name = (PCHAR)KeLoaderModules[i].String;
+       }
+      else
+       {
+         name++;
+       }
+
+      if (!_stricmp (name, "casemap.nls"))
+       {
+         RtlpImportUnicodeCasemap((PUSHORT)start, length);
+       }
+    }
+
+  /* Create initial NLS tables */
+  RtlpCreateInitialNlsTables();
+
   /*
    * Initialize the kernel debugger
    */
@@ -348,12 +472,12 @@ ExpInitializeExecutive(VOID)
   KeLowerIrql(PASSIVE_LEVEL);
 
   if (!SeInit1())
-    KeBugCheck(SECURITY_INITIALIZATION_FAILED);
+    KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
 
   ObInit();
 
   if (!SeInit2())
-    KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
+    KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
 
   PiInitProcessManager();
 
@@ -364,19 +488,6 @@ ExpInitializeExecutive(VOID)
       DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
     }
 
-  /*
-   * Display version number and copyright/warranty message
-   */
-  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");
-
   /* Initialize all processors */
   KeNumberProcessors = 0;
 
@@ -399,6 +510,49 @@ ExpInitializeExecutive(VOID)
       KeNumberProcessors++;
     }
 
+  /*
+   * Initialize various critical subsystems
+   */
+  HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+
+  ExInit();
+  IoInit();
+  PoInit();
+  LdrInitModuleManagement();
+  CmInitializeRegistry();
+  NtInit();
+  MmInit3();
+  CcInit();
+  KdInit2();
+  FsRtlpInitFileLockingImplementation();
+
+  /* Report all resources used by hal */
+  HalReportResourceUsage();
+
+  /* Display the boot screen image if not disabled */
+  if (!NoBootScreen)
+    {
+      InbvEnableBootDriver(TRUE);
+    }
+
+  /*
+   * Clear the screen to blue
+   */
+  HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+
+  /*
+   * Display version number and copyright/warranty message
+   */
+  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");
+
   if (KeNumberProcessors > 1)
     {
       sprintf(str,
@@ -414,29 +568,12 @@ ExpInitializeExecutive(VOID)
     }
   HalDisplayString(str);
 
-  /*
-   * Initialize various critical subsystems
-   */
-  HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+  KdInit3();
 
-  ExInit();
-  IoInit();
-  PoInit();
-  LdrInitModuleManagement();
-  CmInitializeRegistry();
-  NtInit();
-  MmInit3();
 
-  /* Create the nls section */
-  RtlpInitNlsSection();
+  /* Create the NLS section */
+  RtlpCreateNlsSection();
 
-  CcInit();
-  KdInit2();
-  FsRtlpInitFileLockingImplementation();
-  
-  /* Report all resources used by hal */
-  HalReportResourceUsage();
-  
   /*
    * Initalize services loaded at boot time
    */
@@ -449,7 +586,7 @@ ExpInitializeExecutive(VOID)
        KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
     }
 
-  /*  Pass 2: import system hive registry chunk  */
+  /* Pass 1: import system hive registry chunk */
   SetupBoot = TRUE;
   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
     {
@@ -476,7 +613,7 @@ ExpInitializeExecutive(VOID)
        }
     }
 
-  /*  Pass 3: import hardware hive registry chunk  */
+  /* Pass 2: import hardware hive registry chunk */
   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
     {
       start = KeLoaderModules[i].ModStart;
@@ -493,7 +630,6 @@ ExpInitializeExecutive(VOID)
   /* Create dummy keys if no hardware hive was found */
   CmImportHardwareHive (NULL, 0);
 
-
   /* Initialize volatile registry settings */
   if (SetupBoot == FALSE)
     {
@@ -511,7 +647,7 @@ ExpInitializeExecutive(VOID)
 
   IoInit2();
 
-  /*  Pass 4: process boot loaded drivers  */
+  /* Pass 3: process boot loaded drivers */
   BootDriverCount = 0;
   for (i=1; i < KeLoaderBlock.ModsCount; i++)
     {
@@ -529,10 +665,23 @@ ExpInitializeExecutive(VOID)
        BootDriverCount++;
     }
 
+  /* Pass 4: free memory for all boot files, except ntoskrnl.exe and hal.dll */
+  for (i = 2; i < KeLoaderBlock.ModsCount; i++)
+    {
+#ifdef KDBG
+       /* Do not free the memory from symbol files, if the kernel debugger is activ */
+       if (!RtlpCheckFileNameExtension(name, ".sym"))
+#endif
+         {
+           MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
+                                 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
+        }
+    }
+
   if (BootDriverCount == 0)
     {
       DbgPrint("No boot drivers available.\n");
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
 
   /* Create ARC names for boot devices */
@@ -542,7 +691,7 @@ ExpInitializeExecutive(VOID)
   CPRINT("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
   Status = IoCreateSystemRootLink((PUCHAR)KeLoaderBlock.CommandLine);
   if (!NT_SUCCESS(Status))
-    KeBugCheck(INACCESSIBLE_BOOT_DEVICE);
+    KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE);
 
 #ifdef DBGPRINT_FILE_LOG
   /* On the assumption that we can now access disks start up the debug
@@ -557,10 +706,6 @@ ExpInitializeExecutive(VOID)
 
   PiInitDefaultLocale();
 
-  /*
-   * Start the motherboard enumerator (the HAL)
-   */
-  HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
 #if 0
   /*
    * Load boot start drivers
@@ -589,6 +734,24 @@ ExpInitializeExecutive(VOID)
    */
   InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
 
+  /* Create 'ReactOSInitDone' event */
+  RtlInitUnicodeString(&Name, L"\\ReactOSInitDone");
+  InitializeObjectAttributes(&ObjectAttributes,
+    &Name,
+    0,
+    NULL,
+    NULL);
+  Status = NtCreateEvent(&InitDoneEventHandle,
+    EVENT_ALL_ACCESS,
+    &ObjectAttributes,
+    FALSE,              /* Synchronization event */
+    FALSE);             /* Not signalled */
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status);
+      InitDoneEventHandle = INVALID_HANDLE_VALUE;
+    }
+
   /*
    *  Launch initial process
    */
@@ -596,19 +759,67 @@ ExpInitializeExecutive(VOID)
                                 &ThreadHandle);
   if (!NT_SUCCESS(Status))
     {
-      KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
+      KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
     }
 
-  /*
-   * Crash the system if the initial process terminates within 5 seconds.
-   */
-  Timeout.QuadPart = -50000000LL;
-  Status = NtWaitForSingleObject(ProcessHandle,
-                                FALSE,
-                                &Timeout);
-  if (Status != STATUS_TIMEOUT)
+  if (InitDoneEventHandle != INVALID_HANDLE_VALUE)
+    {
+      HANDLE Handles[2]; /* Init event, Initial process */
+
+      Handles[0] = InitDoneEventHandle;
+      Handles[1] = ProcessHandle;
+
+      /* Wait for the system to be initialized */
+      Timeout.QuadPart = -1200000000LL;  /* 120 second timeout */
+      Status = NtWaitForMultipleObjects(((LONG) sizeof(Handles) / sizeof(HANDLE)),
+        Handles,
+        WaitAny,
+        FALSE,    /* Non-alertable */
+        &Timeout);
+      if (!NT_SUCCESS(Status))
+        {
+          DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status);
+        }
+      else if (Status == STATUS_TIMEOUT)
+        {
+          DPRINT1("WARNING: System not initialized after 120 seconds.\n");
+        }
+      else if (Status == STATUS_WAIT_0 + 1)
+        {
+          /*
+           * Crash the system if the initial process was terminated.
+           */
+          KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
+        }
+
+      if (!NoBootScreen)
+        {
+          InbvEnableBootDriver(FALSE);
+        }
+
+      NtSetEvent(InitDoneEventHandle, NULL);
+
+      NtClose(InitDoneEventHandle);
+    }
+  else
     {
-      KeBugCheckEx(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
+      /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */
+      if (!NoBootScreen)
+        {
+          InbvEnableBootDriver(FALSE);
+        }
+
+      /*
+       * Crash the system if the initial process terminates within 5 seconds.
+       */
+      Timeout.QuadPart = -50000000LL;
+      Status = NtWaitForSingleObject(ProcessHandle,
+                                FALSE,
+                                &Timeout);
+      if (Status != STATUS_TIMEOUT)
+        {
+          KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
+        }
     }
 
   NtClose(ThreadHandle);
@@ -627,14 +838,14 @@ KiSystemStartup(BOOLEAN BootProcessor)
     {
       /* Never returns */
       ExpInitializeExecutive();
-      KeBugCheck(0);
+      KEBUGCHECK(0);
     }
   /* Do application processor initialization */
   KeApplicationProcessorInit();
   PsApplicationProcessorInit();
   KeLowerIrql(PASSIVE_LEVEL);
   PsIdleThreadMain(NULL);
-  KeBugCheck(0);
+  KEBUGCHECK(0);
   for(;;);
 }