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.94 2001/04/26 03:58:32 phreak 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 <napi/shared_data.h>
42 #include <internal/v86m.h>
43 #include <internal/kd.h>
44 #include <internal/trap.h>
45 #include "../dbg/kdb.h"
48 #include <internal/debug.h>
50 /* GLOBALS *******************************************************************/
52 ULONG EXPORTED NtBuildNumber
= KERNEL_VERSION_BUILD
;
53 ULONG EXPORTED NtGlobalFlag
= 0;
54 CHAR EXPORTED KeNumberProcessors
;
55 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock
;
56 static LOADER_MODULE KeLoaderModules
[64];
57 static UCHAR KeLoaderModuleStrings
[64][256];
58 static UCHAR KeLoaderCommandLine
[256];
59 static ULONG FirstKrnlPhysAddr
;
60 static ULONG LastKrnlPhysAddr
;
61 static ULONG LastKernelAddress
;
62 volatile BOOLEAN Initialized
= FALSE
;
64 /* FUNCTIONS ****************************************************************/
67 CreateSystemRootLink (PCSZ ParameterLine
)
69 UNICODE_STRING LinkName
;
70 UNICODE_STRING DeviceName
;
71 UNICODE_STRING ArcName
;
72 UNICODE_STRING BootPath
;
78 OBJECT_ATTRIBUTES ObjectAttributes
;
81 /* create local parameter line copy */
82 ParamBuffer
= ExAllocatePool (PagedPool
, 256);
83 strcpy (ParamBuffer
, (char *)ParameterLine
);
85 DPRINT("%s\n", ParamBuffer
);
86 /* Format: <arc_name>\<path> [options...] */
89 p
= strchr (ParamBuffer
, ' ');
92 DPRINT("%s\n", ParamBuffer
);
95 p
= strchr (ParamBuffer
, '\\');
98 DPRINT("Boot path: %s\n", p
);
99 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
104 DPRINT("Boot path: %s\n", "\\");
105 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
107 DPRINT("Arc name: %s\n", ParamBuffer
);
109 /* Only arc name left - build full arc name */
110 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
111 swprintf (ArcNameBuffer
,
112 L
"\\ArcName\\%S", ParamBuffer
);
113 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
114 DPRINT1("Arc name: %wZ\n", &ArcName
);
116 /* free ParamBuffer */
117 ExFreePool (ParamBuffer
);
119 /* allocate device name string */
120 DeviceName
.Length
= 0;
121 DeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
122 DeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
124 InitializeObjectAttributes (&ObjectAttributes
,
130 Status
= NtOpenSymbolicLinkObject (&Handle
,
131 SYMBOLIC_LINK_ALL_ACCESS
,
133 if (!NT_SUCCESS(Status
))
135 RtlFreeUnicodeString (&BootPath
);
136 RtlFreeUnicodeString (&DeviceName
);
137 DbgPrint("NtOpenSymbolicLinkObject() '%wZ' failed (Status %x)\n",
140 RtlFreeUnicodeString (&ArcName
);
144 RtlFreeUnicodeString (&ArcName
);
146 Status
= NtQuerySymbolicLinkObject (Handle
,
150 if (!NT_SUCCESS(Status
))
152 RtlFreeUnicodeString (&BootPath
);
153 RtlFreeUnicodeString (&DeviceName
);
154 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
159 DPRINT("Length: %lu DeviceName: %wZ\n", Length
, &DeviceName
);
161 RtlAppendUnicodeStringToString (&DeviceName
,
164 RtlFreeUnicodeString (&BootPath
);
165 DPRINT("DeviceName: %wZ\n", &DeviceName
);
167 /* create the '\SystemRoot' link */
168 RtlInitUnicodeString (&LinkName
,
171 Status
= IoCreateSymbolicLink (&LinkName
,
173 RtlFreeUnicodeString (&DeviceName
);
174 if (!NT_SUCCESS(Status
))
176 DbgPrint("IoCreateSymbolicLink() failed (Status %x)\n",
182 /* Check if '\SystemRoot'(LinkName) can be opened, otherwise crash it! */
183 InitializeObjectAttributes (&ObjectAttributes
,
189 Status
= NtOpenSymbolicLinkObject (&Handle
,
190 SYMBOLIC_LINK_ALL_ACCESS
,
192 if (!NT_SUCCESS(Status
))
194 DbgPrint("NtOpenSymbolicLinkObject() failed to open '\\SystemRoot' (Status %x)\n",
203 InitSystemSharedUserPage (PCSZ ParameterLine
)
205 PKUSER_SHARED_DATA SharedPage
;
207 UNICODE_STRING ArcDeviceName
;
208 UNICODE_STRING ArcName
;
209 UNICODE_STRING BootPath
;
210 UNICODE_STRING DriveDeviceName
;
211 UNICODE_STRING DriveName
;
212 WCHAR DriveNameBuffer
[20];
214 PWCHAR ArcNameBuffer
;
218 OBJECT_ATTRIBUTES ObjectAttributes
;
221 BOOLEAN BootDriveFound
;
223 SharedPage
= (PKUSER_SHARED_DATA
)KERNEL_SHARED_DATA_BASE
;
224 SharedPage
->DosDeviceMap
= 0;
225 SharedPage
->NtProductType
= NtProductWinNt
;
226 for (i
= 0; i
< 32; i
++)
228 SharedPage
->DosDeviceDriveType
[i
] = 0;
231 BootDriveFound
= FALSE
;
234 * Retrieve the current dos system path
235 * (e.g.: C:\reactos) from the given arc path
236 * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
237 * Format: "<arc_name>\<path> [options...]"
240 /* create local parameter line copy */
241 ParamBuffer
= ExAllocatePool (PagedPool
, 256);
242 strcpy (ParamBuffer
, (char *)ParameterLine
);
243 DPRINT("%s\n", ParamBuffer
);
245 /* cut options off */
246 p
= strchr (ParamBuffer
, ' ');
251 DPRINT("%s\n", ParamBuffer
);
254 p
= strchr (ParamBuffer
, '\\');
257 DPRINT("Boot path: %s\n", p
);
258 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
263 DPRINT("Boot path: %s\n", "\\");
264 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
266 DPRINT("Arc name: %s\n", ParamBuffer
);
268 /* Only arc name left - build full arc name */
269 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
270 swprintf (ArcNameBuffer
, L
"\\ArcName\\%S", ParamBuffer
);
271 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
272 DPRINT("Arc name: %wZ\n", &ArcName
);
274 /* free ParamBuffer */
275 ExFreePool (ParamBuffer
);
277 /* allocate arc device name string */
278 ArcDeviceName
.Length
= 0;
279 ArcDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
280 ArcDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
282 InitializeObjectAttributes (&ObjectAttributes
,
288 Status
= NtOpenSymbolicLinkObject (&Handle
,
289 SYMBOLIC_LINK_ALL_ACCESS
,
291 RtlFreeUnicodeString (&ArcName
);
292 if (!NT_SUCCESS(Status
))
294 RtlFreeUnicodeString (&BootPath
);
295 RtlFreeUnicodeString (&ArcDeviceName
);
296 DbgPrint("NtOpenSymbolicLinkObject() failed (Status %x)\n",
302 Status
= NtQuerySymbolicLinkObject (Handle
,
306 if (!NT_SUCCESS(Status
))
308 RtlFreeUnicodeString (&BootPath
);
309 RtlFreeUnicodeString (&ArcDeviceName
);
310 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
315 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length
, &ArcDeviceName
);
318 /* allocate device name string */
319 DriveDeviceName
.Length
= 0;
320 DriveDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
321 DriveDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
323 for (i
= 0; i
< 26; i
++)
325 swprintf (DriveNameBuffer
, L
"\\??\\%C:", 'A' + i
);
326 RtlInitUnicodeString (&DriveName
,
329 InitializeObjectAttributes (&ObjectAttributes
,
335 Status
= NtOpenSymbolicLinkObject (&Handle
,
336 SYMBOLIC_LINK_ALL_ACCESS
,
338 if (!NT_SUCCESS(Status
))
340 DPRINT("Failed to open link %wZ\n",
345 Status
= NtQuerySymbolicLinkObject (Handle
,
348 if (!NT_SUCCESS(Status
))
350 DPRINT("Failed query open link %wZ\n",
354 DPRINT("Opened link: %wZ ==> %wZ\n",
355 &DriveName
, &DriveDeviceName
);
357 if (!RtlCompareUnicodeString (&ArcDeviceName
, &DriveDeviceName
, FALSE
))
359 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i
, &BootPath
);
360 swprintf (SharedPage
->NtSystemRoot
,
361 L
"%C:%wZ", 'A' + i
, &BootPath
);
363 BootDriveFound
= TRUE
;
368 /* set bit in dos drives bitmap (drive available) */
369 SharedPage
->DosDeviceMap
|= (1<<i
);
372 RtlFreeUnicodeString (&BootPath
);
373 RtlFreeUnicodeString (&DriveDeviceName
);
374 RtlFreeUnicodeString (&ArcDeviceName
);
376 DPRINT("DosDeviceMap: 0x%x\n", SharedPage
->DosDeviceMap
);
378 if (BootDriveFound
== FALSE
)
380 DbgPrint("No system drive found!\n");
386 ExpInitializeExecutive(VOID
)
394 * Fail at runtime if someone has changed various structures without
395 * updating the offsets used for the assembler code.
397 assert(FIELD_OFFSET(KTHREAD
, InitialStack
) == KTHREAD_INITIAL_STACK
);
398 assert(FIELD_OFFSET(KTHREAD
, Teb
) == KTHREAD_TEB
);
399 assert(FIELD_OFFSET(KTHREAD
, KernelStack
) == KTHREAD_KERNEL_STACK
);
400 assert(FIELD_OFFSET(KTHREAD
, PreviousMode
) == KTHREAD_PREVIOUS_MODE
);
401 assert(FIELD_OFFSET(KTHREAD
, TrapFrame
) == KTHREAD_TRAP_FRAME
);
402 assert(FIELD_OFFSET(ETHREAD
, ThreadsProcess
) == ETHREAD_THREADS_PROCESS
);
403 assert(FIELD_OFFSET(KPROCESS
, DirectoryTableBase
) ==
404 KPROCESS_DIRECTORY_TABLE_BASE
);
405 assert(FIELD_OFFSET(KTRAP_FRAME
, Reserved9
) == KTRAP_FRAME_RESERVED9
);
406 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, regs
) == TF_REGS
);
407 assert(FIELD_OFFSET(KV86M_TRAP_FRAME
, orig_ebp
) == TF_ORIG_EBP
);
409 assert(FIELD_OFFSET(KPCR
, ExceptionList
) == KPCR_EXCEPTION_LIST
);
410 assert(FIELD_OFFSET(KPCR
, Self
) == KPCR_SELF
);
411 assert(FIELD_OFFSET(KPCR
, CurrentThread
) == KPCR_CURRENT_THREAD
);
415 KeLowerIrql(DISPATCH_LEVEL
);
419 MmInit1(FirstKrnlPhysAddr
, LastKrnlPhysAddr
, LastKernelAddress
);
422 * Initialize the kernel debugger
424 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
425 if (KdPollBreakIn ())
427 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
433 KeLowerIrql(PASSIVE_LEVEL
);
436 PiInitProcessManager();
439 * Display version number and copyright/warranty message
441 HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR
" (Build "
442 KERNEL_VERSION_BUILD_STR
")\n");
443 HalDisplayString(RES_STR_LEGAL_COPYRIGHT
);
444 HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
445 "Public License, and you\n");
446 HalDisplayString("are welcome to change it and/or distribute copies of it "
448 HalDisplayString("conditions. There is absolutely no warranty for "
451 /* Initialize all processors */
452 KeNumberProcessors
= 0;
454 while (!HalAllProcessorsStarted())
456 if (KeNumberProcessors
!= 0)
458 KePrepareForApplicationProcessorInit(KeNumberProcessors
);
459 PsPrepareForApplicationProcessorInit(KeNumberProcessors
);
461 HalInitializeProcessor(KeNumberProcessors
);
462 KeNumberProcessors
++;
465 if (KeNumberProcessors
> 1)
467 sprintf(str
, "Found %d system processors.\n",
472 strcpy(str
, "Found 1 system processor.\n");
474 HalDisplayString(str
);
477 * Initialize various critical subsystems
479 HalInitSystem (1, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
483 LdrInitModuleManagement();
484 CmInitializeRegistry();
488 /* Report all resources used by hal */
489 HalReportResourceUsage ();
492 * Enter the kernel debugger before starting up the boot drivers
499 * Initalize services loaded at boot time
501 DPRINT1("%d files loaded\n",KeLoaderBlock
.ModsCount
);
502 for (i
=0; i
< KeLoaderBlock
.ModsCount
; i
++)
504 DPRINT1("module: %s\n", KeLoaderModules
[i
].String
);
507 /* Pass 1: load registry chunks passed in */
508 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
510 start
= KeLoaderModules
[i
].ModStart
;
511 if (strcmp ((PCHAR
) start
, "REGEDIT4") == 0)
513 DPRINT1("process registry chunk at %08lx\n", start
);
514 CmImportHive((PCHAR
) start
);
518 /* Pass 2: process boot loaded drivers */
519 for (i
=1; i
< KeLoaderBlock
.ModsCount
; i
++)
521 start
= KeLoaderModules
[i
].ModStart
;
522 name
= (PCHAR
)KeLoaderModules
[i
].String
;
523 if (strcmp ((PCHAR
) start
, "REGEDIT4") != 0)
525 DPRINT1("process module '%s' at %08lx\n", name
, start
);
526 LdrProcessDriver((PVOID
)start
, name
);
530 /* Create the SystemRoot symbolic link */
531 DbgPrint("CommandLine: %s\n", (PUCHAR
)KeLoaderBlock
.CommandLine
);
533 CreateSystemRootLink ((PUCHAR
)KeLoaderBlock
.CommandLine
);
535 #ifdef DBGPRINT_FILE_LOG
536 /* On the assumption that we can now access disks start up the debug
539 #endif /* DBGPRINT_FILE_LOG */
542 CmInitializeRegistry2();
545 * Load Auto configured drivers
547 LdrLoadAutoConfigDrivers();
550 * Assign drive letters
552 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
,
558 * Initialize shared user page:
559 * - set dos system path, dos device map, etc.
561 InitSystemSharedUserPage ((PUCHAR
)KeLoaderBlock
.CommandLine
);
564 * Launch initial process
566 LdrLoadInitialProcess();
568 PsTerminateSystemThread(STATUS_SUCCESS
);
572 KiSystemStartup(BOOLEAN BootProcessor
)
574 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
578 ExpInitializeExecutive();
581 /* Do application processor initialization */
582 KeApplicationProcessorInit();
583 PsApplicationProcessorInit();
584 KeLowerIrql(PASSIVE_LEVEL
);
585 PsIdleThreadMain(NULL
);
591 _main (ULONG MultiBootMagic
, PLOADER_PARAMETER_BLOCK _LoaderBlock
)
593 * FUNCTION: Called by the boot loader to start the kernel
595 * LoaderBlock = Pointer to boot parameters initialized by the boot
597 * NOTE: The boot parameters are stored in low memory which will become
598 * invalid after the memory managment is initialized so we make a local copy.
602 ULONG last_kernel_address
;
603 extern ULONG _bss_end__
;
606 * Copy the parameters to a local buffer because lowmem will go away
608 memcpy (&KeLoaderBlock
, _LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
609 memcpy (&KeLoaderModules
[1], (PVOID
)KeLoaderBlock
.ModsAddr
,
610 sizeof(LOADER_MODULE
) * KeLoaderBlock
.ModsCount
);
611 KeLoaderBlock
.ModsCount
++;
612 KeLoaderBlock
.ModsAddr
= (ULONG
)&KeLoaderModules
;
615 * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
616 * This should be done by the boot loader.
618 strcpy (KeLoaderCommandLine
,
619 "multi(0)disk(0)rdisk(0)partition(1)\\reactos /DEBUGPORT=SCREEN");
620 strcat (KeLoaderCommandLine
, (PUCHAR
)KeLoaderBlock
.CommandLine
);
622 KeLoaderBlock
.CommandLine
= (ULONG
)KeLoaderCommandLine
;
623 strcpy(KeLoaderModuleStrings
[0], "ntoskrnl.exe");
624 KeLoaderModules
[0].String
= (ULONG
)KeLoaderModuleStrings
[0];
625 KeLoaderModules
[0].ModStart
= 0xC0000000;
626 KeLoaderModules
[0].ModEnd
= PAGE_ROUND_UP((ULONG
)&_bss_end__
);
627 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
629 strcpy(KeLoaderModuleStrings
[i
], (PUCHAR
)KeLoaderModules
[i
].String
);
630 KeLoaderModules
[i
].ModStart
-= 0x200000;
631 KeLoaderModules
[i
].ModStart
+= 0xc0000000;
632 KeLoaderModules
[i
].ModEnd
-= 0x200000;
633 KeLoaderModules
[i
].ModEnd
+= 0xc0000000;
634 KeLoaderModules
[i
].String
= (ULONG
)KeLoaderModuleStrings
[i
];
637 last_kernel_address
= KeLoaderModules
[KeLoaderBlock
.ModsCount
- 1].ModEnd
;
639 FirstKrnlPhysAddr
= KeLoaderModules
[0].ModStart
- 0xc0000000 + 0x200000;
640 LastKrnlPhysAddr
= last_kernel_address
- 0xc0000000 + 0x200000;
641 LastKernelAddress
= last_kernel_address
;