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