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.95 2001/05/01 23:08:19 chorns 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 <napi/shared_data.h>
43 #include <internal/v86m.h>
44 #include <internal/kd.h>
45 #include <internal/trap.h>
46 #include "../dbg/kdb.h"
49 #include <internal/debug.h>
51 /* GLOBALS *******************************************************************/
53 ULONG EXPORTED NtBuildNumber
= KERNEL_VERSION_BUILD
;
54 ULONG EXPORTED NtGlobalFlag
= 0;
55 CHAR EXPORTED KeNumberProcessors
;
56 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock
;
57 static LOADER_MODULE KeLoaderModules
[64];
58 static UCHAR KeLoaderModuleStrings
[64][256];
59 static UCHAR KeLoaderCommandLine
[256];
60 static ADDRESS_RANGE KeMemoryMap
[64];
61 static ULONG KeMemoryMapRangeCount
;
62 static ULONG FirstKrnlPhysAddr
;
63 static ULONG LastKrnlPhysAddr
;
64 static ULONG LastKernelAddress
;
65 volatile BOOLEAN Initialized
= FALSE
;
67 /* FUNCTIONS ****************************************************************/
70 CreateSystemRootLink (PCSZ ParameterLine
)
72 UNICODE_STRING LinkName
;
73 UNICODE_STRING DeviceName
;
74 UNICODE_STRING ArcName
;
75 UNICODE_STRING BootPath
;
81 OBJECT_ATTRIBUTES ObjectAttributes
;
84 /* create local parameter line copy */
85 ParamBuffer
= ExAllocatePool (PagedPool
, 256);
86 strcpy (ParamBuffer
, (char *)ParameterLine
);
88 DPRINT("%s\n", ParamBuffer
);
89 /* Format: <arc_name>\<path> [options...] */
92 p
= strchr (ParamBuffer
, ' ');
95 DPRINT("%s\n", ParamBuffer
);
98 p
= strchr (ParamBuffer
, '\\');
101 DPRINT("Boot path: %s\n", p
);
102 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
107 DPRINT("Boot path: %s\n", "\\");
108 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
110 DPRINT("Arc name: %s\n", ParamBuffer
);
112 /* Only arc name left - build full arc name */
113 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
114 swprintf (ArcNameBuffer
,
115 L
"\\ArcName\\%S", ParamBuffer
);
116 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
117 DPRINT1("Arc name: %wZ\n", &ArcName
);
119 /* free ParamBuffer */
120 ExFreePool (ParamBuffer
);
122 /* allocate device name string */
123 DeviceName
.Length
= 0;
124 DeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
125 DeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
127 InitializeObjectAttributes (&ObjectAttributes
,
133 Status
= NtOpenSymbolicLinkObject (&Handle
,
134 SYMBOLIC_LINK_ALL_ACCESS
,
136 if (!NT_SUCCESS(Status
))
138 RtlFreeUnicodeString (&BootPath
);
139 RtlFreeUnicodeString (&DeviceName
);
140 DPRINT("NtOpenSymbolicLinkObject() '%wZ' failed (Status %x)\n",
143 RtlFreeUnicodeString (&ArcName
);
147 RtlFreeUnicodeString (&ArcName
);
149 Status
= NtQuerySymbolicLinkObject (Handle
,
153 if (!NT_SUCCESS(Status
))
155 RtlFreeUnicodeString (&BootPath
);
156 RtlFreeUnicodeString (&DeviceName
);
157 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
162 DPRINT("Length: %lu DeviceName: %wZ\n", Length
, &DeviceName
);
164 RtlAppendUnicodeStringToString (&DeviceName
,
167 RtlFreeUnicodeString (&BootPath
);
168 DPRINT("DeviceName: %wZ\n", &DeviceName
);
170 /* create the '\SystemRoot' link */
171 RtlInitUnicodeString (&LinkName
,
174 Status
= IoCreateSymbolicLink (&LinkName
,
176 RtlFreeUnicodeString (&DeviceName
);
177 if (!NT_SUCCESS(Status
))
179 DbgPrint("IoCreateSymbolicLink() failed (Status %x)\n",
185 /* Check if '\SystemRoot'(LinkName) can be opened, otherwise crash it! */
186 InitializeObjectAttributes (&ObjectAttributes
,
192 Status
= NtOpenSymbolicLinkObject (&Handle
,
193 SYMBOLIC_LINK_ALL_ACCESS
,
195 if (!NT_SUCCESS(Status
))
197 DbgPrint("NtOpenSymbolicLinkObject() failed to open '\\SystemRoot' (Status %x)\n",
206 InitSystemSharedUserPage (PCSZ ParameterLine
)
208 PKUSER_SHARED_DATA SharedPage
;
210 UNICODE_STRING ArcDeviceName
;
211 UNICODE_STRING ArcName
;
212 UNICODE_STRING BootPath
;
213 UNICODE_STRING DriveDeviceName
;
214 UNICODE_STRING DriveName
;
215 WCHAR DriveNameBuffer
[20];
217 PWCHAR ArcNameBuffer
;
221 OBJECT_ATTRIBUTES ObjectAttributes
;
224 BOOLEAN BootDriveFound
;
226 SharedPage
= (PKUSER_SHARED_DATA
)KERNEL_SHARED_DATA_BASE
;
227 SharedPage
->DosDeviceMap
= 0;
228 SharedPage
->NtProductType
= NtProductWinNt
;
229 for (i
= 0; i
< 32; i
++)
231 SharedPage
->DosDeviceDriveType
[i
] = 0;
234 BootDriveFound
= FALSE
;
237 * Retrieve the current dos system path
238 * (e.g.: C:\reactos) from the given arc path
239 * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
240 * Format: "<arc_name>\<path> [options...]"
243 /* create local parameter line copy */
244 ParamBuffer
= ExAllocatePool (PagedPool
, 256);
245 strcpy (ParamBuffer
, (char *)ParameterLine
);
246 DPRINT("%s\n", ParamBuffer
);
248 /* cut options off */
249 p
= strchr (ParamBuffer
, ' ');
254 DPRINT("%s\n", ParamBuffer
);
257 p
= strchr (ParamBuffer
, '\\');
260 DPRINT("Boot path: %s\n", p
);
261 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
266 DPRINT("Boot path: %s\n", "\\");
267 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
269 DPRINT("Arc name: %s\n", ParamBuffer
);
271 /* Only arc name left - build full arc name */
272 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
273 swprintf (ArcNameBuffer
, L
"\\ArcName\\%S", ParamBuffer
);
274 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
275 DPRINT("Arc name: %wZ\n", &ArcName
);
277 /* free ParamBuffer */
278 ExFreePool (ParamBuffer
);
280 /* allocate arc device name string */
281 ArcDeviceName
.Length
= 0;
282 ArcDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
283 ArcDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
285 InitializeObjectAttributes (&ObjectAttributes
,
291 Status
= NtOpenSymbolicLinkObject (&Handle
,
292 SYMBOLIC_LINK_ALL_ACCESS
,
294 RtlFreeUnicodeString (&ArcName
);
295 if (!NT_SUCCESS(Status
))
297 RtlFreeUnicodeString (&BootPath
);
298 RtlFreeUnicodeString (&ArcDeviceName
);
299 DbgPrint("NtOpenSymbolicLinkObject() failed (Status %x)\n",
305 Status
= NtQuerySymbolicLinkObject (Handle
,
309 if (!NT_SUCCESS(Status
))
311 RtlFreeUnicodeString (&BootPath
);
312 RtlFreeUnicodeString (&ArcDeviceName
);
313 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
318 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length
, &ArcDeviceName
);
321 /* allocate device name string */
322 DriveDeviceName
.Length
= 0;
323 DriveDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
324 DriveDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
326 for (i
= 0; i
< 26; i
++)
328 swprintf (DriveNameBuffer
, L
"\\??\\%C:", 'A' + i
);
329 RtlInitUnicodeString (&DriveName
,
332 InitializeObjectAttributes (&ObjectAttributes
,
338 Status
= NtOpenSymbolicLinkObject (&Handle
,
339 SYMBOLIC_LINK_ALL_ACCESS
,
341 if (!NT_SUCCESS(Status
))
343 DPRINT("Failed to open link %wZ\n",
348 Status
= NtQuerySymbolicLinkObject (Handle
,
351 if (!NT_SUCCESS(Status
))
353 DPRINT("Failed query open link %wZ\n",
357 DPRINT("Opened link: %wZ ==> %wZ\n",
358 &DriveName
, &DriveDeviceName
);
360 if (!RtlCompareUnicodeString (&ArcDeviceName
, &DriveDeviceName
, FALSE
))
362 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i
, &BootPath
);
363 swprintf (SharedPage
->NtSystemRoot
,
364 L
"%C:%wZ", 'A' + i
, &BootPath
);
366 BootDriveFound
= TRUE
;
371 /* set bit in dos drives bitmap (drive available) */
372 SharedPage
->DosDeviceMap
|= (1<<i
);
375 RtlFreeUnicodeString (&BootPath
);
376 RtlFreeUnicodeString (&DriveDeviceName
);
377 RtlFreeUnicodeString (&ArcDeviceName
);
379 DPRINT("DosDeviceMap: 0x%x\n", SharedPage
->DosDeviceMap
);
381 if (BootDriveFound
== FALSE
)
383 DbgPrint("No system drive found!\n");
390 VOID
DumpBIOSMemoryMap(VOID
)
394 DbgPrint("Dumping BIOS memory map:\n");
395 DbgPrint("Memory map base: %d\n", KeLoaderBlock
.MmapAddr
);
396 DbgPrint("Memory map size: %d\n", KeLoaderBlock
.MmapLength
);
397 DbgPrint("Address range count: %d\n", KeMemoryMapRangeCount
);
398 for (i
= 0; i
< KeMemoryMapRangeCount
; i
++)
400 DbgPrint("Range: Base (%08X) Length (%08X) Type (%02X)\n",
401 KeMemoryMap
[i
].BaseAddrLow
,
402 KeMemoryMap
[i
].LengthLow
,
403 KeMemoryMap
[i
].Type
);
411 ExpInitializeExecutive(VOID
)
420 * Fail at runtime if someone has changed various structures without
421 * updating the offsets used for the assembler code.
423 assert(FIELD_OFFSET(KTHREAD
, InitialStack
) == KTHREAD_INITIAL_STACK
);
424 assert(FIELD_OFFSET(KTHREAD
, Teb
) == KTHREAD_TEB
);
425 assert(FIELD_OFFSET(KTHREAD
, KernelStack
) == KTHREAD_KERNEL_STACK
);
426 assert(FIELD_OFFSET(KTHREAD
, PreviousMode
) == KTHREAD_PREVIOUS_MODE
);
427 assert(FIELD_OFFSET(KTHREAD
, TrapFrame
) == KTHREAD_TRAP_FRAME
);
428 assert(FIELD_OFFSET(ETHREAD
, ThreadsProcess
) == ETHREAD_THREADS_PROCESS
);
429 assert(FIELD_OFFSET(KPROCESS
, DirectoryTableBase
) ==
430 KPROCESS_DIRECTORY_TABLE_BASE
);
431 assert(FIELD_OFFSET(KTRAP_FRAME
, Reserved9
) == KTRAP_FRAME_RESERVED9
);
432 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, regs
) == TF_REGS
);
433 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, orig_ebp
) == TF_ORIG_EBP
);
435 assert(FIELD_OFFSET(KPCR
, ExceptionList
) == KPCR_EXCEPTION_LIST
);
436 assert(FIELD_OFFSET(KPCR
, Self
) == KPCR_SELF
);
437 assert(FIELD_OFFSET(KPCR
, CurrentThread
) == KPCR_CURRENT_THREAD
);
441 KeLowerIrql(DISPATCH_LEVEL
);
445 MmInit1(FirstKrnlPhysAddr
,
448 (PADDRESS_RANGE
)&KeMemoryMap
,
449 KeMemoryMapRangeCount
);
452 * Initialize the kernel debugger
454 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
455 if (KdPollBreakIn ())
457 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
463 KeLowerIrql(PASSIVE_LEVEL
);
466 PiInitProcessManager();
469 * Display version number and copyright/warranty message
471 HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR
" (Build "
472 KERNEL_VERSION_BUILD_STR
")\n");
473 HalDisplayString(RES_STR_LEGAL_COPYRIGHT
);
474 HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
475 "Public License, and you\n");
476 HalDisplayString("are welcome to change it and/or distribute copies of it "
478 HalDisplayString("conditions. There is absolutely no warranty for "
481 /* Initialize all processors */
482 KeNumberProcessors
= 0;
484 while (!HalAllProcessorsStarted())
486 if (KeNumberProcessors
!= 0)
488 KePrepareForApplicationProcessorInit(KeNumberProcessors
);
489 PsPrepareForApplicationProcessorInit(KeNumberProcessors
);
491 HalInitializeProcessor(KeNumberProcessors
);
492 KeNumberProcessors
++;
495 if (KeNumberProcessors
> 1)
497 sprintf(str
, "Found %d system processors.\n",
502 strcpy(str
, "Found 1 system processor.\n");
504 HalDisplayString(str
);
507 * Initialize various critical subsystems
509 HalInitSystem (1, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
514 LdrInitModuleManagement();
515 CmInitializeRegistry();
519 /* Report all resources used by hal */
520 HalReportResourceUsage ();
523 * Enter the kernel debugger before starting up the boot drivers
530 * Initalize services loaded at boot time
532 DPRINT1("%d files loaded\n",KeLoaderBlock
.ModsCount
);
533 for (i
=0; i
< KeLoaderBlock
.ModsCount
; i
++)
535 CPRINT("Module: %s\n", KeLoaderModules
[i
].String
);
538 /* Pass 1: load registry chunks passed in */
539 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
541 start
= KeLoaderModules
[i
].ModStart
;
542 if (strcmp ((PCHAR
) start
, "REGEDIT4") == 0)
544 CPRINT("Process registry chunk at %08lx\n", start
);
545 CmImportHive((PCHAR
) start
);
549 /* Pass 2: process boot loaded drivers */
550 for (i
=1; i
< KeLoaderBlock
.ModsCount
; i
++)
552 start
= KeLoaderModules
[i
].ModStart
;
553 length
= KeLoaderModules
[i
].ModEnd
- start
;
554 name
= (PCHAR
)KeLoaderModules
[i
].String
;
555 if (strcmp ((PCHAR
) start
, "REGEDIT4") != 0)
557 CPRINT("Processing module '%s' at %08lx, length 0x%08lx\n",
558 name
, start
, length
);
559 LdrProcessDriver((PVOID
)start
, name
, length
);
563 /* Create the SystemRoot symbolic link */
564 CPRINT("CommandLine: %s\n", (PUCHAR
)KeLoaderBlock
.CommandLine
);
566 CreateSystemRootLink ((PUCHAR
)KeLoaderBlock
.CommandLine
);
568 #ifdef DBGPRINT_FILE_LOG
569 /* On the assumption that we can now access disks start up the debug
572 #endif /* DBGPRINT_FILE_LOG */
575 CmInitializeRegistry2();
578 * Start the motherboard enumerator (the HAL)
580 HalInitSystem (2, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
583 * Load boot start drivers
585 IopLoadBootStartDrivers();
588 * Load Auto configured drivers
590 LdrLoadAutoConfigDrivers();
593 * Assign drive letters
595 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
,
601 * Initialize shared user page:
602 * - set dos system path, dos device map, etc.
604 InitSystemSharedUserPage ((PUCHAR
)KeLoaderBlock
.CommandLine
);
607 * Launch initial process
609 LdrLoadInitialProcess();
611 PsTerminateSystemThread(STATUS_SUCCESS
);
615 KiSystemStartup(BOOLEAN BootProcessor
)
617 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
621 ExpInitializeExecutive();
624 /* Do application processor initialization */
625 KeApplicationProcessorInit();
626 PsApplicationProcessorInit();
627 KeLowerIrql(PASSIVE_LEVEL
);
628 PsIdleThreadMain(NULL
);
634 _main (ULONG MultiBootMagic
, PLOADER_PARAMETER_BLOCK _LoaderBlock
)
636 * FUNCTION: Called by the boot loader to start the kernel
638 * LoaderBlock = Pointer to boot parameters initialized by the boot
640 * NOTE: The boot parameters are stored in low memory which will become
641 * invalid after the memory managment is initialized so we make a local copy.
646 ULONG last_kernel_address
;
647 extern ULONG _bss_end__
;
650 * Copy the parameters to a local buffer because lowmem will go away
652 memcpy (&KeLoaderBlock
, _LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
653 memcpy (&KeLoaderModules
[1], (PVOID
)KeLoaderBlock
.ModsAddr
,
654 sizeof(LOADER_MODULE
) * KeLoaderBlock
.ModsCount
);
655 KeLoaderBlock
.ModsCount
++;
656 KeLoaderBlock
.ModsAddr
= (ULONG
)&KeLoaderModules
;
659 * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
660 * This should be done by the boot loader.
662 strcpy (KeLoaderCommandLine
,
663 "multi(0)disk(0)rdisk(0)partition(1)\\reactos /DEBUGPORT=SCREEN");
664 strcat (KeLoaderCommandLine
, (PUCHAR
)KeLoaderBlock
.CommandLine
);
666 KeLoaderBlock
.CommandLine
= (ULONG
)KeLoaderCommandLine
;
667 strcpy(KeLoaderModuleStrings
[0], "ntoskrnl.exe");
668 KeLoaderModules
[0].String
= (ULONG
)KeLoaderModuleStrings
[0];
669 KeLoaderModules
[0].ModStart
= 0xC0000000;
670 KeLoaderModules
[0].ModEnd
= PAGE_ROUND_UP((ULONG
)&_bss_end__
);
671 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
673 strcpy(KeLoaderModuleStrings
[i
], (PUCHAR
)KeLoaderModules
[i
].String
);
674 KeLoaderModules
[i
].ModStart
-= 0x200000;
675 KeLoaderModules
[i
].ModStart
+= 0xc0000000;
676 KeLoaderModules
[i
].ModEnd
-= 0x200000;
677 KeLoaderModules
[i
].ModEnd
+= 0xc0000000;
678 KeLoaderModules
[i
].String
= (ULONG
)KeLoaderModuleStrings
[i
];
681 last_kernel_address
= KeLoaderModules
[KeLoaderBlock
.ModsCount
- 1].ModEnd
;
683 FirstKrnlPhysAddr
= KeLoaderModules
[0].ModStart
- 0xc0000000 + 0x200000;
684 LastKrnlPhysAddr
= last_kernel_address
- 0xc0000000 + 0x200000;
685 LastKernelAddress
= last_kernel_address
;
687 KeMemoryMapRangeCount
= 0;
688 if (KeLoaderBlock
.Flags
& MB_FLAGS_MMAP_INFO
)
690 /* We have a memory map from the nice BIOS */
691 size
= *((PULONG
)(KeLoaderBlock
.MmapAddr
- sizeof(ULONG
)));
693 while (i
< KeLoaderBlock
.MmapLength
)
695 memcpy (&KeMemoryMap
[KeMemoryMapRangeCount
],
696 (PVOID
)(KeLoaderBlock
.MmapAddr
+ i
),
697 sizeof(ADDRESS_RANGE
));
698 KeMemoryMapRangeCount
++;