3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/main.c
23 * PURPOSE: Initalizes the kernel
24 * PROGRAMMER: David Welch (welch@cwcom.net)
29 /* INCLUDES *****************************************************************/
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>
53 #include <internal/ntosdbg.h>
59 #include <internal/debug.h>
61 /* GLOBALS *******************************************************************/
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;
79 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
82 /* FUNCTIONS ****************************************************************/
85 RtlpCheckFileNameExtension(PCHAR FileName,
90 Ext = strrchr(FileName, '.');
91 if ((Extension == NULL) || (*Extension == 0))
98 if (*Extension != '.')
101 if (_stricmp(Ext, Extension) == 0)
109 RtlpIsSystemHive(PCHAR FileName)
113 Name = strrchr(FileName, '\\');
123 return((_stricmp(Name, "system.hiv") == 0) ||
124 (_stricmp(Name, "system") == 0));
129 InitSystemSharedUserPage (PCSZ ParameterLine)
131 UNICODE_STRING ArcDeviceName;
132 UNICODE_STRING ArcName;
133 UNICODE_STRING BootPath;
134 UNICODE_STRING DriveDeviceName;
135 UNICODE_STRING DriveName;
136 WCHAR DriveNameBuffer[20];
138 PWCHAR ArcNameBuffer;
142 OBJECT_ATTRIBUTES ObjectAttributes;
145 BOOLEAN BootDriveFound;
149 * The shared user page has been zeroed-out right after creation.
150 * There is NO need to do this again.
153 SharedUserData->NtProductType = NtProductWinNt;
155 BootDriveFound = FALSE;
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...]"
164 /* create local parameter line copy */
165 ParamBuffer = ExAllocatePool (PagedPool, 256);
166 strcpy (ParamBuffer, (char *)ParameterLine);
167 DPRINT("%s\n", ParamBuffer);
169 /* cut options off */
170 p = strchr (ParamBuffer, ' ');
175 DPRINT("%s\n", ParamBuffer);
178 p = strchr (ParamBuffer, '\\');
181 DPRINT("Boot path: %s\n", p);
182 RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
187 DPRINT("Boot path: %s\n", "\\");
188 RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
190 DPRINT("Arc name: %s\n", ParamBuffer);
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);
198 /* free ParamBuffer */
199 ExFreePool (ParamBuffer);
201 /* allocate arc device name string */
202 ArcDeviceName.Length = 0;
203 ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
204 ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
206 InitializeObjectAttributes (&ObjectAttributes,
212 Status = NtOpenSymbolicLinkObject (&Handle,
213 SYMBOLIC_LINK_ALL_ACCESS,
215 RtlFreeUnicodeString (&ArcName);
216 if (!NT_SUCCESS(Status))
218 RtlFreeUnicodeString (&BootPath);
219 RtlFreeUnicodeString (&ArcDeviceName);
220 CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n",
226 Status = NtQuerySymbolicLinkObject (Handle,
230 if (!NT_SUCCESS(Status))
232 RtlFreeUnicodeString (&BootPath);
233 RtlFreeUnicodeString (&ArcDeviceName);
234 CPRINT("NtQuerySymbolicObject() failed (Status %x)\n",
239 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
242 /* allocate device name string */
243 DriveDeviceName.Length = 0;
244 DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
245 DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
247 for (i = 0; i < 26; i++)
249 swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
250 RtlInitUnicodeString (&DriveName,
253 InitializeObjectAttributes (&ObjectAttributes,
259 Status = NtOpenSymbolicLinkObject (&Handle,
260 SYMBOLIC_LINK_ALL_ACCESS,
262 if (!NT_SUCCESS(Status))
264 DPRINT("Failed to open link %wZ\n",
269 Status = NtQuerySymbolicLinkObject (Handle,
272 if (!NT_SUCCESS(Status))
274 DPRINT("Failed query open link %wZ\n",
278 DPRINT("Opened link: %wZ ==> %wZ\n",
279 &DriveName, &DriveDeviceName);
281 if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE))
283 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
284 swprintf(SharedUserData->NtSystemRoot,
285 L"%C:%wZ", 'A' + i, &BootPath);
287 BootDriveFound = TRUE;
293 RtlFreeUnicodeString (&BootPath);
294 RtlFreeUnicodeString (&DriveDeviceName);
295 RtlFreeUnicodeString (&ArcDeviceName);
297 DPRINT("DosDeviceMap: 0x%x\n", SharedUserData->DosDeviceMap);
299 if (BootDriveFound == FALSE)
301 DbgPrint("No system drive found!\n");
308 ExpInitializeExecutive(VOID)
310 LARGE_INTEGER Timeout;
311 HANDLE ProcessHandle;
313 ULONG BootDriverCount;
323 * Fail at runtime if someone has changed various structures without
324 * updating the offsets used for the assembler code.
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);
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);
345 KeLowerIrql(DISPATCH_LEVEL);
349 MmInit1(FirstKrnlPhysAddr,
352 (PADDRESS_RANGE)&KeMemoryMap,
353 KeMemoryMapRangeCount);
355 /* create default nls tables */
359 * Initialize the kernel debugger
361 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
366 KeLowerIrql(PASSIVE_LEVEL);
369 KeBugCheck(SECURITY_INITIALIZATION_FAILED);
374 KeBugCheck(SECURITY1_INITIALIZATION_FAILED);
376 PiInitProcessManager();
380 if (KdPollBreakIn ())
382 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
386 * Display version number and copyright/warranty message
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 "
395 HalDisplayString("conditions. There is absolutely no warranty for "
398 /* Initialize all processors */
399 KeNumberProcessors = 0;
401 while (!HalAllProcessorsStarted())
403 PVOID ProcessorStack;
405 if (KeNumberProcessors != 0)
407 KePrepareForApplicationProcessorInit(KeNumberProcessors);
408 PsPrepareForApplicationProcessorInit(KeNumberProcessors);
410 /* Allocate a stack for use when booting the processor */
411 /* FIXME: The nonpaged memory for the stack is not released after use */
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++;
420 if (KeNumberProcessors > 1)
423 "Found %d system processors. [%u MB Memory]\n",
425 (KeLoaderBlock.MemHigher + 1088)/ 1024);
430 "Found 1 system processor. [%u MB Memory]\n",
431 (KeLoaderBlock.MemHigher + 1088)/ 1024);
433 HalDisplayString(str);
436 * Initialize various critical subsystems
438 HalInitSystem(1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
443 LdrInitModuleManagement();
444 CmInitializeRegistry();
449 FsRtlpInitFileLockingImplementation();
451 /* Report all resources used by hal */
452 HalReportResourceUsage();
455 * Initalize services loaded at boot time
457 DPRINT("%d files loaded\n",KeLoaderBlock.ModsCount);
458 for (i=0; i < KeLoaderBlock.ModsCount; i++)
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);
466 /* Pass 1: load nls files */
467 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
469 name = (PCHAR)KeLoaderModules[i].String;
470 if (RtlpCheckFileNameExtension(name, ".nls"))
477 name = (PCHAR)KeLoaderModules[i+1].String;
478 if (RtlpCheckFileNameExtension(name, ".nls"))
480 Mod2Start = (ULONG)KeLoaderModules[i+1].ModStart;
481 Mod2End = (ULONG)KeLoaderModules[i+1].ModEnd;
483 name = (PCHAR)KeLoaderModules[i+2].String;
484 if (RtlpCheckFileNameExtension(name, ".nls"))
486 Mod3Start = (ULONG)KeLoaderModules[i+2].ModStart;
487 Mod3End = (ULONG)KeLoaderModules[i+2].ModEnd;
491 /* Initialize nls sections */
492 RtlpInitNlsSections((ULONG)KeLoaderModules[i].ModStart,
493 (ULONG)KeLoaderModules[i].ModEnd,
502 /* Pass 2: load registry chunks passed in */
504 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
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"))
512 CPRINT("Process registry chunk at %08lx\n", start);
513 CmImportHive((PCHAR)start, length);
515 if (RtlpIsSystemHive(name))
521 /* Initialize volatile registry settings */
522 if (SetupBoot == FALSE)
524 CmInit2((PCHAR)KeLoaderBlock.CommandLine);
528 * Enter the kernel debugger before starting up the boot drivers
534 IoCreateDriverList();
536 /* Pass 3: process boot loaded drivers */
538 for (i=1; i < KeLoaderBlock.ModsCount; i++)
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"))
546 CPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
547 name, start, length);
548 LdrInitializeBootStartDriver((PVOID)start, name, length);
550 if (RtlpCheckFileNameExtension(name, ".sys"))
554 if (BootDriverCount == 0)
556 DbgPrint("No boot drivers available.\n");
560 /* Create ARC names for boot devices */
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);
569 #ifdef DBGPRINT_FILE_LOG
570 /* On the assumption that we can now access disks start up the debug
573 #endif /* DBGPRINT_FILE_LOG */
580 PiInitDefaultLocale();
583 * Start the motherboard enumerator (the HAL)
585 HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
588 * Load boot start drivers
590 IopLoadBootStartDrivers();
593 * Load Auto configured drivers
595 LdrLoadAutoConfigDrivers();
598 IoDestroyDriverList();
601 * Assign drive letters
603 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock,
609 * Initialize shared user page:
610 * - set dos system path, dos device map, etc.
612 InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
615 * Launch initial process
617 Status = LdrLoadInitialProcess(&ProcessHandle,
619 if (!NT_SUCCESS(Status))
621 KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
625 * Crash the system if the initial process terminates within 5 seconds.
627 Timeout.QuadPart = -50000000LL;
628 Status = NtWaitForSingleObject(ProcessHandle,
631 if (Status != STATUS_TIMEOUT)
633 KeBugCheckEx(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
636 NtClose(ThreadHandle);
637 NtClose(ProcessHandle);
639 PsTerminateSystemThread(STATUS_SUCCESS);
644 KiSystemStartup(BOOLEAN BootProcessor)
646 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
651 ExpInitializeExecutive();
654 /* Do application processor initialization */
655 KeApplicationProcessorInit();
656 PsApplicationProcessorInit();
657 KeLowerIrql(PASSIVE_LEVEL);
658 PsIdleThreadMain(NULL);
664 _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
666 * FUNCTION: Called by the boot loader to start the kernel
668 * LoaderBlock = Pointer to boot parameters initialized by the boot
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.
676 ULONG last_kernel_address;
677 extern ULONG _bss_end__;
682 /* Low level architecture specific initialization */
686 * Copy the parameters to a local buffer because lowmem will go away
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;
695 * Convert a path specification in the grub format to one understood by the
696 * rest of the kernel.
698 if (((PUCHAR)_LoaderBlock->CommandLine)[0] == '(')
700 ULONG DiskNumber = 0, PartNumber = 0;
706 if (((PUCHAR)_LoaderBlock->CommandLine)[1] == 'h' &&
707 ((PUCHAR)_LoaderBlock->CommandLine)[2] == 'd')
709 DiskNumber = ((PUCHAR)_LoaderBlock->CommandLine)[3] - '0';
710 PartNumber = ((PUCHAR)_LoaderBlock->CommandLine)[5] - '0';
712 strcpy(Temp, &((PUCHAR)_LoaderBlock->CommandLine)[7]);
713 if ((options = strchr(Temp, ' ')) != NULL)
722 if ((s1 = strrchr(Temp, '/')) != NULL)
725 if ((s1 = strrchr(Temp, '/')) != NULL)
730 sprintf(KeLoaderCommandLine,
731 "multi(0)disk(0)rdisk(%d)partition(%d)%s %s",
732 DiskNumber, PartNumber + 1, Temp, options);
734 p = KeLoaderCommandLine;
735 while (*p != 0 && *p != ' ')
743 DPRINT1("Command Line: %s\n", KeLoaderCommandLine);
747 strcpy(KeLoaderCommandLine, (PUCHAR)_LoaderBlock->CommandLine);
749 KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
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++)
758 if ((s = strrchr((PUCHAR)KeLoaderModules[i].String, '/')) != 0)
760 strcpy(KeLoaderModuleStrings[i], s + 1);
764 strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
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];
774 HalnInitializeDisplay((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
777 HalBase = KeLoaderModules[1].ModStart;
779 PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd);
784 LdrSafePEProcessModule((PVOID)HalBase, (PVOID)DriverBase, (PVOID)0xC0000000, &DriverSize);
786 LdrHalBase = (ULONG_PTR)DriverBase;
787 last_kernel_address = DriverBase + DriverSize;
790 * Process ntoskrnl.exe
792 LdrSafePEProcessModule((PVOID)0xC0000000, (PVOID)0xC0000000, (PVOID)DriverBase, &DriverSize);
794 FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000;
795 LastKrnlPhysAddr = last_kernel_address - 0xc0000000 + 0x200000;
796 LastKernelAddress = last_kernel_address;
799 /* FIXME: VMware does not like it when ReactOS is using the BIOS memory map */
800 KeLoaderBlock.Flags &= ~MB_FLAGS_MMAP_INFO;
803 KeMemoryMapRangeCount = 0;
804 if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
806 /* We have a memory map from the nice BIOS */
807 size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
809 while (i < KeLoaderBlock.MmapLength)
811 memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
812 (PVOID)(KeLoaderBlock.MmapAddr + i),
813 sizeof(ADDRESS_RANGE));
814 KeMemoryMapRangeCount++;