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.
19 /* $Id: main.c,v 1.138 2002/09/15 10:45:02 guido Exp $
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/module.h>
36 #include <internal/ldr.h>
37 #include <internal/ex.h>
38 #include <internal/ps.h>
39 #include <internal/ke.h>
40 #include <internal/io.h>
41 #include <internal/po.h>
42 #include <internal/cc.h>
43 #include <internal/se.h>
44 #include <internal/v86m.h>
45 #include <internal/kd.h>
46 #include <internal/trap.h>
47 #include "../dbg/kdb.h"
48 #include <internal/registry.h>
49 #include <reactos/bugcodes.h>
52 #include <internal/ntosdbg.h>
58 #include <internal/debug.h>
60 /* GLOBALS *******************************************************************/
62 ULONG EXPORTED NtBuildNumber
= KERNEL_VERSION_BUILD
;
63 ULONG EXPORTED NtGlobalFlag
= 0;
64 CHAR EXPORTED KeNumberProcessors
;
65 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock
;
66 ULONG EXPORTED KeDcacheFlushCount
= 0;
67 ULONG EXPORTED KeIcacheFlushCount
= 0;
68 static LOADER_MODULE KeLoaderModules
[64];
69 static UCHAR KeLoaderModuleStrings
[64][256];
70 static UCHAR KeLoaderCommandLine
[256];
71 static ADDRESS_RANGE KeMemoryMap
[64];
72 static ULONG KeMemoryMapRangeCount
;
73 static ULONG FirstKrnlPhysAddr
;
74 static ULONG LastKrnlPhysAddr
;
75 static ULONG LastKernelAddress
;
76 volatile BOOLEAN Initialized
= FALSE
;
78 extern PVOID Ki386InitialStackArray
[MAXIMUM_PROCESSORS
];
81 /* FUNCTIONS ****************************************************************/
84 RtlpCheckFileNameExtension(PCHAR FileName
,
89 Ext
= strrchr(FileName
, '.');
90 if ((Extension
== NULL
) || (*Extension
== 0))
97 if (*Extension
!= '.')
100 if (_stricmp(Ext
, Extension
) == 0)
108 InitSystemSharedUserPage (PCSZ ParameterLine
)
110 UNICODE_STRING ArcDeviceName
;
111 UNICODE_STRING ArcName
;
112 UNICODE_STRING BootPath
;
113 UNICODE_STRING DriveDeviceName
;
114 UNICODE_STRING DriveName
;
115 WCHAR DriveNameBuffer
[20];
117 PWCHAR ArcNameBuffer
;
121 OBJECT_ATTRIBUTES ObjectAttributes
;
124 BOOLEAN BootDriveFound
;
128 * The shared user page has been zeroed-out right after creation.
129 * There is NO need to do this again.
132 SharedUserData
->NtProductType
= NtProductWinNt
;
134 BootDriveFound
= FALSE
;
137 * Retrieve the current dos system path
138 * (e.g.: C:\reactos) from the given arc path
139 * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
140 * Format: "<arc_name>\<path> [options...]"
143 /* create local parameter line copy */
144 ParamBuffer
= ExAllocatePool (PagedPool
, 256);
145 strcpy (ParamBuffer
, (char *)ParameterLine
);
146 DPRINT("%s\n", ParamBuffer
);
148 /* cut options off */
149 p
= strchr (ParamBuffer
, ' ');
154 DPRINT("%s\n", ParamBuffer
);
157 p
= strchr (ParamBuffer
, '\\');
160 DPRINT("Boot path: %s\n", p
);
161 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
166 DPRINT("Boot path: %s\n", "\\");
167 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
169 DPRINT("Arc name: %s\n", ParamBuffer
);
171 /* Only arc name left - build full arc name */
172 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
173 swprintf (ArcNameBuffer
, L
"\\ArcName\\%S", ParamBuffer
);
174 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
175 DPRINT("Arc name: %wZ\n", &ArcName
);
177 /* free ParamBuffer */
178 ExFreePool (ParamBuffer
);
180 /* allocate arc device name string */
181 ArcDeviceName
.Length
= 0;
182 ArcDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
183 ArcDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
185 InitializeObjectAttributes (&ObjectAttributes
,
191 Status
= NtOpenSymbolicLinkObject (&Handle
,
192 SYMBOLIC_LINK_ALL_ACCESS
,
194 RtlFreeUnicodeString (&ArcName
);
195 if (!NT_SUCCESS(Status
))
197 RtlFreeUnicodeString (&BootPath
);
198 RtlFreeUnicodeString (&ArcDeviceName
);
199 CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n",
205 Status
= NtQuerySymbolicLinkObject (Handle
,
209 if (!NT_SUCCESS(Status
))
211 RtlFreeUnicodeString (&BootPath
);
212 RtlFreeUnicodeString (&ArcDeviceName
);
213 CPRINT("NtQuerySymbolicObject() failed (Status %x)\n",
218 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length
, &ArcDeviceName
);
221 /* allocate device name string */
222 DriveDeviceName
.Length
= 0;
223 DriveDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
224 DriveDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
226 for (i
= 0; i
< 26; i
++)
228 swprintf (DriveNameBuffer
, L
"\\??\\%C:", 'A' + i
);
229 RtlInitUnicodeString (&DriveName
,
232 InitializeObjectAttributes (&ObjectAttributes
,
238 Status
= NtOpenSymbolicLinkObject (&Handle
,
239 SYMBOLIC_LINK_ALL_ACCESS
,
241 if (!NT_SUCCESS(Status
))
243 DPRINT("Failed to open link %wZ\n",
248 Status
= NtQuerySymbolicLinkObject (Handle
,
251 if (!NT_SUCCESS(Status
))
253 DPRINT("Failed query open link %wZ\n",
257 DPRINT("Opened link: %wZ ==> %wZ\n",
258 &DriveName
, &DriveDeviceName
);
260 if (!RtlCompareUnicodeString (&ArcDeviceName
, &DriveDeviceName
, FALSE
))
262 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i
, &BootPath
);
263 swprintf(SharedUserData
->NtSystemRoot
,
264 L
"%C:%wZ", 'A' + i
, &BootPath
);
266 BootDriveFound
= TRUE
;
272 RtlFreeUnicodeString (&BootPath
);
273 RtlFreeUnicodeString (&DriveDeviceName
);
274 RtlFreeUnicodeString (&ArcDeviceName
);
276 DPRINT("DosDeviceMap: 0x%x\n", SharedUserData
->DosDeviceMap
);
278 if (BootDriveFound
== FALSE
)
280 DbgPrint("No system drive found!\n");
286 ExpInitializeExecutive(VOID
)
288 ULONG BootDriverCount
;
297 * Fail at runtime if someone has changed various structures without
298 * updating the offsets used for the assembler code.
300 assert(FIELD_OFFSET(KTHREAD
, InitialStack
) == KTHREAD_INITIAL_STACK
);
301 assert(FIELD_OFFSET(KTHREAD
, Teb
) == KTHREAD_TEB
);
302 assert(FIELD_OFFSET(KTHREAD
, KernelStack
) == KTHREAD_KERNEL_STACK
);
303 assert(FIELD_OFFSET(KTHREAD
, PreviousMode
) == KTHREAD_PREVIOUS_MODE
);
304 assert(FIELD_OFFSET(KTHREAD
, TrapFrame
) == KTHREAD_TRAP_FRAME
);
305 assert(FIELD_OFFSET(KTHREAD
, CallbackStack
) == KTHREAD_CALLBACK_STACK
);
306 assert(FIELD_OFFSET(ETHREAD
, ThreadsProcess
) == ETHREAD_THREADS_PROCESS
);
307 assert(FIELD_OFFSET(KPROCESS
, DirectoryTableBase
) ==
308 KPROCESS_DIRECTORY_TABLE_BASE
);
309 assert(FIELD_OFFSET(KTRAP_FRAME
, Reserved9
) == KTRAP_FRAME_RESERVED9
);
310 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, regs
) == TF_REGS
);
311 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, orig_ebp
) == TF_ORIG_EBP
);
313 assert(FIELD_OFFSET(KPCR
, ExceptionList
) == KPCR_EXCEPTION_LIST
);
314 assert(FIELD_OFFSET(KPCR
, Self
) == KPCR_SELF
);
315 assert(FIELD_OFFSET(KPCR
, CurrentThread
) == KPCR_CURRENT_THREAD
);
319 KeLowerIrql(DISPATCH_LEVEL
);
323 MmInit1(FirstKrnlPhysAddr
,
326 (PADDRESS_RANGE
)&KeMemoryMap
,
327 KeMemoryMapRangeCount
);
329 /* create default nls tables */
333 * Initialize the kernel debugger
335 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
340 KeLowerIrql(PASSIVE_LEVEL
);
343 KeBugCheck(SECURITY_INITIALIZATION_FAILED
);
348 KeBugCheck(SECURITY1_INITIALIZATION_FAILED
);
350 PiInitProcessManager();
354 if (KdPollBreakIn ())
356 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
360 * Display version number and copyright/warranty message
362 HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR
" (Build "
363 KERNEL_VERSION_BUILD_STR
")\n");
364 HalDisplayString(RES_STR_LEGAL_COPYRIGHT
);
365 HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
366 "Public License, and you\n");
367 HalDisplayString("are welcome to change it and/or distribute copies of it "
369 HalDisplayString("conditions. There is absolutely no warranty for "
372 /* Initialize all processors */
373 KeNumberProcessors
= 0;
375 while (!HalAllProcessorsStarted())
377 PVOID ProcessorStack
;
379 if (KeNumberProcessors
!= 0)
381 KePrepareForApplicationProcessorInit(KeNumberProcessors
);
382 PsPrepareForApplicationProcessorInit(KeNumberProcessors
);
384 /* Allocate a stack for use when booting the processor */
385 /* FIXME: The nonpaged memory for the stack is not released after use */
387 ExAllocatePool(NonPagedPool
, MM_STACK_SIZE
) + MM_STACK_SIZE
;
388 Ki386InitialStackArray
[((int)KeNumberProcessors
)] =
389 (PVOID
)(ProcessorStack
- MM_STACK_SIZE
);
390 HalInitializeProcessor(KeNumberProcessors
, ProcessorStack
);
391 KeNumberProcessors
++;
394 if (KeNumberProcessors
> 1)
397 "Found %d system processors. [%lu MB Memory]\n",
399 (KeLoaderBlock
.MemHigher
+ 1088)/ 1024);
404 "Found 1 system processor. [%lu MB Memory]\n",
405 (KeLoaderBlock
.MemHigher
+ 1088)/ 1024);
407 HalDisplayString(str
);
410 * Initialize various critical subsystems
412 HalInitSystem(1, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
417 LdrInitModuleManagement();
418 CmInitializeRegistry();
424 /* Report all resources used by hal */
425 HalReportResourceUsage();
428 * Initalize services loaded at boot time
430 DPRINT("%d files loaded\n",KeLoaderBlock
.ModsCount
);
431 for (i
=0; i
< KeLoaderBlock
.ModsCount
; i
++)
433 CPRINT("Module: '%s' at %08lx, length 0x%08lx\n",
434 KeLoaderModules
[i
].String
,
435 KeLoaderModules
[i
].ModStart
,
436 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
439 /* Pass 1: load nls files */
440 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
442 name
= (PCHAR
)KeLoaderModules
[i
].String
;
443 if (RtlpCheckFileNameExtension(name
, ".nls"))
450 name
= (PCHAR
)KeLoaderModules
[i
+1].String
;
451 if (RtlpCheckFileNameExtension(name
, ".nls"))
453 Mod2Start
= (ULONG
)KeLoaderModules
[i
+1].ModStart
;
454 Mod2End
= (ULONG
)KeLoaderModules
[i
+1].ModEnd
;
456 name
= (PCHAR
)KeLoaderModules
[i
+2].String
;
457 if (RtlpCheckFileNameExtension(name
, ".nls"))
459 Mod3Start
= (ULONG
)KeLoaderModules
[i
+2].ModStart
;
460 Mod3End
= (ULONG
)KeLoaderModules
[i
+2].ModEnd
;
464 /* Initialize nls sections */
465 RtlpInitNlsSections((ULONG
)KeLoaderModules
[i
].ModStart
,
466 (ULONG
)KeLoaderModules
[i
].ModEnd
,
475 /* Pass 2: load registry chunks passed in */
476 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
478 start
= KeLoaderModules
[i
].ModStart
;
479 length
= KeLoaderModules
[i
].ModEnd
- start
;
480 name
= (PCHAR
)KeLoaderModules
[i
].String
;
481 if (RtlpCheckFileNameExtension(name
, "") ||
482 RtlpCheckFileNameExtension(name
, ".hiv"))
484 CPRINT("Process registry chunk at %08lx\n", start
);
485 CmImportHive((PCHAR
)start
, length
);
489 /* Initialize volatile registry settings */
490 CmInit2((PCHAR
)KeLoaderBlock
.CommandLine
);
493 * Enter the kernel debugger before starting up the boot drivers
499 IoCreateDriverList();
501 /* Pass 3: process boot loaded drivers */
503 for (i
=1; i
< KeLoaderBlock
.ModsCount
; i
++)
505 start
= KeLoaderModules
[i
].ModStart
;
506 length
= KeLoaderModules
[i
].ModEnd
- start
;
507 name
= (PCHAR
)KeLoaderModules
[i
].String
;
508 if (RtlpCheckFileNameExtension(name
, ".sys") ||
509 RtlpCheckFileNameExtension(name
, ".sym"))
511 CPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
512 name
, start
, length
);
513 LdrInitializeBootStartDriver((PVOID
)start
, name
, length
);
515 if (RtlpCheckFileNameExtension(name
, ".sys"))
519 if (BootDriverCount
== 0)
521 DbgPrint("No boot drivers available.\n");
525 /* Create ARC names for boot devices */
528 /* Create the SystemRoot symbolic link */
529 CPRINT("CommandLine: %s\n", (PUCHAR
)KeLoaderBlock
.CommandLine
);
530 Status
= IoCreateSystemRootLink((PUCHAR
)KeLoaderBlock
.CommandLine
);
531 if (!NT_SUCCESS(Status
))
532 KeBugCheck(INACCESSIBLE_BOOT_DEVICE
);
534 #ifdef DBGPRINT_FILE_LOG
535 /* On the assumption that we can now access disks start up the debug
538 #endif /* DBGPRINT_FILE_LOG */
541 PiInitDefaultLocale();
544 * Start the motherboard enumerator (the HAL)
546 HalInitSystem(2, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
549 * Load boot start drivers
551 IopLoadBootStartDrivers();
554 * Load Auto configured drivers
556 LdrLoadAutoConfigDrivers();
559 IoDestroyDriverList();
562 * Assign drive letters
564 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
,
570 * Initialize shared user page:
571 * - set dos system path, dos device map, etc.
573 InitSystemSharedUserPage ((PUCHAR
)KeLoaderBlock
.CommandLine
);
576 * Launch initial process
578 LdrLoadInitialProcess();
580 PsTerminateSystemThread(STATUS_SUCCESS
);
585 KiSystemStartup(BOOLEAN BootProcessor
)
587 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
592 ExpInitializeExecutive();
595 /* Do application processor initialization */
596 KeApplicationProcessorInit();
597 PsApplicationProcessorInit();
598 KeLowerIrql(PASSIVE_LEVEL
);
599 PsIdleThreadMain(NULL
);
605 _main (ULONG MultiBootMagic
, PLOADER_PARAMETER_BLOCK _LoaderBlock
)
607 * FUNCTION: Called by the boot loader to start the kernel
609 * LoaderBlock = Pointer to boot parameters initialized by the boot
611 * NOTE: The boot parameters are stored in low memory which will become
612 * invalid after the memory managment is initialized so we make a local copy.
617 ULONG last_kernel_address
;
618 extern ULONG _bss_end__
;
623 /* Low level architecture specific initialization */
627 * Copy the parameters to a local buffer because lowmem will go away
629 memcpy(&KeLoaderBlock
, _LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
630 memcpy(&KeLoaderModules
[1], (PVOID
)KeLoaderBlock
.ModsAddr
,
631 sizeof(LOADER_MODULE
) * KeLoaderBlock
.ModsCount
);
632 KeLoaderBlock
.ModsCount
++;
633 KeLoaderBlock
.ModsAddr
= (ULONG
)&KeLoaderModules
;
636 * Convert a path specification in the grub format to one understood by the
637 * rest of the kernel.
639 if (((PUCHAR
)_LoaderBlock
->CommandLine
)[0] == '(')
641 ULONG DiskNumber
= 0, PartNumber
= 0;
647 if (((PUCHAR
)_LoaderBlock
->CommandLine
)[1] == 'h' &&
648 ((PUCHAR
)_LoaderBlock
->CommandLine
)[2] == 'd')
650 DiskNumber
= ((PUCHAR
)_LoaderBlock
->CommandLine
)[3] - '0';
651 PartNumber
= ((PUCHAR
)_LoaderBlock
->CommandLine
)[5] - '0';
653 strcpy(Temp
, &((PUCHAR
)_LoaderBlock
->CommandLine
)[7]);
654 if ((options
= strchr(Temp
, ' ')) != NULL
)
663 if ((s1
= strrchr(Temp
, '/')) != NULL
)
666 if ((s1
= strrchr(Temp
, '/')) != NULL
)
671 sprintf(KeLoaderCommandLine
,
672 "multi(0)disk(0)rdisk(%ld)partition(%ld)%s %s",
673 DiskNumber
, PartNumber
+ 1, Temp
, options
);
675 p
= KeLoaderCommandLine
;
676 while (*p
!= 0 && *p
!= ' ')
684 DPRINT1("Command Line: %s\n", KeLoaderCommandLine
);
688 strcpy(KeLoaderCommandLine
, (PUCHAR
)_LoaderBlock
->CommandLine
);
690 KeLoaderBlock
.CommandLine
= (ULONG
)KeLoaderCommandLine
;
692 strcpy(KeLoaderModuleStrings
[0], "ntoskrnl.exe");
693 KeLoaderModules
[0].String
= (ULONG
)KeLoaderModuleStrings
[0];
694 KeLoaderModules
[0].ModStart
= 0xC0000000;
695 KeLoaderModules
[0].ModEnd
= PAGE_ROUND_UP((ULONG
)&_bss_end__
);
696 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
698 strcpy(KeLoaderModuleStrings
[i
], (PUCHAR
)KeLoaderModules
[i
].String
);
699 KeLoaderModules
[i
].ModStart
-= 0x200000;
700 KeLoaderModules
[i
].ModStart
+= 0xc0000000;
701 KeLoaderModules
[i
].ModEnd
-= 0x200000;
702 KeLoaderModules
[i
].ModEnd
+= 0xc0000000;
703 KeLoaderModules
[i
].String
= (ULONG
)KeLoaderModuleStrings
[i
];
707 HalnInitializeDisplay((PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
710 HalBase
= KeLoaderModules
[1].ModStart
;
712 PAGE_ROUND_UP(KeLoaderModules
[KeLoaderBlock
.ModsCount
- 1].ModEnd
);
717 LdrSafePEProcessModule((PVOID
)HalBase
, (PVOID
)DriverBase
, (PVOID
)0xC0000000, &DriverSize
);
719 LdrHalBase
= (ULONG_PTR
)DriverBase
;
720 last_kernel_address
= DriverBase
+ DriverSize
;
723 * Process ntoskrnl.exe
725 LdrSafePEProcessModule((PVOID
)0xC0000000, (PVOID
)0xC0000000, (PVOID
)DriverBase
, &DriverSize
);
727 FirstKrnlPhysAddr
= KeLoaderModules
[0].ModStart
- 0xc0000000 + 0x200000;
728 LastKrnlPhysAddr
= last_kernel_address
- 0xc0000000 + 0x200000;
729 LastKernelAddress
= last_kernel_address
;
732 /* FIXME: VMware does not like it when ReactOS is using the BIOS memory map */
733 KeLoaderBlock
.Flags
&= ~MB_FLAGS_MMAP_INFO
;
736 KeMemoryMapRangeCount
= 0;
737 if (KeLoaderBlock
.Flags
& MB_FLAGS_MMAP_INFO
)
739 /* We have a memory map from the nice BIOS */
740 size
= *((PULONG
)(KeLoaderBlock
.MmapAddr
- sizeof(ULONG
)));
742 while (i
< KeLoaderBlock
.MmapLength
)
744 memcpy (&KeMemoryMap
[KeMemoryMapRangeCount
],
745 (PVOID
)(KeLoaderBlock
.MmapAddr
+ i
),
746 sizeof(ADDRESS_RANGE
));
747 KeMemoryMapRangeCount
++;