Fixed prototype for MmSetAddressRangeModified().
[reactos.git] / ntoskrnl / ke / main.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS kernel
22  * FILE:            ntoskrnl/ke/main.c
23  * PURPOSE:         Initalizes the kernel
24  * PROGRAMMER:      David Welch (welch@cwcom.net)
25  * UPDATE HISTORY:
26  *                28/05/98: Created
27  */
28
29 /* INCLUDES *****************************************************************/
30
31 #define NTOS_MODE_KERNEL
32 #include <ntos.h>
33 #include <internal/ntoskrnl.h>
34 #include <reactos/resource.h>
35 #include <internal/mm.h>
36 #include <internal/ifs.h>
37 #include <internal/module.h>
38 #include <internal/ldr.h>
39 #include <internal/ex.h>
40 #include <internal/ps.h>
41 #include <internal/ke.h>
42 #include <internal/io.h>
43 #include <internal/po.h>
44 #include <internal/cc.h>
45 #include <internal/se.h>
46 #include <internal/v86m.h>
47 #include <internal/kd.h>
48 #include <internal/trap.h>
49 #include "../dbg/kdb.h"
50 #include <internal/registry.h>
51 #include <internal/nls.h>
52 #include <reactos/bugcodes.h>
53 #include <ntos/bootvid.h>
54 #include <napi/core.h>
55
56 #ifdef HALDBG
57 #include <internal/ntosdbg.h>
58 #else
59 #define ps(args...)
60 #endif
61
62 #define NDEBUG
63 #include <internal/debug.h>
64
65 /* GLOBALS *******************************************************************/
66
67 ULONG EXPORTED NtBuildNumber = KERNEL_VERSION_BUILD;
68 ULONG EXPORTED NtGlobalFlag = 0;
69 CHAR  EXPORTED KeNumberProcessors;
70 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
71 ULONG EXPORTED KeDcacheFlushCount = 0;
72 ULONG EXPORTED KeIcacheFlushCount = 0;
73 static LOADER_MODULE KeLoaderModules[64];
74 static UCHAR KeLoaderModuleStrings[64][256];
75 static UCHAR KeLoaderCommandLine[256];
76 static ADDRESS_RANGE KeMemoryMap[64];
77 static ULONG KeMemoryMapRangeCount;
78 static ULONG FirstKrnlPhysAddr;
79 static ULONG LastKrnlPhysAddr;
80 static ULONG LastKernelAddress;
81 volatile BOOLEAN Initialized = FALSE;
82 extern ULONG MmCoreDumpType;
83
84 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
85
86
87 /* FUNCTIONS ****************************************************************/
88
89 static BOOLEAN
90 RtlpCheckFileNameExtension(PCHAR FileName,
91                            PCHAR Extension)
92 {
93   PCHAR Ext;
94
95   Ext = strrchr(FileName, '.');
96   if (Ext == NULL)
97     {
98       if ((Extension == NULL) || (*Extension == 0))
99         return TRUE;
100       else
101         return FALSE;
102     }
103
104   if (*Extension != '.')
105     Ext++;
106
107   if (_stricmp(Ext, Extension) == 0)
108     return TRUE;
109   else
110     return FALSE;
111 }
112
113
114 static VOID
115 InitSystemSharedUserPage (PCSZ ParameterLine)
116 {
117    UNICODE_STRING ArcDeviceName;
118    UNICODE_STRING ArcName;
119    UNICODE_STRING BootPath;
120    UNICODE_STRING DriveDeviceName;
121    UNICODE_STRING DriveName;
122    WCHAR DriveNameBuffer[20];
123    PCHAR ParamBuffer;
124    PWCHAR ArcNameBuffer;
125    PCHAR p;
126    NTSTATUS Status;
127    ULONG Length;
128    OBJECT_ATTRIBUTES ObjectAttributes;
129    HANDLE Handle;
130    ULONG i;
131    BOOLEAN BootDriveFound;
132
133    /*
134     * NOTE:
135     *   The shared user page has been zeroed-out right after creation.
136     *   There is NO need to do this again.
137     */
138
139    SharedUserData->NtProductType = NtProductWinNt;
140
141    BootDriveFound = FALSE;
142
143    /*
144     * Retrieve the current dos system path
145     * (e.g.: C:\reactos) from the given arc path
146     * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
147     * Format: "<arc_name>\<path> [options...]"
148     */
149
150    /* create local parameter line copy */
151    ParamBuffer = ExAllocatePool (PagedPool, 256);
152    strcpy (ParamBuffer, (char *)ParameterLine);
153    DPRINT("%s\n", ParamBuffer);
154
155    /* cut options off */
156    p = strchr (ParamBuffer, ' ');
157    if (p)
158      {
159         *p = 0;
160      }
161    DPRINT("%s\n", ParamBuffer);
162
163    /* extract path */
164    p = strchr (ParamBuffer, '\\');
165    if (p)
166      {
167        DPRINT("Boot path: %s\n", p);
168        RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
169        *p = 0;
170      }
171    else
172      {
173        DPRINT("Boot path: %s\n", "\\");
174        RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
175      }
176    DPRINT("Arc name: %s\n", ParamBuffer);
177    
178    /* Only arc name left - build full arc name */
179    ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
180    swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer);
181    RtlInitUnicodeString (&ArcName, ArcNameBuffer);
182    DPRINT("Arc name: %wZ\n", &ArcName);
183
184    /* free ParamBuffer */
185    ExFreePool (ParamBuffer);
186
187    /* allocate arc device name string */
188    ArcDeviceName.Length = 0;
189    ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
190    ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
191
192    InitializeObjectAttributes (&ObjectAttributes,
193                                &ArcName,
194                                OBJ_OPENLINK,
195                                NULL,
196                                NULL);
197
198    Status = NtOpenSymbolicLinkObject (&Handle,
199                                       SYMBOLIC_LINK_ALL_ACCESS,
200                                       &ObjectAttributes);
201    RtlFreeUnicodeString (&ArcName);
202    if (!NT_SUCCESS(Status))
203      {
204         RtlFreeUnicodeString (&BootPath);
205         RtlFreeUnicodeString (&ArcDeviceName);
206         CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n",
207                  Status);
208
209         KEBUGCHECK (0x0);
210      }
211
212    Status = NtQuerySymbolicLinkObject (Handle,
213                                        &ArcDeviceName,
214                                        &Length);
215    NtClose (Handle);
216    if (!NT_SUCCESS(Status))
217      {
218         RtlFreeUnicodeString (&BootPath);
219         RtlFreeUnicodeString (&ArcDeviceName);
220         CPRINT("NtQuerySymbolicObject() failed (Status %x)\n",
221                  Status);
222
223         KEBUGCHECK (0x0);
224      }
225    DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
226
227
228    /* allocate device name string */
229    DriveDeviceName.Length = 0;
230    DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
231    DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
232
233    for (i = 0; i < 26; i++)
234      {
235         swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
236         RtlInitUnicodeString (&DriveName,
237                               DriveNameBuffer);
238
239         InitializeObjectAttributes (&ObjectAttributes,
240                                     &DriveName,
241                                     OBJ_OPENLINK,
242                                     NULL,
243                                     NULL);
244
245         Status = NtOpenSymbolicLinkObject (&Handle,
246                                            SYMBOLIC_LINK_ALL_ACCESS,
247                                            &ObjectAttributes);
248         if (!NT_SUCCESS(Status))
249           {
250              DPRINT("Failed to open link %wZ\n",
251                     &DriveName);
252              continue;
253           }
254
255         Status = NtQuerySymbolicLinkObject (Handle,
256                                             &DriveDeviceName,
257                                             &Length);
258         if (!NT_SUCCESS(Status))
259           {
260              DPRINT("Failed query open link %wZ\n",
261                     &DriveName);
262              continue;
263           }
264         DPRINT("Opened link: %wZ ==> %wZ\n",
265                &DriveName, &DriveDeviceName);
266
267         if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE))
268           {
269              DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
270              swprintf(SharedUserData->NtSystemRoot,
271                       L"%C:%wZ", 'A' + i, &BootPath);
272              
273              BootDriveFound = TRUE;
274           }
275
276         NtClose (Handle);
277      }
278
279    RtlFreeUnicodeString (&BootPath);
280    RtlFreeUnicodeString (&DriveDeviceName);
281    RtlFreeUnicodeString (&ArcDeviceName);
282
283    DPRINT("DosDeviceMap: 0x%x\n", SharedUserData->DosDeviceMap);
284
285    if (BootDriveFound == FALSE)
286      {
287         DbgPrint("No system drive found!\n");
288         KEBUGCHECK (0x0);
289      }
290 }
291
292 VOID STATIC
293 MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
294 {
295   PHYSICAL_ADDRESS Page;
296   ULONG i;
297
298   for (i = 0; i < PAGE_ROUND_UP(Length)/PAGE_SIZE; i++)
299   {
300      Page = MmGetPhysicalAddressForProcess(NULL, StartAddress + i * PAGE_SIZE);
301      MmDeleteVirtualMapping(NULL, StartAddress + i * PAGE_SIZE, FALSE, NULL, NULL);
302      MmDereferencePage(Page);
303   }
304 }
305
306 VOID
307 ExpInitializeExecutive(VOID)
308 {
309   LARGE_INTEGER Timeout;
310   HANDLE ProcessHandle;
311   HANDLE ThreadHandle;
312   ULONG BootDriverCount;
313   ULONG i;
314   ULONG start;
315   ULONG length;
316   PCHAR name;
317   CHAR str[50];
318   NTSTATUS Status;
319   BOOLEAN SetupBoot;
320   PCHAR p1, p2;
321   ULONG MaxMem;
322   BOOLEAN NoBootScreen = FALSE;
323   UNICODE_STRING Name;
324   HANDLE InitDoneEventHandle;
325   OBJECT_ATTRIBUTES ObjectAttributes;
326
327   /*
328    * Fail at runtime if someone has changed various structures without
329    * updating the offsets used for the assembler code.
330    */
331   assert(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
332   assert(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
333   assert(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
334   assert(FIELD_OFFSET(KTHREAD, ServiceTable) == KTHREAD_SERVICE_TABLE);
335   assert(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
336   assert(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
337   assert(FIELD_OFFSET(KTHREAD, CallbackStack) == KTHREAD_CALLBACK_STACK);
338   assert(FIELD_OFFSET(ETHREAD, ThreadsProcess) == ETHREAD_THREADS_PROCESS);
339   assert(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == 
340          KPROCESS_DIRECTORY_TABLE_BASE);
341   assert(FIELD_OFFSET(KPROCESS, IopmOffset) == KPROCESS_IOPM_OFFSET);
342   assert(FIELD_OFFSET(KPROCESS, LdtDescriptor) == KPROCESS_LDT_DESCRIPTOR0);
343   assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
344   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
345   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
346
347   assert(FIELD_OFFSET(KPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST);
348   assert(FIELD_OFFSET(KPCR, Self) == KPCR_SELF);
349   assert(FIELD_OFFSET(IKPCR, Tib.ExceptionList) == KPCR_EXCEPTION_LIST);
350   assert(FIELD_OFFSET(IKPCR, Self) == KPCR_SELF);
351   assert(FIELD_OFFSET(IKPCR, CurrentThread) == KPCR_CURRENT_THREAD);  
352
353   LdrInit1();
354
355   KeLowerIrql(DISPATCH_LEVEL);
356   
357   NtEarlyInitVdm();
358
359   p1 = (PCHAR)KeLoaderBlock.CommandLine;
360
361   MaxMem = 0;
362   while(*p1 && (p2 = strchr(p1, '/')))
363   {
364      p2++;
365      if (!_strnicmp(p2, "MAXMEM", 6))
366      {
367         p2 += 6;
368         while (isspace(*p2)) p2++;
369         if (*p2 == '=')
370         {
371            p2++;
372            while(isspace(*p2)) p2++;
373            if (isdigit(*p2))
374            {
375               while (isdigit(*p2))
376               {
377                  MaxMem = MaxMem * 10 + *p2 - '0';
378                  p2++;
379               }
380               break;
381            }
382         }
383      }
384     else if (!_strnicmp(p2, "NOBOOTSCREEN", 12))
385       {
386         p2 += 12;
387         NoBootScreen = TRUE;
388       }
389      else if (!_strnicmp(p2, "CRASHDUMP", 9))
390       {
391         p2 += 9;
392         if (*p2 == ':')
393           {
394             p2++;
395             if (!_strnicmp(p2, "FULL", 4))
396               {
397                 MmCoreDumpType = MM_CORE_DUMP_TYPE_FULL;
398               }
399             else
400               {
401                 MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE;
402               }     
403           }
404       }
405      p1 = p2;
406   }
407
408   MmInit1(FirstKrnlPhysAddr,
409           LastKrnlPhysAddr,
410           LastKernelAddress,
411           (PADDRESS_RANGE)&KeMemoryMap,
412           KeMemoryMapRangeCount,
413           MaxMem > 8 ? MaxMem : 4096);
414
415   /* Import ANSI code page table */
416   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
417     {
418       start = KeLoaderModules[i].ModStart;
419       length = KeLoaderModules[i].ModEnd - start;
420
421       name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
422       if (name == NULL)
423         {
424           name = (PCHAR)KeLoaderModules[i].String;
425         }
426       else
427         {
428           name++;
429         }
430
431       if (!_stricmp (name, "ansi.nls"))
432         {
433           RtlpImportAnsiCodePage((PUSHORT)start, length);
434         }
435     }
436
437   /* Import OEM code page table */
438   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
439     {
440       start = KeLoaderModules[i].ModStart;
441       length = KeLoaderModules[i].ModEnd - start;
442
443       name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
444       if (name == NULL)
445         {
446           name = (PCHAR)KeLoaderModules[i].String;
447         }
448       else
449         {
450           name++;
451         }
452
453       if (!_stricmp (name, "oem.nls"))
454         {
455           RtlpImportOemCodePage((PUSHORT)start, length);
456         }
457     }
458
459   /* Import Unicode casemap table */
460   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
461     {
462       start = KeLoaderModules[i].ModStart;
463       length = KeLoaderModules[i].ModEnd - start;
464
465       name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
466       if (name == NULL)
467         {
468           name = (PCHAR)KeLoaderModules[i].String;
469         }
470       else
471         {
472           name++;
473         }
474
475       if (!_stricmp (name, "casemap.nls"))
476         {
477           RtlpImportUnicodeCasemap((PUSHORT)start, length);
478         }
479     }
480
481   /* Create initial NLS tables */
482   RtlpCreateInitialNlsTables();
483
484   /*
485    * Initialize the kernel debugger
486    */
487   KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
488
489   MmInit2();
490   KeInit2();
491   
492   KeLowerIrql(PASSIVE_LEVEL);
493
494   if (!SeInit1())
495     KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
496
497   ObInit();
498
499   if (!SeInit2())
500     KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
501
502   PiInitProcessManager();
503
504   KdInit1();
505
506   if (KdPollBreakIn ())
507     {
508       DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
509     }
510
511   /* Initialize all processors */
512   KeNumberProcessors = 0;
513
514   while (!HalAllProcessorsStarted())
515     {
516       PVOID ProcessorStack;
517
518       if (KeNumberProcessors != 0)
519         {
520           KePrepareForApplicationProcessorInit(KeNumberProcessors);
521           PsPrepareForApplicationProcessorInit(KeNumberProcessors);
522         }
523       /* Allocate a stack for use when booting the processor */
524       /* FIXME: The nonpaged memory for the stack is not released after use */
525       ProcessorStack = 
526         ExAllocatePool(NonPagedPool, MM_STACK_SIZE) + MM_STACK_SIZE;
527       Ki386InitialStackArray[((int)KeNumberProcessors)] = 
528         (PVOID)(ProcessorStack - MM_STACK_SIZE);
529       HalInitializeProcessor(KeNumberProcessors, ProcessorStack);
530       KeNumberProcessors++;
531     }
532
533   /*
534    * Initialize various critical subsystems
535    */
536   HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
537
538   ExInit();
539   IoInit();
540   PoInit();
541   LdrInitModuleManagement();
542   CmInitializeRegistry();
543   NtInit();
544   MmInit3();
545   CcInit();
546   KdInit2();
547   FsRtlpInitFileLockingImplementation();
548
549   /* Report all resources used by hal */
550   HalReportResourceUsage();  
551
552   /*
553    * Clear the screen to blue
554    */
555   HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
556
557   /*
558    * Display version number and copyright/warranty message
559    */
560   HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build "
561                    KERNEL_VERSION_BUILD_STR")\n");
562   HalDisplayString(RES_STR_LEGAL_COPYRIGHT);
563   HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
564                    "Public License, and you\n");
565   HalDisplayString("are welcome to change it and/or distribute copies of it "
566                    "under certain\n"); 
567   HalDisplayString("conditions. There is absolutely no warranty for "
568                    "ReactOS.\n\n");
569
570   if (KeNumberProcessors > 1)
571     {
572       sprintf(str,
573               "Found %d system processors. [%lu MB Memory]\n",
574               KeNumberProcessors,
575               (KeLoaderBlock.MemHigher + 1088)/ 1024);
576     }
577   else
578     {
579       sprintf(str,
580               "Found 1 system processor. [%lu MB Memory]\n",
581               (KeLoaderBlock.MemHigher + 1088)/ 1024);
582     }
583   HalDisplayString(str);
584
585   KdInit3();
586
587
588   /* Create the NLS section */
589   RtlpCreateNlsSection();
590
591   /*
592    * Initalize services loaded at boot time
593    */
594   DPRINT("%d files loaded\n",KeLoaderBlock.ModsCount);
595   for (i=0; i < KeLoaderBlock.ModsCount; i++)
596     {
597       CPRINT("Module: '%s' at %08lx, length 0x%08lx\n",
598        KeLoaderModules[i].String,
599        KeLoaderModules[i].ModStart,
600        KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
601     }
602
603   /* Pass 1: import system hive registry chunk */
604   SetupBoot = TRUE;
605   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
606     {
607       start = KeLoaderModules[i].ModStart;
608       length = KeLoaderModules[i].ModEnd - start;
609
610       DPRINT("Module: '%s'\n", (PCHAR)KeLoaderModules[i].String);
611       name = strrchr((PCHAR)KeLoaderModules[i].String, '\\');
612       if (name == NULL)
613         {
614           name = (PCHAR)KeLoaderModules[i].String;
615         }
616       else
617         {
618           name++;
619         }
620
621       if (!_stricmp (name, "system") ||
622           !_stricmp (name, "system.hiv"))
623         {
624           CPRINT("Process system hive registry chunk at %08lx\n", start);
625           SetupBoot = FALSE;
626           CmImportSystemHive((PCHAR)start, length);
627         }
628     }
629
630   /* Pass 2: import hardware hive registry chunk */
631   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
632     {
633       start = KeLoaderModules[i].ModStart;
634       length = KeLoaderModules[i].ModEnd - start;
635       name = (PCHAR)KeLoaderModules[i].String;
636       if (!_stricmp (name, "hardware") ||
637           !_stricmp (name, "hardware.hiv"))
638         {
639           CPRINT("Process hardware hive registry chunk at %08lx\n", start);
640           CmImportHardwareHive((PCHAR)start, length);
641         }
642     }
643
644   /* Create dummy keys if no hardware hive was found */
645   CmImportHardwareHive (NULL, 0);
646
647   /* Initialize volatile registry settings */
648   if (SetupBoot == FALSE)
649     {
650       CmInit2((PCHAR)KeLoaderBlock.CommandLine);
651     }
652
653   /*
654    * Enter the kernel debugger before starting up the boot drivers
655    */
656 #ifdef KDBG
657   KdbEnter();
658 #endif /* KDBG */
659
660   IoCreateDriverList();
661
662   IoInit2();
663
664   /* Pass 3: process boot loaded drivers */
665   BootDriverCount = 0;
666   for (i=1; i < KeLoaderBlock.ModsCount; i++)
667     {
668       start = KeLoaderModules[i].ModStart;
669       length = KeLoaderModules[i].ModEnd - start;
670       name = (PCHAR)KeLoaderModules[i].String;
671       if (RtlpCheckFileNameExtension(name, ".sys") ||
672           RtlpCheckFileNameExtension(name, ".sym"))
673         {
674           CPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
675                  name, start, length);
676           LdrInitializeBootStartDriver((PVOID)start, name, length);
677         }
678       if (RtlpCheckFileNameExtension(name, ".sys"))
679         BootDriverCount++;
680     }
681
682   /* Pass 4: free memory for all boot files, except ntoskrnl.exe and hal.dll */
683   for (i = 2; i < KeLoaderBlock.ModsCount; i++)
684     {
685 #ifdef KDBG
686        /* Do not free the memory from symbol files, if the kernel debugger is activ */
687        if (!RtlpCheckFileNameExtension(name, ".sym"))
688 #endif
689          {
690            MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
691                                   KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
692          }
693     }
694
695   if (BootDriverCount == 0)
696     {
697       DbgPrint("No boot drivers available.\n");
698       KEBUGCHECK(0);
699     }
700
701   /* Display the boot screen image if not disabled */
702   if (!NoBootScreen)
703     {
704       InbvEnableBootDriver(TRUE);
705     }
706
707   /* Create ARC names for boot devices */
708   IoCreateArcNames();
709
710   /* Create the SystemRoot symbolic link */
711   CPRINT("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
712   Status = IoCreateSystemRootLink((PUCHAR)KeLoaderBlock.CommandLine);
713   if (!NT_SUCCESS(Status))
714     KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE);
715
716 #ifdef DBGPRINT_FILE_LOG
717   /* On the assumption that we can now access disks start up the debug
718      logger thread */
719   DebugLogInit2();
720 #endif /* DBGPRINT_FILE_LOG */
721
722 #ifdef KDBG
723   KdbInitProfiling2();
724 #endif /* KDBG */
725
726   PiInitDefaultLocale();
727
728 #if 0
729   /*
730    * Load boot start drivers
731    */
732   IopLoadBootStartDrivers();
733 #else
734   /*
735    * Load Auto configured drivers
736    */
737   LdrLoadAutoConfigDrivers();
738 #endif
739
740   IoDestroyDriverList();
741
742   /*
743    * Assign drive letters
744    */
745   IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock,
746                         NULL,
747                         NULL,
748                         NULL);
749
750   /*
751    * Initialize shared user page:
752    *  - set dos system path, dos device map, etc.
753    */
754   InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
755
756   /* Create 'ReactOSInitDone' event */
757   RtlInitUnicodeString(&Name, L"\\ReactOSInitDone");
758   InitializeObjectAttributes(&ObjectAttributes,
759     &Name,
760     0,
761     NULL,
762     NULL);
763   Status = NtCreateEvent(&InitDoneEventHandle,
764     EVENT_ALL_ACCESS,
765     &ObjectAttributes,
766     FALSE,              /* Synchronization event */
767     FALSE);             /* Not signalled */
768   if (!NT_SUCCESS(Status))
769     {
770       DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status);
771       InitDoneEventHandle = INVALID_HANDLE_VALUE;
772     }
773
774   /*
775    *  Launch initial process
776    */
777   Status = LdrLoadInitialProcess(&ProcessHandle,
778                                  &ThreadHandle);
779   if (!NT_SUCCESS(Status))
780     {
781       KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
782     }
783
784   if (InitDoneEventHandle != INVALID_HANDLE_VALUE)
785     {
786       HANDLE Handles[2]; /* Init event, Initial process */
787
788       Handles[0] = InitDoneEventHandle;
789       Handles[1] = ProcessHandle;
790
791       /* Wait for the system to be initialized */
792       Timeout.QuadPart = -1200000000LL;  /* 120 second timeout */
793       Status = NtWaitForMultipleObjects(((LONG) sizeof(Handles) / sizeof(HANDLE)),
794         Handles,
795         WaitAny,
796         FALSE,    /* Non-alertable */
797         &Timeout);
798       if (!NT_SUCCESS(Status))
799         {
800           DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status);
801         }
802       else if (Status == STATUS_TIMEOUT)
803         {
804           DPRINT1("WARNING: System not initialized after 120 seconds.\n");
805         }
806       else if (Status == STATUS_WAIT_0 + 1)
807         {
808           /*
809            * Crash the system if the initial process was terminated.
810            */
811           KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
812         }
813
814       if (!NoBootScreen)
815         {
816           InbvEnableBootDriver(FALSE);
817         }
818
819       NtSetEvent(InitDoneEventHandle, NULL);
820
821       NtClose(InitDoneEventHandle);
822     }
823   else
824     {
825       /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */
826       if (!NoBootScreen)
827         {
828           InbvEnableBootDriver(FALSE);
829         }
830
831       /*
832        * Crash the system if the initial process terminates within 5 seconds.
833        */
834       Timeout.QuadPart = -50000000LL;
835       Status = NtWaitForSingleObject(ProcessHandle,
836                                  FALSE,
837                                  &Timeout);
838       if (Status != STATUS_TIMEOUT)
839         {
840           KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
841         }
842     }
843
844   NtClose(ThreadHandle);
845   NtClose(ProcessHandle);
846
847   PsTerminateSystemThread(STATUS_SUCCESS);
848 }
849
850
851 VOID
852 KiSystemStartup(BOOLEAN BootProcessor)
853 {
854   HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
855
856   if (BootProcessor)
857     {
858       /* Never returns */
859       ExpInitializeExecutive();
860       KEBUGCHECK(0);
861     }
862   /* Do application processor initialization */
863   KeApplicationProcessorInit();
864   PsApplicationProcessorInit();
865   KeLowerIrql(PASSIVE_LEVEL);
866   PsIdleThreadMain(NULL);
867   KEBUGCHECK(0);
868   for(;;);
869 }
870
871 VOID
872 _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
873 /*
874  * FUNCTION: Called by the boot loader to start the kernel
875  * ARGUMENTS:
876  *          LoaderBlock = Pointer to boot parameters initialized by the boot 
877  *                        loader
878  * NOTE: The boot parameters are stored in low memory which will become
879  * invalid after the memory managment is initialized so we make a local copy.
880  */
881 {
882   ULONG i;
883   ULONG size;
884   ULONG last_kernel_address;
885   extern ULONG _bss_end__;
886   ULONG HalBase;
887   ULONG DriverBase;
888   ULONG DriverSize;
889
890   /* Low level architecture specific initialization */
891   KeInit1();
892
893   /*
894    * Copy the parameters to a local buffer because lowmem will go away
895    */
896   memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
897   memcpy(&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr,
898          sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
899   KeLoaderBlock.ModsCount++;
900   KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
901
902   /*
903    * Convert a path specification in the grub format to one understood by the
904    * rest of the kernel.
905    */
906   if (((PUCHAR)_LoaderBlock->CommandLine)[0] == '(')
907     {
908       ULONG DiskNumber = 0, PartNumber = 0;
909       PCH p;
910       CHAR Temp[256];
911       PCH options;
912       PCH s1;
913
914       if (((PUCHAR)_LoaderBlock->CommandLine)[1] == 'h' &&
915           ((PUCHAR)_LoaderBlock->CommandLine)[2] == 'd')
916         {
917           DiskNumber = ((PUCHAR)_LoaderBlock->CommandLine)[3] - '0';
918           PartNumber = ((PUCHAR)_LoaderBlock->CommandLine)[5] - '0';
919         }
920       strcpy(Temp, &((PUCHAR)_LoaderBlock->CommandLine)[7]);
921       if ((options = strchr(Temp, ' ')) != NULL)
922         {
923           *options = 0;
924           options++;
925         }
926       else
927         {
928           options = "";
929         }
930       if ((s1 = strrchr(Temp, '/')) != NULL)
931         {
932           *s1 = 0;
933           if ((s1 = strrchr(Temp, '/')) != NULL)
934             {
935               *s1 = 0;
936             }
937         }
938       sprintf(KeLoaderCommandLine, 
939               "multi(0)disk(0)rdisk(%lu)partition(%lu)%s %s",
940               DiskNumber, PartNumber + 1, Temp, options);
941
942       p = KeLoaderCommandLine;
943       while (*p != 0 && *p != ' ')
944         {
945           if ((*p) == '/')
946             {
947               (*p) = '\\';
948             }
949           p++;
950         }
951       DPRINT1("Command Line: %s\n", KeLoaderCommandLine);
952     }
953   else
954     {
955       strcpy(KeLoaderCommandLine, (PUCHAR)_LoaderBlock->CommandLine);
956     }
957   KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
958   
959   strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
960   KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
961   KeLoaderModules[0].ModStart = 0xC0000000;
962   KeLoaderModules[0].ModEnd = PAGE_ROUND_UP((ULONG)&_bss_end__);
963   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
964     {      
965       CHAR* s;
966       if ((s = strrchr((PUCHAR)KeLoaderModules[i].String, '/')) != 0)
967         {
968           strcpy(KeLoaderModuleStrings[i], s + 1);
969         }
970       else
971         {
972           strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
973         }
974       KeLoaderModules[i].ModStart -= 0x200000;
975       KeLoaderModules[i].ModStart += 0xc0000000;
976       KeLoaderModules[i].ModEnd -= 0x200000;
977       KeLoaderModules[i].ModEnd += 0xc0000000;
978       KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
979     }
980
981 #ifdef HAL_DBG
982   HalnInitializeDisplay((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
983 #endif
984
985   HalBase = KeLoaderModules[1].ModStart;
986   DriverBase = 
987     PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd);
988
989   /*
990    * Process hal.dll
991    */
992   LdrSafePEProcessModule((PVOID)HalBase, (PVOID)DriverBase, (PVOID)0xC0000000, &DriverSize);
993
994   LdrHalBase = (ULONG_PTR)DriverBase;
995   last_kernel_address = DriverBase + DriverSize;
996
997   /*
998    * Process ntoskrnl.exe
999    */
1000   LdrSafePEProcessModule((PVOID)0xC0000000, (PVOID)0xC0000000, (PVOID)DriverBase, &DriverSize);
1001
1002   FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000;
1003   LastKrnlPhysAddr = last_kernel_address - 0xc0000000 + 0x200000;
1004   LastKernelAddress = last_kernel_address;
1005
1006 #ifndef ACPI
1007   /* FIXME: VMware does not like it when ReactOS is using the BIOS memory map */
1008   KeLoaderBlock.Flags &= ~MB_FLAGS_MMAP_INFO;
1009 #endif
1010
1011   KeMemoryMapRangeCount = 0;
1012   if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
1013     {
1014       /* We have a memory map from the nice BIOS */
1015       size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
1016       i = 0;
1017       while (i < KeLoaderBlock.MmapLength)
1018         {
1019           memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
1020             (PVOID)(KeLoaderBlock.MmapAddr + i),
1021                   sizeof(ADDRESS_RANGE));
1022           KeMemoryMapRangeCount++;
1023           i += size;
1024         }
1025     }
1026   
1027   KiSystemStartup(1);
1028 }
1029
1030 /* EOF */
1031