2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/init.c
5 * PURPOSE: Executive initalization
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Added ExpInitializeExecutive
8 * and optimized/cleaned it.
9 * Eric Kohl (ekohl@abo.rhein-zeitung.de)
13 #include <ntos/bootvid.h>
15 #include <internal/debug.h>
17 /* DATA **********************************************************************/
19 extern ULONG MmCoreDumpType
;
20 extern CHAR KiTimerSystemAuditing
;
21 extern PVOID Ki386InitialStackArray
[MAXIMUM_PROCESSORS
];
22 extern ADDRESS_RANGE KeMemoryMap
[64];
23 extern ULONG KeMemoryMapRangeCount
;
24 extern ULONG_PTR FirstKrnlPhysAddr
;
25 extern ULONG_PTR LastKrnlPhysAddr
;
26 extern ULONG_PTR LastKernelAddress
;
27 extern LOADER_MODULE KeLoaderModules
[64];
28 extern PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages
;
29 extern LIST_ENTRY KiProfileListHead
;
30 extern LIST_ENTRY KiProfileSourceListHead
;
31 extern KSPIN_LOCK KiProfileLock
;
32 BOOLEAN SetupMode
= TRUE
;
34 VOID
PspPostInitSystemProcess(VOID
);
36 /* FUNCTIONS ****************************************************************/
41 InitSystemSharedUserPage (PCSZ ParameterLine
)
43 UNICODE_STRING ArcDeviceName
;
44 UNICODE_STRING ArcName
;
45 UNICODE_STRING BootPath
;
46 UNICODE_STRING DriveDeviceName
;
47 UNICODE_STRING DriveName
;
48 WCHAR DriveNameBuffer
[20];
54 OBJECT_ATTRIBUTES ObjectAttributes
;
57 BOOLEAN BootDriveFound
= FALSE
;
61 * The shared user page has been zeroed-out right after creation.
62 * There is NO need to do this again.
64 Ki386SetProcessorFeatures();
66 /* Set the Version Data */
67 SharedUserData
->NtProductType
= NtProductWinNt
;
68 SharedUserData
->ProductTypeIsValid
= TRUE
;
69 SharedUserData
->NtMajorVersion
= 5;
70 SharedUserData
->NtMinorVersion
= 0;
73 * Retrieve the current dos system path
74 * (e.g.: C:\reactos) from the given arc path
75 * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
76 * Format: "<arc_name>\<path> [options...]"
79 /* Create local parameter line copy */
80 ParamBuffer
= ExAllocatePool(PagedPool
, 256);
81 strcpy (ParamBuffer
, (char *)ParameterLine
);
82 DPRINT("%s\n", ParamBuffer
);
85 p
= strchr (ParamBuffer
, ' ');
87 DPRINT("%s\n", ParamBuffer
);
90 p
= strchr (ParamBuffer
, '\\');
93 DPRINT("Boot path: %s\n", p
);
94 RtlCreateUnicodeStringFromAsciiz (&BootPath
, p
);
99 DPRINT("Boot path: %s\n", "\\");
100 RtlCreateUnicodeStringFromAsciiz (&BootPath
, "\\");
102 DPRINT("Arc name: %s\n", ParamBuffer
);
104 /* Only ARC Name left - Build full ARC Name */
105 ArcNameBuffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
106 swprintf (ArcNameBuffer
, L
"\\ArcName\\%S", ParamBuffer
);
107 RtlInitUnicodeString (&ArcName
, ArcNameBuffer
);
108 DPRINT("Arc name: %wZ\n", &ArcName
);
110 /* Free ParamBuffer */
111 ExFreePool (ParamBuffer
);
113 /* Allocate ARC Device Name string */
114 ArcDeviceName
.Length
= 0;
115 ArcDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
116 ArcDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
118 /* Open the Symbolic Link */
119 InitializeObjectAttributes(&ObjectAttributes
,
124 Status
= NtOpenSymbolicLinkObject(&Handle
,
125 SYMBOLIC_LINK_ALL_ACCESS
,
128 /* Free the String */
129 ExFreePool(ArcName
.Buffer
);
131 /* Check for Success */
132 if (!NT_SUCCESS(Status
)) {
134 /* Free the Strings */
135 RtlFreeUnicodeString(&BootPath
);
136 ExFreePool(ArcDeviceName
.Buffer
);
137 CPRINT("NtOpenSymbolicLinkObject() failed (Status %x)\n", Status
);
142 Status
= NtQuerySymbolicLinkObject(Handle
,
147 /* Check for Success */
148 if (!NT_SUCCESS(Status
)) {
150 /* Free the Strings */
151 RtlFreeUnicodeString(&BootPath
);
152 ExFreePool(ArcDeviceName
.Buffer
);
153 CPRINT("NtQuerySymbolicLinkObject() failed (Status %x)\n", Status
);
156 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length
, &ArcDeviceName
);
158 /* Allocate Device Name string */
159 DriveDeviceName
.Length
= 0;
160 DriveDeviceName
.MaximumLength
= 256 * sizeof(WCHAR
);
161 DriveDeviceName
.Buffer
= ExAllocatePool (PagedPool
, 256 * sizeof(WCHAR
));
164 for (i
= 0; i
< 26; i
++) {
166 /* Setup the String */
167 swprintf (DriveNameBuffer
, L
"\\??\\%C:", 'A' + i
);
168 RtlInitUnicodeString(&DriveName
,
171 /* Open the Symbolic Link */
172 InitializeObjectAttributes(&ObjectAttributes
,
177 Status
= NtOpenSymbolicLinkObject(&Handle
,
178 SYMBOLIC_LINK_ALL_ACCESS
,
181 /* If it failed, skip to the next drive */
182 if (!NT_SUCCESS(Status
)) {
183 DPRINT("Failed to open link %wZ\n", &DriveName
);
188 Status
= NtQuerySymbolicLinkObject(Handle
,
192 /* If it failed, skip to the next drive */
193 if (!NT_SUCCESS(Status
)) {
194 DPRINT("Failed to query link %wZ\n", &DriveName
);
197 DPRINT("Opened link: %wZ ==> %wZ\n", &DriveName
, &DriveDeviceName
);
199 /* See if we've found the boot drive */
200 if (!RtlCompareUnicodeString (&ArcDeviceName
, &DriveDeviceName
, FALSE
)) {
202 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i
, &BootPath
);
203 swprintf(SharedUserData
->NtSystemRoot
, L
"%C:%wZ", 'A' + i
, &BootPath
);
204 BootDriveFound
= TRUE
;
207 /* Close this Link */
211 /* Free all the Strings we have in memory */
212 RtlFreeUnicodeString (&BootPath
);
213 ExFreePool(DriveDeviceName
.Buffer
);
214 ExFreePool(ArcDeviceName
.Buffer
);
216 /* Make sure we found the Boot Drive */
217 if (BootDriveFound
== FALSE
) {
219 DbgPrint("No system drive found!\n");
220 KEBUGCHECK (NO_BOOT_DEVICE
);
227 ExecuteRuntimeAsserts(VOID
)
230 * Fail at runtime if someone has changed various structures without
231 * updating the offsets used for the assembler code.
233 ASSERT(FIELD_OFFSET(KTHREAD
, InitialStack
) == KTHREAD_INITIAL_STACK
);
234 ASSERT(FIELD_OFFSET(KTHREAD
, Teb
) == KTHREAD_TEB
);
235 ASSERT(FIELD_OFFSET(KTHREAD
, KernelStack
) == KTHREAD_KERNEL_STACK
);
236 ASSERT(FIELD_OFFSET(KTHREAD
, NpxState
) == KTHREAD_NPX_STATE
);
237 ASSERT(FIELD_OFFSET(KTHREAD
, ServiceTable
) == KTHREAD_SERVICE_TABLE
);
238 ASSERT(FIELD_OFFSET(KTHREAD
, PreviousMode
) == KTHREAD_PREVIOUS_MODE
);
239 ASSERT(FIELD_OFFSET(KTHREAD
, TrapFrame
) == KTHREAD_TRAP_FRAME
);
240 ASSERT(FIELD_OFFSET(KTHREAD
, CallbackStack
) == KTHREAD_CALLBACK_STACK
);
241 ASSERT(FIELD_OFFSET(KTHREAD
, ApcState
.Process
) == KTHREAD_APCSTATE_PROCESS
);
242 ASSERT(FIELD_OFFSET(KPROCESS
, DirectoryTableBase
) == KPROCESS_DIRECTORY_TABLE_BASE
);
243 ASSERT(FIELD_OFFSET(KPROCESS
, IopmOffset
) == KPROCESS_IOPM_OFFSET
);
244 ASSERT(FIELD_OFFSET(KPROCESS
, LdtDescriptor
) == KPROCESS_LDT_DESCRIPTOR0
);
245 ASSERT(FIELD_OFFSET(KTRAP_FRAME
, Reserved9
) == KTRAP_FRAME_RESERVED9
);
246 ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME
, SavedExceptionStack
) == TF_SAVED_EXCEPTION_STACK
);
247 ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME
, regs
) == TF_REGS
);
248 ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME
, orig_ebp
) == TF_ORIG_EBP
);
249 ASSERT(FIELD_OFFSET(KPCR
, Tib
.ExceptionList
) == KPCR_EXCEPTION_LIST
);
250 ASSERT(FIELD_OFFSET(KPCR
, Self
) == KPCR_SELF
);
251 ASSERT(FIELD_OFFSET(KPCR
, PrcbData
) + FIELD_OFFSET(KPRCB
, CurrentThread
) == KPCR_CURRENT_THREAD
);
252 ASSERT(FIELD_OFFSET(KPCR
, PrcbData
) + FIELD_OFFSET(KPRCB
, NpxThread
) == KPCR_NPX_THREAD
);
253 ASSERT(FIELD_OFFSET(KTSS
, Esp0
) == KTSS_ESP0
);
254 ASSERT(FIELD_OFFSET(KTSS
, Eflags
) == KTSS_EFLAGS
);
255 ASSERT(FIELD_OFFSET(KTSS
, IoMapBase
) == KTSS_IOMAPBASE
);
256 ASSERT(sizeof(FX_SAVE_AREA
) == SIZEOF_FX_SAVE_AREA
);
262 ParseAndCacheLoadedModules(VOID
)
267 /* Loop the Module List and get the modules we want */
268 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++) {
270 /* Get the Name of this Module */
271 if (!(Name
= strrchr((PCHAR
)KeLoaderModules
[i
].String
, '\\'))) {
274 Name
= (PCHAR
)KeLoaderModules
[i
].String
;
282 /* Now check for any of the modules we will need later */
283 if (!_stricmp(Name
, "ansi.nls")) {
285 CachedModules
[AnsiCodepage
] = &KeLoaderModules
[i
];
287 } else if (!_stricmp(Name
, "oem.nls")) {
289 CachedModules
[OemCodepage
] = &KeLoaderModules
[i
];
291 } else if (!_stricmp(Name
, "casemap.nls")) {
293 CachedModules
[UnicodeCasemap
] = &KeLoaderModules
[i
];
295 } else if (!_stricmp(Name
, "system") || !_stricmp(Name
, "system.hiv")) {
297 CachedModules
[SystemRegistry
] = &KeLoaderModules
[i
];
300 } else if (!_stricmp(Name
, "hardware") || !_stricmp(Name
, "hardware.hiv")) {
302 CachedModules
[HardwareRegistry
] = &KeLoaderModules
[i
];
310 ParseCommandLine(PULONG MaxMem
,
313 PBOOLEAN ForceAcpiDisable
)
317 p1
= (PCHAR
)KeLoaderBlock
.CommandLine
;
318 while(*p1
&& (p2
= strchr(p1
, '/'))) {
321 if (!_strnicmp(p2
, "MAXMEM", 6)) {
324 while (isspace(*p2
)) p2
++;
330 while(isspace(*p2
)) p2
++;
333 while (isdigit(*p2
)) {
334 *MaxMem
= *MaxMem
* 10 + *p2
- '0';
340 } else if (!_strnicmp(p2
, "NOGUIBOOT", 9)) {
345 } else if (!_strnicmp(p2
, "CRASHDUMP", 9)) {
351 if (!_strnicmp(p2
, "FULL", 4)) {
353 MmCoreDumpType
= MM_CORE_DUMP_TYPE_FULL
;
357 MmCoreDumpType
= MM_CORE_DUMP_TYPE_NONE
;
360 } else if (!_strnicmp(p2
, "BOOTLOG", 7)) {
364 } else if (!_strnicmp(p2
, "NOACPI", 6)) {
367 *ForceAcpiDisable
= TRUE
;
376 ExpDisplayNotice(VOID
)
383 "\n\n\n ReactOS " KERNEL_VERSION_STR
" Setup \n");
385 " \xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD");
391 HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR
" (Build "
392 KERNEL_VERSION_BUILD_STR
")\n");
393 HalDisplayString(RES_STR_LEGAL_COPYRIGHT
);
394 HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
395 "Public License, and you\n");
396 HalDisplayString("are welcome to change it and/or distribute copies of it "
398 HalDisplayString("conditions. There is absolutely no warranty for "
401 /* Display number of Processors */
403 "Found %x system processor(s). [%lu MB Memory]\n",
404 (int)KeNumberProcessors
,
405 (KeLoaderBlock
.MemHigher
+ 1088)/ 1024);
406 HalDisplayString(str
);
413 ExpInitializeExecutive(VOID
)
415 UNICODE_STRING EventName
;
416 HANDLE InitDoneEventHandle
;
417 OBJECT_ATTRIBUTES ObjectAttributes
;
418 BOOLEAN NoGuiBoot
= FALSE
;
419 BOOLEAN BootLog
= FALSE
;
421 BOOLEAN ForceAcpiDisable
= FALSE
;
422 LARGE_INTEGER Timeout
;
423 HANDLE ProcessHandle
;
427 /* Check if the structures match the ASM offset constants */
428 ExecuteRuntimeAsserts();
430 /* Sets up the Text Sections of the Kernel and HAL for debugging */
433 /* Lower the IRQL to Dispatch Level */
434 KeLowerIrql(DISPATCH_LEVEL
);
436 /* Sets up the VDM Data */
439 /* Parse Command Line Settings */
440 ParseCommandLine(&MaxMem
, &NoGuiBoot
, &BootLog
, &ForceAcpiDisable
);
442 /* Initialize Kernel Memory Address Space */
443 MmInit1(FirstKrnlPhysAddr
,
446 (PADDRESS_RANGE
)&KeMemoryMap
,
447 KeMemoryMapRangeCount
,
448 MaxMem
> 8 ? MaxMem
: 4096);
450 /* Parse the Loaded Modules (by FreeLoader) and cache the ones we'll need */
451 ParseAndCacheLoadedModules();
453 /* Initialize the kernel debugger parameters */
454 KdInitSystem(0, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
456 /* Initialize the Dispatcher, Clock and Bug Check Mechanisms. */
459 /* Bring back the IRQL to Passive */
460 KeLowerIrql(PASSIVE_LEVEL
);
462 /* Initialize Profiling */
463 InitializeListHead(&KiProfileListHead
);
464 InitializeListHead(&KiProfileSourceListHead
);
465 KeInitializeSpinLock(&KiProfileLock
);
467 /* Load basic Security for other Managers */
468 if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED
);
470 /* Create the Basic Object Manager Types to allow new Object Types */
473 /* Initialize Lookaside Lists */
476 /* Set up Region Maps, Sections and the Paging File */
479 /* Initialize Tokens now that the Object Manager is ready */
480 if (!SeInit2()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED
);
482 /* Set 1 CPU for now, we'll increment this later */
483 KeNumberProcessors
= 1;
485 /* Initalize the Process Manager */
486 PiInitProcessManager();
488 /* Break into the Debugger if requested */
489 if (KdPollBreakIn()) DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
491 /* Initialize all processors */
492 while (!HalAllProcessorsStarted()) {
494 PVOID ProcessorStack
;
496 /* Set up the Kernel and Process Manager for this CPU */
497 KePrepareForApplicationProcessorInit(KeNumberProcessors
);
498 KeCreateApplicationProcessorIdleThread(KeNumberProcessors
);
500 /* Allocate a stack for use when booting the processor */
501 ProcessorStack
= Ki386InitialStackArray
[((int)KeNumberProcessors
)] + MM_STACK_SIZE
;
503 /* Tell HAL a new CPU is being started */
504 HalStartNextProcessor(0, (ULONG
)ProcessorStack
- 2*sizeof(FX_SAVE_AREA
));
505 KeNumberProcessors
++;
508 /* Do Phase 1 HAL Initalization */
509 HalInitSystem(1, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
511 /* Initialize Basic System Objects and Worker Threads */
514 /* Create the system handle table, assign it to the system process, create
515 the client id table and assign a PID for the system process. This needs
516 to be done before the worker threads are initialized so the system
517 process gets the first PID (4) */
518 PspPostInitSystemProcess();
520 /* initialize the worker threads */
521 ExpInitializeWorkerThreads();
523 /* initialize callbacks */
524 ExpInitializeCallbacks();
526 /* Call KD Providers at Phase 1 */
527 KdInitSystem(1, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
529 /* Initialize I/O Objects, Filesystems, Error Logging and Shutdown */
533 PoInit((PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
, ForceAcpiDisable
);
535 /* Initialize the Registry (Hives are NOT yet loaded!) */
536 CmInitializeRegistry();
538 /* Unmap Low memory, initialize the Page Zeroing and the Balancer Thread */
541 /* Initialize Cache Views */
544 /* Initialize File Locking */
545 FsRtlpInitFileLockingImplementation();
547 /* Report all resources used by hal */
548 HalReportResourceUsage();
550 /* Clear the screen to blue */
551 HalInitSystem(2, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
553 /* Display version number and copyright/warranty message */
556 /* Call KD Providers at Phase 2 */
557 KdInitSystem(2, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
559 /* Import and create NLS Data and Sections */
562 /* Import and Load Registry Hives */
563 CmInitHives(SetupMode
);
565 /* Initialize the time zone information from the registry */
566 ExpInitTimeZoneInfo();
568 /* Enter the kernel debugger before starting up the boot drivers */
569 if (KdDebuggerEnabled
) KdbEnter();
571 /* Setup Drivers and Root Device Node */
574 /* Display the boot screen image if not disabled */
575 if (!NoGuiBoot
) InbvEnableBootDriver(TRUE
);
577 /* Create ARC Names, SystemRoot SymLink, Load Drivers and Assign Letters */
580 /* Load the System DLL and its Entrypoints */
581 LdrpInitializeSystemDll();
583 /* Initialize the Default Locale */
584 PiInitDefaultLocale();
586 /* Initialize shared user page. Set dos system path, dos device map, etc. */
587 InitSystemSharedUserPage ((PCHAR
)KeLoaderBlock
.CommandLine
);
589 /* Create 'ReactOSInitDone' event */
590 RtlInitUnicodeString(&EventName
, L
"\\ReactOSInitDone");
591 InitializeObjectAttributes(&ObjectAttributes
,
596 Status
= ZwCreateEvent(&InitDoneEventHandle
,
599 SynchronizationEvent
,
602 /* Check for Success */
603 if (!NT_SUCCESS(Status
)) {
605 DPRINT1("Failed to create 'ReactOSInitDone' event (Status 0x%x)\n", Status
);
606 InitDoneEventHandle
= INVALID_HANDLE_VALUE
;
609 /* Launch initial process */
610 Status
= LdrLoadInitialProcess(&ProcessHandle
,
613 /* Check for success, Bugcheck if we failed */
614 if (!NT_SUCCESS(Status
)) {
616 KEBUGCHECKEX(SESSION4_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
619 /* Wait on the Completion Event */
620 if (InitDoneEventHandle
!= INVALID_HANDLE_VALUE
) {
622 HANDLE Handles
[2]; /* Init event, Initial process */
624 /* Setup the Handles to wait on */
625 Handles
[0] = InitDoneEventHandle
;
626 Handles
[1] = ProcessHandle
;
628 /* Wait for the system to be initialized */
629 Timeout
.QuadPart
= (LONGLONG
)-1200000000; /* 120 second timeout */
630 Status
= ZwWaitForMultipleObjects(2,
635 if (!NT_SUCCESS(Status
)) {
637 DPRINT1("NtWaitForMultipleObjects failed with status 0x%x!\n", Status
);
639 } else if (Status
== STATUS_TIMEOUT
) {
641 DPRINT1("WARNING: System not initialized after 120 seconds.\n");
643 } else if (Status
== STATUS_WAIT_0
+ 1) {
645 /* Crash the system if the initial process was terminated. */
646 KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
649 /* Disable the Boot Logo */
650 if (!NoGuiBoot
) InbvEnableBootDriver(FALSE
);
652 /* Signal the Event and close the handle */
653 ZwSetEvent(InitDoneEventHandle
, NULL
);
654 ZwClose(InitDoneEventHandle
);
658 /* On failure to create 'ReactOSInitDone' event, go to text mode ASAP */
659 if (!NoGuiBoot
) InbvEnableBootDriver(FALSE
);
661 /* Crash the system if the initial process terminates within 5 seconds. */
662 Timeout
.QuadPart
= (LONGLONG
)-50000000; /* 5 second timeout */
663 Status
= ZwWaitForSingleObject(ProcessHandle
,
667 /* Check for timeout, crash if the initial process didn't initalize */
668 if (Status
!= STATUS_TIMEOUT
) KEBUGCHECKEX(SESSION5_INITIALIZATION_FAILED
, Status
, 1, 0, 0);
671 /* Enable the Clock, close remaining handles */
672 KiTimerSystemAuditing
= 1;
673 ZwClose(ThreadHandle
);
674 ZwClose(ProcessHandle
);
680 ExpInitLookasideLists();
686 ExpInitializeEventImplementation();
687 ExpInitializeEventPairImplementation();
688 ExpInitializeMutantImplementation();
689 ExpInitializeSemaphoreImplementation();
690 ExpInitializeTimerImplementation();
692 ExpInitializeProfileImplementation();
695 ExpInitializeHandleTables();