branch update for HEAD-2003021201
[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 #include <ddk/ntddk.h>
32 #include <internal/ntoskrnl.h>
33 #include <reactos/resource.h>
34 #include <internal/mm.h>
35 #include <internal/ifs.h>
36 #include <internal/module.h>
37 #include <internal/ldr.h>
38 #include <internal/ex.h>
39 #include <internal/ps.h>
40 #include <internal/ke.h>
41 #include <internal/io.h>
42 #include <internal/po.h>
43 #include <internal/cc.h>
44 #include <internal/se.h>
45 #include <internal/v86m.h>
46 #include <internal/kd.h>
47 #include <internal/trap.h>
48 #include "../dbg/kdb.h"
49 #include <internal/registry.h>
50 #include <reactos/bugcodes.h>
51
52 #ifdef HALDBG
53 #include <internal/ntosdbg.h>
54 #else
55 #define ps(args...)
56 #endif
57
58 #define NDEBUG
59 #include <internal/debug.h>
60
61 /* GLOBALS *******************************************************************/
62
63 ULONG EXPORTED NtBuildNumber = KERNEL_VERSION_BUILD;
64 ULONG EXPORTED NtGlobalFlag = 0;
65 CHAR  EXPORTED KeNumberProcessors;
66 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
67 ULONG EXPORTED KeDcacheFlushCount = 0;
68 ULONG EXPORTED KeIcacheFlushCount = 0;
69 static LOADER_MODULE KeLoaderModules[64];
70 static UCHAR KeLoaderModuleStrings[64][256];
71 static UCHAR KeLoaderCommandLine[256];
72 static ADDRESS_RANGE KeMemoryMap[64];
73 static ULONG KeMemoryMapRangeCount;
74 static ULONG FirstKrnlPhysAddr;
75 static ULONG LastKrnlPhysAddr;
76 static ULONG LastKernelAddress;
77 volatile BOOLEAN Initialized = FALSE;
78
79 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
80
81
82 /* FUNCTIONS ****************************************************************/
83
84 static BOOLEAN
85 RtlpCheckFileNameExtension(PCHAR FileName,
86                            PCHAR Extension)
87 {
88    PCHAR Ext;
89
90    Ext = strrchr(FileName, '.');
91    if ((Extension == NULL) || (*Extension == 0))
92      {
93         if (Ext == NULL)
94           return TRUE;
95         else
96           return FALSE;
97      }
98    if (*Extension != '.')
99      Ext++;
100    
101    if (_stricmp(Ext, Extension) == 0)
102      return TRUE;
103    else
104      return FALSE;
105 }
106
107
108 static BOOLEAN
109 RtlpIsSystemHive(PCHAR FileName)
110 {
111   PCHAR Name;
112
113   Name = strrchr(FileName, '\\');
114   if (Name == NULL)
115   {
116     Name = FileName;
117   }
118   else
119   {
120     Name = Name + 1;
121   }
122
123   return((_stricmp(Name, "system.hiv") == 0) ||
124          (_stricmp(Name, "system") == 0));
125 }
126
127
128 static VOID
129 InitSystemSharedUserPage (PCSZ ParameterLine)
130 {
131    UNICODE_STRING ArcDeviceName;
132    UNICODE_STRING ArcName;
133    UNICODE_STRING BootPath;
134    UNICODE_STRING DriveDeviceName;
135    UNICODE_STRING DriveName;
136    WCHAR DriveNameBuffer[20];
137    PCHAR ParamBuffer;
138    PWCHAR ArcNameBuffer;
139    PCHAR p;
140    NTSTATUS Status;
141    ULONG Length;
142    OBJECT_ATTRIBUTES ObjectAttributes;
143    HANDLE Handle;
144    ULONG i;
145    BOOLEAN BootDriveFound;
146
147    /*
148     * NOTE:
149     *   The shared user page has been zeroed-out right after creation.
150     *   There is NO need to do this again.
151     */
152
153    SharedUserData->NtProductType = NtProductWinNt;
154
155    BootDriveFound = FALSE;
156
157    /*
158     * Retrieve the current dos system path
159     * (e.g.: C:\reactos) from the given arc path
160     * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
161     * Format: "<arc_name>\<path> [options...]"
162     */
163
164    /* create local parameter line copy */
165    ParamBuffer = ExAllocatePool (PagedPool, 256);
166    strcpy (ParamBuffer, (char *)ParameterLine);
167    DPRINT("%s\n", ParamBuffer);
168
169    /* cut options off */
170    p = strchr (ParamBuffer, ' ');
171    if (p)
172      {
173         *p = 0;
174      }
175    DPRINT("%s\n", ParamBuffer);
176
177    /* extract path */
178    p = strchr (ParamBuffer, '\\');
179    if (p)
180      {
181        DPRINT("Boot path: %s\n", p);
182        RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
183        *p = 0;
184      }
185    else
186      {
187        DPRINT("Boot path: %s\n", "\\");
188        RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
189      }
190    DPRINT("Arc name: %s\n", ParamBuffer);
191    
192    /* Only arc name left - build full arc name */
193    ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
194    swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer);
195    RtlInitUnicodeString (&ArcName, ArcNameBuffer);
196    DPRINT("Arc name: %wZ\n", &ArcName);
197
198    /* free ParamBuffer */
199    ExFreePool (ParamBuffer);
200
201    /* allocate arc device name string */
202    ArcDeviceName.Length = 0;
203    ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
204    ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
205
206    InitializeObjectAttributes (&ObjectAttributes,
207                                &ArcName,
208                                OBJ_OPENLINK,
209                                NULL,
210                                NULL);
211
212    Status = NtOpenSymbolicLinkObject (&Handle,
213                                       SYMBOLIC_LINK_ALL_ACCESS,
214                                       &ObjectAttributes);
215    RtlFreeUnicodeString (&ArcName);
216    if (!NT_SUCCESS(Status))
217      {
218         RtlFreeUnicodeString (&BootPath);
219         RtlFreeUnicodeString (&ArcDeviceName);
220         CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n",
221                  Status);
222
223         KeBugCheck (0x0);
224      }
225
226    Status = NtQuerySymbolicLinkObject (Handle,
227                                        &ArcDeviceName,
228                                        &Length);
229    NtClose (Handle);
230    if (!NT_SUCCESS(Status))
231      {
232         RtlFreeUnicodeString (&BootPath);
233         RtlFreeUnicodeString (&ArcDeviceName);
234         CPRINT("NtQuerySymbolicObject() failed (Status %x)\n",
235                  Status);
236
237         KeBugCheck (0x0);
238      }
239    DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
240
241
242    /* allocate device name string */
243    DriveDeviceName.Length = 0;
244    DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
245    DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
246
247    for (i = 0; i < 26; i++)
248      {
249         swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
250         RtlInitUnicodeString (&DriveName,
251                               DriveNameBuffer);
252
253         InitializeObjectAttributes (&ObjectAttributes,
254                                     &DriveName,
255                                     OBJ_OPENLINK,
256                                     NULL,
257                                     NULL);
258
259         Status = NtOpenSymbolicLinkObject (&Handle,
260                                            SYMBOLIC_LINK_ALL_ACCESS,
261                                            &ObjectAttributes);
262         if (!NT_SUCCESS(Status))
263           {
264              DPRINT("Failed to open link %wZ\n",
265                     &DriveName);
266              continue;
267           }
268
269         Status = NtQuerySymbolicLinkObject (Handle,
270                                             &DriveDeviceName,
271                                             &Length);
272         if (!NT_SUCCESS(Status))
273           {
274              DPRINT("Failed query open link %wZ\n",
275                     &DriveName);
276              continue;
277           }
278         DPRINT("Opened link: %wZ ==> %wZ\n",
279                &DriveName, &DriveDeviceName);
280
281         if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE))
282           {
283              DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
284              swprintf(SharedUserData->NtSystemRoot,
285                       L"%C:%wZ", 'A' + i, &BootPath);
286              
287              BootDriveFound = TRUE;
288           }
289
290         NtClose (Handle);
291      }
292
293    RtlFreeUnicodeString (&BootPath);
294    RtlFreeUnicodeString (&DriveDeviceName);
295    RtlFreeUnicodeString (&ArcDeviceName);
296
297    DPRINT("DosDeviceMap: 0x%x\n", SharedUserData->DosDeviceMap);
298
299    if (BootDriveFound == FALSE)
300      {
301         DbgPrint("No system drive found!\n");
302         KeBugCheck (0x0);
303      }
304 }
305
306
307 VOID
308 ExpInitializeExecutive(VOID)
309 {
310   LARGE_INTEGER Timeout;
311   HANDLE ProcessHandle;
312   HANDLE ThreadHandle;
313   ULONG BootDriverCount;
314   ULONG i;
315   ULONG start;
316   ULONG length;
317   PCHAR name;
318   CHAR str[50];
319   NTSTATUS Status;
320   BOOLEAN SetupBoot;
321
322   /*
323    * Fail at runtime if someone has changed various structures without
324    * updating the offsets used for the assembler code.
325    */
326   assert(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
327   assert(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
328   assert(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
329   assert(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
330   assert(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
331   assert(FIELD_OFFSET(KTHREAD, CallbackStack) == KTHREAD_CALLBACK_STACK);
332   assert(FIELD_OFFSET(ETHREAD, ThreadsProcess) == ETHREAD_THREADS_PROCESS);
333   assert(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == 
334          KPROCESS_DIRECTORY_TABLE_BASE);
335   assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
336   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
337   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
338   
339   assert(FIELD_OFFSET(KPCR, ExceptionList) == KPCR_EXCEPTION_LIST);
340   assert(FIELD_OFFSET(KPCR, Self) == KPCR_SELF);
341   assert(FIELD_OFFSET(KPCR, CurrentThread) == KPCR_CURRENT_THREAD);
342
343   LdrInit1();
344
345   KeLowerIrql(DISPATCH_LEVEL);
346   
347   NtEarlyInitVdm();
348   
349   MmInit1(FirstKrnlPhysAddr,
350           LastKrnlPhysAddr,
351           LastKernelAddress,
352           (PADDRESS_RANGE)&KeMemoryMap,
353           KeMemoryMapRangeCount);
354   
355   /* create default nls tables */
356   RtlpInitNlsTables();
357   
358   /*
359    * Initialize the kernel debugger
360    */
361   KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
362
363   MmInit2();
364   KeInit2();
365   
366   KeLowerIrql(PASSIVE_LEVEL);
367
368   if (!SeInit1())
369     KeBugCheck(SECURITY_INITIALIZATION_FAILED);
370
371   ObInit();
372
373   if (!SeInit2())
374     KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
375
376   PiInitProcessManager();
377
378   KdInit1();
379
380   if (KdPollBreakIn ())
381     {
382       DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
383     }
384
385   /*
386    * Display version number and copyright/warranty message
387    */
388   HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build "
389                    KERNEL_VERSION_BUILD_STR")\n");
390   HalDisplayString(RES_STR_LEGAL_COPYRIGHT);
391   HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
392                    "Public License, and you\n");
393   HalDisplayString("are welcome to change it and/or distribute copies of it "
394                    "under certain\n"); 
395   HalDisplayString("conditions. There is absolutely no warranty for "
396                    "ReactOS.\n\n");
397
398   /* Initialize all processors */
399   KeNumberProcessors = 0;
400
401   while (!HalAllProcessorsStarted())
402     {
403       PVOID ProcessorStack;
404
405       if (KeNumberProcessors != 0)
406         {
407           KePrepareForApplicationProcessorInit(KeNumberProcessors);
408           PsPrepareForApplicationProcessorInit(KeNumberProcessors);
409         }
410       /* Allocate a stack for use when booting the processor */
411       /* FIXME: The nonpaged memory for the stack is not released after use */
412       ProcessorStack = 
413         ExAllocatePool(NonPagedPool, MM_STACK_SIZE) + MM_STACK_SIZE;
414       Ki386InitialStackArray[((int)KeNumberProcessors)] = 
415         (PVOID)(ProcessorStack - MM_STACK_SIZE);
416       HalInitializeProcessor(KeNumberProcessors, ProcessorStack);
417       KeNumberProcessors++;
418     }
419
420   if (KeNumberProcessors > 1)
421     {
422       sprintf(str,
423               "Found %d system processors. [%u MB Memory]\n",
424               KeNumberProcessors,
425               (KeLoaderBlock.MemHigher + 1088)/ 1024);
426     }
427   else
428     {
429       sprintf(str,
430               "Found 1 system processor. [%u MB Memory]\n",
431               (KeLoaderBlock.MemHigher + 1088)/ 1024);
432     }
433   HalDisplayString(str);
434
435   /*
436    * Initialize various critical subsystems
437    */
438   HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
439
440   ExInit();
441   IoInit();
442   PoInit();
443   LdrInitModuleManagement();
444   CmInitializeRegistry();
445   NtInit();
446   MmInit3();
447   CcInit();
448   KdInit2();
449   FsRtlpInitFileLockingImplementation();
450   
451   /* Report all resources used by hal */
452   HalReportResourceUsage();
453   
454   /*
455    * Initalize services loaded at boot time
456    */
457   DPRINT("%d files loaded\n",KeLoaderBlock.ModsCount);
458   for (i=0; i < KeLoaderBlock.ModsCount; i++)
459     {
460       CPRINT("Module: '%s' at %08lx, length 0x%08lx\n",
461        KeLoaderModules[i].String,
462        KeLoaderModules[i].ModStart,
463        KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
464     }
465
466   /*  Pass 1: load nls files  */
467   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
468     {
469       name = (PCHAR)KeLoaderModules[i].String;
470       if (RtlpCheckFileNameExtension(name, ".nls"))
471         {
472           ULONG Mod2Start = 0;
473           ULONG Mod2End = 0;
474           ULONG Mod3Start = 0;
475           ULONG Mod3End = 0;
476
477           name = (PCHAR)KeLoaderModules[i+1].String;
478           if (RtlpCheckFileNameExtension(name, ".nls"))
479             {
480               Mod2Start = (ULONG)KeLoaderModules[i+1].ModStart;
481               Mod2End = (ULONG)KeLoaderModules[i+1].ModEnd;
482
483               name = (PCHAR)KeLoaderModules[i+2].String;
484               if (RtlpCheckFileNameExtension(name, ".nls"))
485                 {
486                   Mod3Start = (ULONG)KeLoaderModules[i+2].ModStart;
487                   Mod3End = (ULONG)KeLoaderModules[i+2].ModEnd;
488                 }
489             }
490
491           /* Initialize nls sections */
492           RtlpInitNlsSections((ULONG)KeLoaderModules[i].ModStart,
493                               (ULONG)KeLoaderModules[i].ModEnd,
494                               Mod2Start,
495                               Mod2End,
496                               Mod3Start,
497                               Mod3End);
498           break;
499         }
500     }
501
502   /*  Pass 2: load registry chunks passed in  */
503   SetupBoot = TRUE;
504   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
505     {
506       start = KeLoaderModules[i].ModStart;
507       length = KeLoaderModules[i].ModEnd - start;
508       name = (PCHAR)KeLoaderModules[i].String;
509       if (RtlpCheckFileNameExtension(name, "") ||
510           RtlpCheckFileNameExtension(name, ".hiv"))
511         {
512           CPRINT("Process registry chunk at %08lx\n", start);
513           CmImportHive((PCHAR)start, length);
514         }
515       if (RtlpIsSystemHive(name))
516         {
517           SetupBoot = FALSE;
518         }
519     }
520
521   /* Initialize volatile registry settings */
522   if (SetupBoot == FALSE)
523     {
524       CmInit2((PCHAR)KeLoaderBlock.CommandLine);
525     }
526
527   /*
528    * Enter the kernel debugger before starting up the boot drivers
529    */
530 #ifdef KDBG
531   KdbEnter();
532 #endif /* KDBG */
533
534   IoCreateDriverList();
535
536   /*  Pass 3: process boot loaded drivers  */
537   BootDriverCount = 0;
538   for (i=1; i < KeLoaderBlock.ModsCount; i++)
539     {
540       start = KeLoaderModules[i].ModStart;
541       length = KeLoaderModules[i].ModEnd - start;
542       name = (PCHAR)KeLoaderModules[i].String;
543       if (RtlpCheckFileNameExtension(name, ".sys") ||
544           RtlpCheckFileNameExtension(name, ".sym"))
545         {
546           CPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
547                  name, start, length);
548           LdrInitializeBootStartDriver((PVOID)start, name, length);
549         }
550       if (RtlpCheckFileNameExtension(name, ".sys"))
551         BootDriverCount++;
552     }
553
554   if (BootDriverCount == 0)
555     {
556       DbgPrint("No boot drivers available.\n");
557       KeBugCheck(0);
558     }
559
560   /* Create ARC names for boot devices */
561   IoCreateArcNames();
562
563   /* Create the SystemRoot symbolic link */
564   CPRINT("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
565   Status = IoCreateSystemRootLink((PUCHAR)KeLoaderBlock.CommandLine);
566   if (!NT_SUCCESS(Status))
567     KeBugCheck(INACCESSIBLE_BOOT_DEVICE);
568
569 #ifdef DBGPRINT_FILE_LOG
570   /* On the assumption that we can now access disks start up the debug
571      logger thread */
572   DebugLogInit2();
573 #endif /* DBGPRINT_FILE_LOG */
574
575 #ifdef KDBG
576   KdbInitProfiling2();
577 #endif /* KDBG */
578
579
580   PiInitDefaultLocale();
581
582   /*
583    * Start the motherboard enumerator (the HAL)
584    */
585   HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
586 #if 0
587   /*
588    * Load boot start drivers
589    */
590   IopLoadBootStartDrivers();
591 #else
592   /*
593    * Load Auto configured drivers
594    */
595   LdrLoadAutoConfigDrivers();
596 #endif
597
598   IoDestroyDriverList();
599
600   /*
601    * Assign drive letters
602    */
603   IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock,
604                         NULL,
605                         NULL,
606                         NULL);
607
608   /*
609    * Initialize shared user page:
610    *  - set dos system path, dos device map, etc.
611    */
612   InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
613
614   /*
615    *  Launch initial process
616    */
617   Status = LdrLoadInitialProcess(&ProcessHandle,
618                                  &ThreadHandle);
619   if (!NT_SUCCESS(Status))
620     {
621       KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
622     }
623
624   /*
625    * Crash the system if the initial process terminates within 5 seconds.
626    */
627   Timeout.QuadPart = -50000000LL;
628   Status = NtWaitForSingleObject(ProcessHandle,
629                                  FALSE,
630                                  &Timeout);
631   if (Status != STATUS_TIMEOUT)
632     {
633       KeBugCheckEx(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
634     }
635
636   NtClose(ThreadHandle);
637   NtClose(ProcessHandle);
638
639   PsTerminateSystemThread(STATUS_SUCCESS);
640 }
641
642
643 VOID
644 KiSystemStartup(BOOLEAN BootProcessor)
645 {
646   HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
647
648   if (BootProcessor)
649     {
650       /* Never returns */
651       ExpInitializeExecutive();
652       KeBugCheck(0);
653     }
654   /* Do application processor initialization */
655   KeApplicationProcessorInit();
656   PsApplicationProcessorInit();
657   KeLowerIrql(PASSIVE_LEVEL);
658   PsIdleThreadMain(NULL);
659   KeBugCheck(0);
660   for(;;);
661 }
662
663 VOID
664 _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
665 /*
666  * FUNCTION: Called by the boot loader to start the kernel
667  * ARGUMENTS:
668  *          LoaderBlock = Pointer to boot parameters initialized by the boot 
669  *                        loader
670  * NOTE: The boot parameters are stored in low memory which will become
671  * invalid after the memory managment is initialized so we make a local copy.
672  */
673 {
674   ULONG i;
675   ULONG size;
676   ULONG last_kernel_address;
677   extern ULONG _bss_end__;
678   ULONG HalBase;
679   ULONG DriverBase;
680   ULONG DriverSize;
681
682   /* Low level architecture specific initialization */
683   KeInit1();
684
685   /*
686    * Copy the parameters to a local buffer because lowmem will go away
687    */
688   memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
689   memcpy(&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr,
690          sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
691   KeLoaderBlock.ModsCount++;
692   KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
693
694   /*
695    * Convert a path specification in the grub format to one understood by the
696    * rest of the kernel.
697    */
698   if (((PUCHAR)_LoaderBlock->CommandLine)[0] == '(')
699     {
700       ULONG DiskNumber = 0, PartNumber = 0;
701       PCH p;
702       CHAR Temp[256];
703       PCH options;
704       PCH s1;
705
706       if (((PUCHAR)_LoaderBlock->CommandLine)[1] == 'h' &&
707           ((PUCHAR)_LoaderBlock->CommandLine)[2] == 'd')
708         {
709           DiskNumber = ((PUCHAR)_LoaderBlock->CommandLine)[3] - '0';
710           PartNumber = ((PUCHAR)_LoaderBlock->CommandLine)[5] - '0';
711         }
712       strcpy(Temp, &((PUCHAR)_LoaderBlock->CommandLine)[7]);
713       if ((options = strchr(Temp, ' ')) != NULL)
714         {
715           *options = 0;
716           options++;
717         }
718       else
719         {
720           options = "";
721         }
722       if ((s1 = strrchr(Temp, '/')) != NULL)
723         {
724           *s1 = 0;
725           if ((s1 = strrchr(Temp, '/')) != NULL)
726             {
727               *s1 = 0;
728             }
729         }
730       sprintf(KeLoaderCommandLine, 
731               "multi(0)disk(0)rdisk(%d)partition(%d)%s %s",
732               DiskNumber, PartNumber + 1, Temp, options);
733
734       p = KeLoaderCommandLine;
735       while (*p != 0 && *p != ' ')
736         {
737           if ((*p) == '/')
738             {
739               (*p) = '\\';
740             }
741           p++;
742         }
743       DPRINT1("Command Line: %s\n", KeLoaderCommandLine);
744     }
745   else
746     {
747       strcpy(KeLoaderCommandLine, (PUCHAR)_LoaderBlock->CommandLine);
748     }
749   KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
750   
751   strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
752   KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
753   KeLoaderModules[0].ModStart = 0xC0000000;
754   KeLoaderModules[0].ModEnd = PAGE_ROUND_UP((ULONG)&_bss_end__);
755   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
756     {      
757       CHAR* s;
758       if ((s = strrchr((PUCHAR)KeLoaderModules[i].String, '/')) != 0)
759         {
760           strcpy(KeLoaderModuleStrings[i], s + 1);
761         }
762       else
763         {
764           strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
765         }
766       KeLoaderModules[i].ModStart -= 0x200000;
767       KeLoaderModules[i].ModStart += 0xc0000000;
768       KeLoaderModules[i].ModEnd -= 0x200000;
769       KeLoaderModules[i].ModEnd += 0xc0000000;
770       KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
771     }
772
773 #ifdef HAL_DBG
774   HalnInitializeDisplay((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
775 #endif
776
777   HalBase = KeLoaderModules[1].ModStart;
778   DriverBase = 
779     PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd);
780
781   /*
782    * Process hal.dll
783    */
784   LdrSafePEProcessModule((PVOID)HalBase, (PVOID)DriverBase, (PVOID)0xC0000000, &DriverSize);
785
786   LdrHalBase = (ULONG_PTR)DriverBase;
787   last_kernel_address = DriverBase + DriverSize;
788
789   /*
790    * Process ntoskrnl.exe
791    */
792   LdrSafePEProcessModule((PVOID)0xC0000000, (PVOID)0xC0000000, (PVOID)DriverBase, &DriverSize);
793
794   FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000;
795   LastKrnlPhysAddr = last_kernel_address - 0xc0000000 + 0x200000;
796   LastKernelAddress = last_kernel_address;
797
798 #ifndef ACPI
799   /* FIXME: VMware does not like it when ReactOS is using the BIOS memory map */
800   KeLoaderBlock.Flags &= ~MB_FLAGS_MMAP_INFO;
801 #endif
802
803   KeMemoryMapRangeCount = 0;
804   if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
805     {
806       /* We have a memory map from the nice BIOS */
807       size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
808       i = 0;
809       while (i < KeLoaderBlock.MmapLength)
810         {
811           memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
812             (PVOID)(KeLoaderBlock.MmapAddr + i),
813                   sizeof(ADDRESS_RANGE));
814           KeMemoryMapRangeCount++;
815           i += size;
816         }
817     }
818   
819   KiSystemStartup(1);
820 }
821
822 /* EOF */
823