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