- Use WinXP style /SOS output when enabled. (TODO: Display banner/memory/cpu).
[reactos.git] / reactos / ntoskrnl / ex / init.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ex/init.c
5 * PURPOSE: Executive Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl (ekohl@rz-online.de)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* DATA **********************************************************************/
17
18 #define BUILD_OSCSDVERSION(major, minor) (((major & 0xFF) << 8) | (minor & 0xFF))
19
20 /* NT Version Info */
21 ULONG NtMajorVersion = 5;
22 ULONG NtMinorVersion = 0;
23 ULONG NtOSCSDVersion = BUILD_OSCSDVERSION(4, 0);
24 ULONG NtBuildNumber = KERNEL_VERSION_BUILD;
25 ULONG NtGlobalFlag;
26 ULONG ExSuiteMask;
27
28 /* Init flags and settings */
29 ULONG ExpInitializationPhase;
30 BOOLEAN ExpInTextModeSetup;
31 BOOLEAN IoRemoteBootClient;
32 ULONG InitSafeBootMode;
33 BOOLEAN InitIsWinPEMode, InitWinPEModeType;
34
35 /* NT Boot Path */
36 UNICODE_STRING NtSystemRoot;
37
38 /* NT Initial User Application */
39 WCHAR NtInitialUserProcessBuffer[128] = L"\\SystemRoot\\System32\\smss.exe";
40 ULONG NtInitialUserProcessBufferLength = sizeof(NtInitialUserProcessBuffer) -
41 sizeof(WCHAR);
42 ULONG NtInitialUserProcessBufferType = REG_SZ;
43
44 /* Boot NLS information */
45 PVOID ExpNlsTableBase;
46 ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
47 ULONG ExpUnicodeCaseTableDataOffset;
48 NLSTABLEINFO ExpNlsTableInfo;
49 ULONG ExpNlsTableSize;
50 PVOID ExpNlsSectionPointer;
51
52 /* CMOS Timer Sanity */
53 BOOLEAN ExCmosClockIsSane = TRUE;
54
55 /* FUNCTIONS ****************************************************************/
56
57 NTSTATUS
58 NTAPI
59 ExpCreateSystemRootLink(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
60 {
61 UNICODE_STRING LinkName;
62 OBJECT_ATTRIBUTES ObjectAttributes;
63 HANDLE LinkHandle;
64 NTSTATUS Status;
65 ANSI_STRING AnsiName;
66 CHAR Buffer[256];
67 ANSI_STRING TargetString;
68 UNICODE_STRING TargetName;
69
70 /* Initialize the ArcName tree */
71 RtlInitUnicodeString(&LinkName, L"\\ArcName");
72 InitializeObjectAttributes(&ObjectAttributes,
73 &LinkName,
74 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
75 NULL,
76 SePublicDefaultUnrestrictedSd);
77
78 /* Create it */
79 Status = NtCreateDirectoryObject(&LinkHandle,
80 DIRECTORY_ALL_ACCESS,
81 &ObjectAttributes);
82 if (!NT_SUCCESS(Status))
83 {
84 /* Failed */
85 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 1, 0, 0);
86 }
87
88 /* Close the LinkHandle */
89 NtClose(LinkHandle);
90
91 /* Initialize the Device tree */
92 RtlInitUnicodeString(&LinkName, L"\\Device");
93 InitializeObjectAttributes(&ObjectAttributes,
94 &LinkName,
95 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
96 NULL,
97 SePublicDefaultUnrestrictedSd);
98
99 /* Create it */
100 Status = NtCreateDirectoryObject(&LinkHandle,
101 DIRECTORY_ALL_ACCESS,
102 &ObjectAttributes);
103 if (!NT_SUCCESS(Status))
104 {
105 /* Failed */
106 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 2, 0, 0);
107 }
108
109 /* Close the LinkHandle */
110 ObCloseHandle(LinkHandle, KernelMode);
111
112 /* Create the system root symlink name */
113 RtlInitAnsiString(&AnsiName, "\\SystemRoot");
114 Status = RtlAnsiStringToUnicodeString(&LinkName, &AnsiName, TRUE);
115 if (!NT_SUCCESS(Status))
116 {
117 /* Failed */
118 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 3, 0, 0);
119 }
120
121 /* Initialize the attributes for the link */
122 InitializeObjectAttributes(&ObjectAttributes,
123 &LinkName,
124 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
125 NULL,
126 SePublicDefaultUnrestrictedSd);
127
128 /* Build the ARC name */
129 sprintf(Buffer,
130 "\\ArcName\\%s%s",
131 LoaderBlock->ArcBootDeviceName,
132 LoaderBlock->NtBootPathName);
133 Buffer[strlen(Buffer) - 1] = ANSI_NULL;
134
135 /* Convert it to Unicode */
136 RtlInitString(&TargetString, Buffer);
137 Status = RtlAnsiStringToUnicodeString(&TargetName,
138 &TargetString,
139 TRUE);
140 if (!NT_SUCCESS(Status))
141 {
142 /* We failed, bugcheck */
143 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 4, 0, 0);
144 }
145
146 /* Create it */
147 Status = NtCreateSymbolicLinkObject(&LinkHandle,
148 SYMBOLIC_LINK_ALL_ACCESS,
149 &ObjectAttributes,
150 &TargetName);
151
152 /* Free the strings */
153 RtlFreeUnicodeString(&LinkName);
154 RtlFreeUnicodeString(&TargetName);
155
156 /* Check if creating the link failed */
157 if (!NT_SUCCESS(Status))
158 {
159 /* Failed */
160 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 5, 0, 0);
161 }
162
163 /* Close the handle and return success */
164 ObCloseHandle(LinkHandle, KernelMode);
165 return STATUS_SUCCESS;
166 }
167
168 VOID
169 NTAPI
170 ExpInitNls(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
171 {
172 LARGE_INTEGER SectionSize;
173 NTSTATUS Status;
174 HANDLE NlsSection;
175 PVOID SectionBase = NULL;
176 ULONG ViewSize = 0;
177 LARGE_INTEGER SectionOffset = {{0}};
178 PLIST_ENTRY ListHead, NextEntry;
179 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
180
181 /* Check if this is boot-time phase 0 initialization */
182 if (!ExpInitializationPhase)
183 {
184 /* Loop the memory descriptors */
185 ListHead = &LoaderBlock->MemoryDescriptorListHead;
186 NextEntry = ListHead->Flink;
187 while (NextEntry != ListHead)
188 {
189 /* Get the current block */
190 MdBlock = CONTAINING_RECORD(NextEntry,
191 MEMORY_ALLOCATION_DESCRIPTOR,
192 ListEntry);
193
194 /* Check if this is an NLS block */
195 if (MdBlock->MemoryType == LoaderNlsData)
196 {
197 /* Increase the table size */
198 ExpNlsTableSize += MdBlock->PageCount * PAGE_SIZE;
199 }
200
201 /* Go to the next block */
202 NextEntry = MdBlock->ListEntry.Flink;
203 }
204
205 /*
206 * In NT, the memory blocks are contiguous, but in ReactOS they aren't,
207 * so unless someone fixes FreeLdr, we'll have to use this icky hack.
208 */
209 ExpNlsTableSize += 2 * PAGE_SIZE; // BIAS FOR FREELDR. HACK!
210
211 /* Allocate the a new buffer since loader memory will be freed */
212 ExpNlsTableBase = ExAllocatePoolWithTag(NonPagedPool,
213 ExpNlsTableSize,
214 TAG('R', 't', 'l', 'i'));
215 if (!ExpNlsTableBase) KeBugCheck(PHASE0_INITIALIZATION_FAILED);
216
217 /* Copy the codepage data in its new location. */
218 RtlCopyMemory(ExpNlsTableBase,
219 LoaderBlock->NlsData->AnsiCodePageData,
220 ExpNlsTableSize);
221
222 /* Initialize and reset the NLS TAbles */
223 RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
224 ExpAnsiCodePageDataOffset),
225 (PVOID)((ULONG_PTR)ExpNlsTableBase +
226 ExpOemCodePageDataOffset),
227 (PVOID)((ULONG_PTR)ExpNlsTableBase +
228 ExpUnicodeCaseTableDataOffset),
229 &ExpNlsTableInfo);
230 RtlResetRtlTranslations(&ExpNlsTableInfo);
231 return;
232 }
233
234 /* Set the section size */
235 SectionSize.QuadPart = ExpNlsTableSize;
236
237 /* Create the NLS Section */
238 Status = ZwCreateSection(&NlsSection,
239 SECTION_ALL_ACCESS,
240 NULL,
241 &SectionSize,
242 PAGE_READWRITE,
243 SEC_COMMIT,
244 NULL);
245 if (!NT_SUCCESS(Status))
246 {
247 /* Failed */
248 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 1, 0, 0);
249 }
250
251 /* Get a pointer to the section */
252 Status = ObReferenceObjectByHandle(NlsSection,
253 SECTION_ALL_ACCESS,
254 MmSectionObjectType,
255 KernelMode,
256 &ExpNlsSectionPointer,
257 NULL);
258 ZwClose(NlsSection);
259 if (!NT_SUCCESS(Status))
260 {
261 /* Failed */
262 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 2, 0, 0);
263 }
264
265 /* Map the NLS Section in system space */
266 Status = MmMapViewInSystemSpace(ExpNlsSectionPointer,
267 &SectionBase,
268 &ExpNlsTableSize);
269 if (!NT_SUCCESS(Status))
270 {
271 /* Failed */
272 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 3, 0, 0);
273 }
274
275 /* Copy the codepage data in its new location. */
276 RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
277
278 /* Free the previously allocated buffer and set the new location */
279 ExFreePool(ExpNlsTableBase);
280 ExpNlsTableBase = SectionBase;
281
282 /* Initialize the NLS Tables */
283 RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
284 ExpAnsiCodePageDataOffset),
285 (PVOID)((ULONG_PTR)ExpNlsTableBase +
286 ExpOemCodePageDataOffset),
287 (PVOID)((ULONG_PTR)ExpNlsTableBase +
288 ExpUnicodeCaseTableDataOffset),
289 &ExpNlsTableInfo);
290 RtlResetRtlTranslations(&ExpNlsTableInfo);
291
292 /* Reset the base to 0 */
293 SectionBase = NULL;
294
295 /* Map the section in the system process */
296 Status = MmMapViewOfSection(ExpNlsSectionPointer,
297 PsGetCurrentProcess(),
298 &SectionBase,
299 0L,
300 0L,
301 &SectionOffset,
302 &ViewSize,
303 ViewShare,
304 0L,
305 PAGE_READWRITE);
306 if (!NT_SUCCESS(Status))
307 {
308 /* Failed */
309 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 5, 0, 0);
310 }
311
312 /* Copy the table into the system process and set this as the base */
313 RtlCopyMemory(SectionBase, ExpNlsTableBase, ExpNlsTableSize);
314 ExpNlsTableBase = SectionBase;
315 }
316
317 NTSTATUS
318 NTAPI
319 ExpLoadInitialProcess(IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation)
320 {
321 PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL;
322 NTSTATUS Status;
323 ULONG Size;
324 PWSTR p;
325 UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
326 UNICODE_STRING SmssName, Environment, SystemDriveString;
327 PVOID EnvironmentPtr = NULL;
328
329 /* Allocate memory for the process parameters */
330 Size = sizeof(RTL_USER_PROCESS_PARAMETERS) +
331 ((MAX_PATH * 6) * sizeof(WCHAR));
332 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
333 (PVOID)&ProcessParameters,
334 0,
335 &Size,
336 MEM_COMMIT,
337 PAGE_READWRITE);
338 if (!NT_SUCCESS(Status))
339 {
340 /* Failed */
341 KeBugCheckEx(SESSION1_INITIALIZATION_FAILED, Status, 0, 0, 0);
342 }
343
344 /* Setup the basic header, and give the process the low 1MB to itself */
345 ProcessParameters->Length = Size;
346 ProcessParameters->MaximumLength = Size;
347 ProcessParameters->Flags = RTL_USER_PROCESS_PARAMETERS_NORMALIZED |
348 RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
349
350 /* Allocate a page for the environment */
351 Size = PAGE_SIZE;
352 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
353 &EnvironmentPtr,
354 0,
355 &Size,
356 MEM_COMMIT,
357 PAGE_READWRITE);
358 if (!NT_SUCCESS(Status))
359 {
360 /* Failed */
361 KeBugCheckEx(SESSION2_INITIALIZATION_FAILED, Status, 0, 0, 0);
362 }
363
364 /* Write the pointer */
365 ProcessParameters->Environment = EnvironmentPtr;
366
367 /* Make a buffer for the DOS path */
368 p = (PWSTR)(ProcessParameters + 1);
369 ProcessParameters->CurrentDirectory.DosPath.Buffer = p;
370 ProcessParameters->
371 CurrentDirectory.DosPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
372
373 /* Copy the DOS path */
374 RtlCopyUnicodeString(&ProcessParameters->CurrentDirectory.DosPath,
375 &NtSystemRoot);
376
377 /* Make a buffer for the DLL Path */
378 p = (PWSTR)((PCHAR)ProcessParameters->CurrentDirectory.DosPath.Buffer +
379 ProcessParameters->CurrentDirectory.DosPath.MaximumLength);
380 ProcessParameters->DllPath.Buffer = p;
381 ProcessParameters->DllPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
382
383 /* Copy the DLL path and append the system32 directory */
384 RtlCopyUnicodeString(&ProcessParameters->DllPath,
385 &ProcessParameters->CurrentDirectory.DosPath);
386 RtlAppendUnicodeToString(&ProcessParameters->DllPath, L"\\System32");
387
388 /* Make a buffer for the image name */
389 p = (PWSTR)((PCHAR)ProcessParameters->DllPath.Buffer +
390 ProcessParameters->DllPath.MaximumLength);
391 ProcessParameters->ImagePathName.Buffer = p;
392 ProcessParameters->ImagePathName.MaximumLength = MAX_PATH * sizeof(WCHAR);
393
394 /* Make sure the buffer is a valid string which within the given length */
395 if ((NtInitialUserProcessBufferType != REG_SZ) ||
396 ((NtInitialUserProcessBufferLength != -1) &&
397 ((NtInitialUserProcessBufferLength < sizeof(WCHAR)) ||
398 (NtInitialUserProcessBufferLength >
399 sizeof(NtInitialUserProcessBuffer) - sizeof(WCHAR)))))
400 {
401 /* Invalid initial process string, bugcheck */
402 KeBugCheckEx(SESSION2_INITIALIZATION_FAILED,
403 (ULONG_PTR)STATUS_INVALID_PARAMETER,
404 NtInitialUserProcessBufferType,
405 NtInitialUserProcessBufferLength,
406 sizeof(NtInitialUserProcessBuffer));
407 }
408
409 /* Cut out anything after a space */
410 p = NtInitialUserProcessBuffer;
411 while (*p && *p != L' ') p++;
412
413 /* Set the image path length */
414 ProcessParameters->ImagePathName.Length =
415 (USHORT)((PCHAR)p - (PCHAR)NtInitialUserProcessBuffer);
416
417 /* Copy the actual buffer */
418 RtlCopyMemory(ProcessParameters->ImagePathName.Buffer,
419 NtInitialUserProcessBuffer,
420 ProcessParameters->ImagePathName.Length);
421
422 /* Null-terminate it */
423 ProcessParameters->
424 ImagePathName.Buffer[ProcessParameters->ImagePathName.Length /
425 sizeof(WCHAR)] = UNICODE_NULL;
426
427 /* Make a buffer for the command line */
428 p = (PWSTR)((PCHAR)ProcessParameters->ImagePathName.Buffer +
429 ProcessParameters->ImagePathName.MaximumLength);
430 ProcessParameters->CommandLine.Buffer = p;
431 ProcessParameters->CommandLine.MaximumLength = MAX_PATH * sizeof(WCHAR);
432
433 /* Add the image name to the command line */
434 RtlAppendUnicodeToString(&ProcessParameters->CommandLine,
435 NtInitialUserProcessBuffer);
436
437 /* Create the environment string */
438 RtlInitEmptyUnicodeString(&Environment,
439 ProcessParameters->Environment,
440 (USHORT)Size);
441
442 /* Append the DLL path to it */
443 RtlAppendUnicodeToString(&Environment, L"Path=" );
444 RtlAppendUnicodeStringToString(&Environment, &ProcessParameters->DllPath);
445 RtlAppendUnicodeStringToString(&Environment, &NullString );
446
447 /* Create the system drive string */
448 SystemDriveString = NtSystemRoot;
449 SystemDriveString.Length = 2 * sizeof(WCHAR);
450
451 /* Append it to the environment */
452 RtlAppendUnicodeToString(&Environment, L"SystemDrive=");
453 RtlAppendUnicodeStringToString(&Environment, &SystemDriveString);
454 RtlAppendUnicodeStringToString(&Environment, &NullString);
455
456 /* Append the system root to the environment */
457 RtlAppendUnicodeToString(&Environment, L"SystemRoot=");
458 RtlAppendUnicodeStringToString(&Environment, &NtSystemRoot);
459 RtlAppendUnicodeStringToString(&Environment, &NullString);
460
461 /* Create SMSS process */
462 SmssName = ProcessParameters->ImagePathName;
463 Status = RtlCreateUserProcess(&SmssName,
464 OBJ_CASE_INSENSITIVE,
465 RtlDeNormalizeProcessParams(
466 ProcessParameters),
467 NULL,
468 NULL,
469 NULL,
470 FALSE,
471 NULL,
472 NULL,
473 ProcessInformation);
474 if (!NT_SUCCESS(Status))
475 {
476 /* Failed */
477 KeBugCheckEx(SESSION3_INITIALIZATION_FAILED, Status, 0, 0, 0);
478 }
479
480 /* Resume the thread */
481 Status = ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
482 if (!NT_SUCCESS(Status))
483 {
484 /* Failed */
485 KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
486 }
487
488 /* Return success */
489 return STATUS_SUCCESS;
490 }
491
492 ULONG
493 NTAPI
494 ExComputeTickCountMultiplier(IN ULONG ClockIncrement)
495 {
496 ULONG MsRemainder = 0, MsIncrement;
497 ULONG IncrementRemainder;
498 ULONG i;
499
500 /* Count the number of milliseconds for each clock interrupt */
501 MsIncrement = ClockIncrement / (10 * 1000);
502
503 /* Count the remainder from the division above, with 24-bit precision */
504 IncrementRemainder = ClockIncrement - (MsIncrement * (10 * 1000));
505 for (i= 0; i < 24; i++)
506 {
507 /* Shift the remainders */
508 MsRemainder <<= 1;
509 IncrementRemainder <<= 1;
510
511 /* Check if we've went past 1 ms */
512 if (IncrementRemainder >= (10 * 1000))
513 {
514 /* Increase the remainder by one, and substract from increment */
515 IncrementRemainder -= (10 * 1000);
516 MsRemainder |= 1;
517 }
518 }
519
520 /* Return the increment */
521 return (MsIncrement << 24) | MsRemainder;
522 }
523
524 BOOLEAN
525 NTAPI
526 ExpInitSystemPhase0(VOID)
527 {
528 /* Initialize EXRESOURCE Support */
529 ExpResourceInitialization();
530
531 /* Initialize the environment lock */
532 ExInitializeFastMutex(&ExpEnvironmentLock);
533
534 /* Initialize the lookaside lists and locks */
535 ExpInitLookasideLists();
536
537 /* Initialize the Firmware Table resource and listhead */
538 InitializeListHead(&ExpFirmwareTableProviderListHead);
539 ExInitializeResourceLite(&ExpFirmwareTableResource);
540
541 /* Set the suite mask to maximum and return */
542 ExSuiteMask = 0xFFFFFFFF;
543 return TRUE;
544 }
545
546 BOOLEAN
547 NTAPI
548 ExpInitSystemPhase1(VOID)
549 {
550 /* Initialize worker threads */
551 ExpInitializeWorkerThreads();
552
553 /* Initialize pushlocks */
554 ExpInitializePushLocks();
555
556 /* Initialize events and event pairs */
557 ExpInitializeEventImplementation();
558 ExpInitializeEventPairImplementation();
559
560 /* Initialize callbacks */
561 ExpInitializeCallbacks();
562
563 /* Initialize mutants */
564 ExpInitializeMutantImplementation();
565
566 /* Initialize semaphores */
567 ExpInitializeSemaphoreImplementation();
568
569 /* Initialize timers */
570 ExpInitializeTimerImplementation();
571
572 /* Initialize profiling */
573 ExpInitializeProfileImplementation();
574
575 /* Initialize UUIDs */
576 ExpInitUuids();
577
578 /* Initialize Win32K */
579 ExpWin32kInit();
580 return TRUE;
581 }
582
583 BOOLEAN
584 NTAPI
585 ExInitSystem(VOID)
586 {
587 /* Check the initialization phase */
588 switch (ExpInitializationPhase)
589 {
590 case 0:
591
592 /* Do Phase 0 */
593 return ExpInitSystemPhase0();
594
595 case 1:
596
597 /* Do Phase 1 */
598 return ExpInitSystemPhase1();
599
600 default:
601
602 /* Don't know any other phase! Bugcheck! */
603 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
604 return FALSE;
605 }
606 }
607
608 BOOLEAN
609 NTAPI
610 ExpIsLoaderValid(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
611 {
612 PLOADER_PARAMETER_EXTENSION Extension;
613
614 /* Get the loader extension */
615 Extension = LoaderBlock->Extension;
616
617 /* Validate the size (larger structures are OK, we'll just ignore them) */
618 if (Extension->Size < sizeof(LOADER_PARAMETER_EXTENSION)) return FALSE;
619
620 /* Don't validate upper versions */
621 if (Extension->MajorVersion > 5) return TRUE;
622
623 /* Fail if this is NT 4 */
624 if (Extension->MajorVersion < 5) return FALSE;
625
626 /* Fail if this is XP */
627 if (Extension->MinorVersion < 2) return FALSE;
628
629 /* This is 2003 or newer, approve it */
630 return TRUE;
631 }
632
633 VOID
634 NTAPI
635 ExpLoadBootSymbols(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
636 {
637 ULONG i = 0;
638 PLIST_ENTRY NextEntry;
639 ULONG Count, Length;
640 PWCHAR Name;
641 PLDR_DATA_TABLE_ENTRY LdrEntry;
642 BOOLEAN OverFlow = FALSE;
643 CHAR NameBuffer[256];
644 ANSI_STRING SymbolString;
645
646 /* Loop the driver list */
647 NextEntry = LoaderBlock->LoadOrderListHead.Flink;
648 while (NextEntry != &LoaderBlock->LoadOrderListHead)
649 {
650 /* Skip the first two images */
651 if (i >= 2)
652 {
653 /* Get the entry */
654 LdrEntry = CONTAINING_RECORD(NextEntry,
655 LDR_DATA_TABLE_ENTRY,
656 InLoadOrderLinks);
657 if (LdrEntry->FullDllName.Buffer[0] == L'\\')
658 {
659 /* We have a name, read its data */
660 Name = LdrEntry->FullDllName.Buffer;
661 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
662
663 /* Check if our buffer can hold it */
664 if (sizeof(NameBuffer) < Length + sizeof(ANSI_NULL))
665 {
666 /* It's too long */
667 OverFlow = TRUE;
668 }
669 else
670 {
671 /* Copy the name */
672 for (Count = 0; Count < Length; Count++, Name++)
673 {
674 /* Copy the character */
675 NameBuffer[Count] = (CHAR)*Name;
676 }
677
678 /* Null-terminate */
679 NameBuffer[Count] = ANSI_NULL;
680 }
681 }
682 else
683 {
684 /* This should be a driver, check if it fits */
685 if (sizeof(NameBuffer) <
686 (sizeof("\\System32\\Drivers\\") +
687 NtSystemRoot.Length / sizeof(WCHAR) - sizeof(UNICODE_NULL) +
688 LdrEntry->BaseDllName.Length / sizeof(WCHAR) +
689 sizeof(ANSI_NULL)))
690 {
691 /* Buffer too small */
692 OverFlow = TRUE;
693 }
694 else
695 {
696 /* Otherwise build the name. HACKED for GCC :( */
697 sprintf(NameBuffer,
698 "%c\\System32\\Drivers\\%S",
699 SharedUserData->NtSystemRoot[2],
700 LdrEntry->BaseDllName.Buffer);
701 }
702 }
703
704 /* Check if the buffer was ok */
705 if (!OverFlow)
706 {
707 /* Initialize the ANSI_STRING for the debugger */
708 RtlInitString(&SymbolString, NameBuffer);
709
710 /* Load the symbols */
711 DbgLoadImageSymbols(&SymbolString,
712 LdrEntry->DllBase,
713 0xFFFFFFFF);
714 }
715 }
716
717 /* Go to the next entry */
718 i++;
719 NextEntry = NextEntry->Flink;
720 }
721
722 /* Check if we should break after symbol load */
723 if (KdBreakAfterSymbolLoad) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
724 }
725
726 VOID
727 NTAPI
728 ExpInitializeExecutive(IN ULONG Cpu,
729 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
730 {
731 PNLS_DATA_BLOCK NlsData;
732 CHAR Buffer[256];
733 ANSI_STRING AnsiPath;
734 NTSTATUS Status;
735 PCHAR CommandLine, PerfMem;
736 ULONG PerfMemUsed;
737
738 /* Validate Loader */
739 if (!ExpIsLoaderValid(LoaderBlock))
740 {
741 /* Invalid loader version */
742 KeBugCheckEx(MISMATCHED_HAL,
743 3,
744 LoaderBlock->Extension->Size,
745 LoaderBlock->Extension->MajorVersion,
746 LoaderBlock->Extension->MinorVersion);
747 }
748
749 /* Initialize PRCB pool lookaside pointers */
750 ExInitPoolLookasidePointers();
751
752 /* Check if this is an application CPU */
753 if (Cpu)
754 {
755 /* Then simply initialize it with HAL */
756 if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
757 {
758 /* Initialization failed */
759 KeBugCheck(HAL_INITIALIZATION_FAILED);
760 }
761
762 /* We're done */
763 return;
764 }
765
766 /* Assume no text-mode or remote boot */
767 ExpInTextModeSetup = FALSE;
768 IoRemoteBootClient = FALSE;
769
770 /* Check if we have a setup loader block */
771 if (LoaderBlock->SetupLdrBlock)
772 {
773 /* Check if this is text-mode setup */
774 if (LoaderBlock->SetupLdrBlock->Flags & 1) ExpInTextModeSetup = TRUE;
775
776 /* Check if this is network boot */
777 if (LoaderBlock->SetupLdrBlock->Flags & 2)
778 {
779 /* Set variable */
780 IoRemoteBootClient = TRUE;
781
782 /* Make sure we're actually booting off the network */
783 ASSERT(!_memicmp(LoaderBlock->ArcBootDeviceName, "net(0)", 6));
784 }
785 }
786
787 /* Set phase to 0 */
788 ExpInitializationPhase = 0;
789
790 /* Get boot command line */
791 CommandLine = LoaderBlock->LoadOptions;
792 if (CommandLine)
793 {
794 /* Upcase it for comparison and check if we're in performance mode */
795 _strupr(CommandLine);
796 PerfMem = strstr(CommandLine, "PERFMEM");
797 if (PerfMem)
798 {
799 /* Check if the user gave a number of bytes to use */
800 PerfMem = strstr(PerfMem, "=");
801 if (PerfMem)
802 {
803 /* Read the number of pages we'll use */
804 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
805 if (PerfMem)
806 {
807 /* FIXME: TODO */
808 DPRINT1("BBT performance mode not yet supported."
809 "/PERFMEM option ignored.\n");
810 }
811 }
812 }
813
814 /* Check if we're burning memory */
815 PerfMem = strstr(CommandLine, "BURNMEMORY");
816 if (PerfMem)
817 {
818 /* Check if the user gave a number of bytes to use */
819 PerfMem = strstr(PerfMem, "=");
820 if (PerfMem)
821 {
822 /* Read the number of pages we'll use */
823 PerfMemUsed = atol(PerfMem + 1) * (1024 * 1024 / PAGE_SIZE);
824 if (PerfMem)
825 {
826 /* FIXME: TODO */
827 DPRINT1("Burnable memory support not yet present."
828 "/BURNMEM option ignored.\n");
829 }
830 }
831 }
832 }
833
834 /* Setup NLS Base and offsets */
835 NlsData = LoaderBlock->NlsData;
836 ExpNlsTableBase = NlsData->AnsiCodePageData;
837 ExpAnsiCodePageDataOffset = 0;
838 ExpOemCodePageDataOffset = ((ULONG_PTR)NlsData->OemCodePageData -
839 (ULONG_PTR)NlsData->AnsiCodePageData);
840 ExpUnicodeCaseTableDataOffset = ((ULONG_PTR)NlsData->UnicodeCodePageData -
841 (ULONG_PTR)NlsData->AnsiCodePageData);
842
843 /* Initialize the NLS Tables */
844 RtlInitNlsTables((PVOID)((ULONG_PTR)ExpNlsTableBase +
845 ExpAnsiCodePageDataOffset),
846 (PVOID)((ULONG_PTR)ExpNlsTableBase +
847 ExpOemCodePageDataOffset),
848 (PVOID)((ULONG_PTR)ExpNlsTableBase +
849 ExpUnicodeCaseTableDataOffset),
850 &ExpNlsTableInfo);
851 RtlResetRtlTranslations(&ExpNlsTableInfo);
852
853 /* Now initialize the HAL */
854 if (!HalInitSystem(ExpInitializationPhase, LoaderBlock))
855 {
856 /* HAL failed to initialize, bugcheck */
857 KeBugCheck(HAL_INITIALIZATION_FAILED);
858 }
859
860 /* Make sure interrupts are active now */
861 _enable();
862
863 /* Clear the crypto exponent */
864 SharedUserData->CryptoExponent = 0;
865
866 /* Set global flags for the checked build */
867 #if DBG
868 NtGlobalFlag |= FLG_ENABLE_CLOSE_EXCEPTIONS |
869 FLG_ENABLE_KDEBUG_SYMBOL_LOAD;
870 #endif
871
872 /* Setup NT System Root Path */
873 sprintf(Buffer, "C:%s", LoaderBlock->NtBootPathName);
874
875 /* Convert to ANSI_STRING and null-terminate it */
876 RtlInitString(&AnsiPath, Buffer );
877 Buffer[--AnsiPath.Length] = ANSI_NULL;
878
879 /* Get the string from KUSER_SHARED_DATA's buffer */
880 RtlInitEmptyUnicodeString(&NtSystemRoot,
881 SharedUserData->NtSystemRoot,
882 sizeof(SharedUserData->NtSystemRoot));
883
884 /* Now fill it in */
885 Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE);
886 if (!NT_SUCCESS(Status)) KEBUGCHECK(SESSION3_INITIALIZATION_FAILED);
887
888 /* Setup bugcheck messages */
889 KiInitializeBugCheck();
890
891 /* Setup initial system settings (FIXME: Needs Cm Rewrite) */
892 //CmGetSystemControlValues(CommandLine, &CmControlVector);
893
894 /* Initialize the executive at phase 0 */
895 if (!ExInitSystem()) KEBUGCHECK(PHASE0_INITIALIZATION_FAILED);
896
897 /* Load boot symbols */
898 ExpLoadBootSymbols(LoaderBlock);
899
900 /* Set system ranges */
901 SharedUserData->Reserved1 = (ULONG_PTR)MmHighestUserAddress;
902 SharedUserData->Reserved3 = (ULONG_PTR)MmSystemRangeStart;
903
904 /* Make a copy of the NLS Tables */
905 ExpInitNls(LoaderBlock);
906
907 /* Check if the user wants a kernel stack trace database */
908 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB)
909 {
910 /* FIXME: TODO */
911 DPRINT1("Kernel-mode stack trace support not yet present."
912 "FLG_KERNEL_STACK_TRACE_DB flag ignored.\n");
913 }
914
915 /* Check if he wanted exception logging */
916 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
917 {
918 /* FIXME: TODO */
919 DPRINT1("Kernel-mode exception logging support not yet present."
920 "FLG_ENABLE_EXCEPTION_LOGGING flag ignored.\n");
921 }
922
923 /* Initialize the Handle Table */
924 ExpInitializeHandleTables();
925
926 #if DBG
927 /* On checked builds, allocate the system call count table */
928 KeServiceDescriptorTable[0].Count =
929 ExAllocatePoolWithTag(NonPagedPool,
930 KiServiceLimit * sizeof(ULONG),
931 TAG('C', 'a', 'l', 'l'));
932
933 /* Use it for the shadow table too */
934 KeServiceDescriptorTableShadow[0].Count = KeServiceDescriptorTable[0].Count;
935
936 /* Make sure allocation succeeded */
937 if (KeServiceDescriptorTable[0].Count)
938 {
939 /* Zero the call counts to 0 */
940 RtlZeroMemory(KeServiceDescriptorTable[0].Count,
941 KiServiceLimit * sizeof(ULONG));
942 }
943 #endif
944
945 /* Create the Basic Object Manager Types to allow new Object Types */
946 if (!ObInit()) KEBUGCHECK(OBJECT_INITIALIZATION_FAILED);
947
948 /* Load basic Security for other Managers */
949 if (!SeInit()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
950
951 /* Initialize the Process Manager */
952 if (!PsInitSystem(LoaderBlock)) KEBUGCHECK(PROCESS_INITIALIZATION_FAILED);
953
954 /* Initialize the PnP Manager */
955 if (!PpInitSystem()) KEBUGCHECK(PP0_INITIALIZATION_FAILED);
956
957 /* Initialize the User-Mode Debugging Subsystem */
958 DbgkInitialize();
959
960 /* Calculate the tick count multiplier */
961 ExpTickCountMultiplier = ExComputeTickCountMultiplier(KeMaximumIncrement);
962 SharedUserData->TickCountMultiplier = ExpTickCountMultiplier;
963
964 /* Set the OS Version */
965 SharedUserData->NtMajorVersion = NtMajorVersion;
966 SharedUserData->NtMinorVersion = NtMinorVersion;
967
968 /* Set the machine type */
969 #if defined(_X86_)
970 SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_I386;
971 SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_I386;
972 #elif defined(_PPC_) // <3 Arty
973 SharedUserData->ImageNumberLow = IMAGE_FILE_MACHINE_POWERPC;
974 SharedUserData->ImageNumberHigh = IMAGE_FILE_MACHINE_POWERPC;
975 #elif
976 #error "Unsupported ReactOS Target"
977 #endif
978 }
979
980 VOID
981 NTAPI
982 Phase1InitializationDiscard(PVOID Context)
983 {
984 PLOADER_PARAMETER_BLOCK LoaderBlock = Context;
985 PCHAR CommandLine, Y2KHackRequired;
986 LARGE_INTEGER Timeout;
987 NTSTATUS Status;
988 TIME_FIELDS TimeFields;
989 LARGE_INTEGER SystemBootTime, UniversalBootTime, OldTime;
990 PRTL_USER_PROCESS_INFORMATION ProcessInfo;
991 BOOLEAN SosEnabled, NoGuiBoot;
992 ULONG YearHack = 0;
993
994 /* Allocate initial process information */
995 ProcessInfo = ExAllocatePoolWithTag(NonPagedPool,
996 sizeof(RTL_USER_PROCESS_INFORMATION),
997 TAG('I', 'n', 'i', 't'));
998 if (!ProcessInfo)
999 {
1000 /* Bugcheck */
1001 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 8, 0, 0);
1002 }
1003
1004 /* Set to phase 1 */
1005 ExpInitializationPhase = 1;
1006
1007 /* Set us at maximum priority */
1008 KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
1009
1010 /* Do Phase 1 HAL Initialization */
1011 if (!HalInitSystem(1, LoaderBlock)) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1012
1013 /* Get the command line and upcase it */
1014 CommandLine = _strupr(LoaderBlock->LoadOptions);
1015
1016 /* Check if GUI Boot is enabled */
1017 NoGuiBoot = (strstr(CommandLine, "NOGUIBOOT")) ? TRUE: FALSE;
1018
1019 /* Get the SOS setting */
1020 SosEnabled = strstr(CommandLine, "SOS") ? TRUE: FALSE;
1021
1022 /* Setup the boot driver */
1023 InbvDisplayInitialize();
1024 if (!ExpInTextModeSetup) InbvDisplayInitialize2(NoGuiBoot);
1025
1026 /* Check if GUI boot is enabled */
1027 if (!NoGuiBoot)
1028 {
1029 /* It is, display the boot logo and enable printing strings */
1030 InbvEnableDisplayString(SosEnabled);
1031 InbvDisplayBootLogo(SosEnabled);
1032 }
1033 else
1034 {
1035 /* Release display ownership if not using GUI boot */
1036 if (!SosEnabled) InbvNotifyDisplayOwnershipLost(NULL);
1037
1038 /* Don't allow boot-time strings */
1039 InbvEnableDisplayString(FALSE);
1040 }
1041
1042 /* Check if this is LiveCD (WinPE) mode */
1043 if (strstr(CommandLine, "MININT"))
1044 {
1045 /* Setup WinPE Settings */
1046 InitIsWinPEMode = TRUE;
1047 InitWinPEModeType |= (strstr(CommandLine, "INRAM")) ? 0x80000000 : 1;
1048 }
1049
1050 /* FIXME: Print product name, version, and build */
1051
1052 /* Initialize Power Subsystem in Phase 0 */
1053 if (!PoInitSystem(0, AcpiTableDetected)) KeBugCheck(INTERNAL_POWER_ERROR);
1054
1055 /* Check for Y2K hack */
1056 Y2KHackRequired = strstr(CommandLine, "YEAR");
1057 if (Y2KHackRequired) Y2KHackRequired = strstr(Y2KHackRequired, "=");
1058 if (Y2KHackRequired) YearHack = atol(Y2KHackRequired + 1);
1059
1060 /* Query the clock */
1061 if ((ExCmosClockIsSane) && (HalQueryRealTimeClock(&TimeFields)))
1062 {
1063 /* Check if we're using the Y2K hack */
1064 if (Y2KHackRequired) TimeFields.Year = (CSHORT)YearHack;
1065
1066 /* Convert to time fields */
1067 RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
1068 UniversalBootTime = SystemBootTime;
1069
1070 #if 0 // FIXME: Won't work until we can read registry data here
1071 /* FIXME: This assumes that the RTC is not already in GMT */
1072 ExpTimeZoneBias.QuadPart = Int32x32To64(ExpLastTimeZoneBias * 60,
1073 10000000);
1074
1075 /* Set the boot time-zone bias */
1076 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
1077 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
1078 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
1079
1080 /* Convert the boot time to local time, and set it */
1081 UniversalBootTime.QuadPart = SystemBootTime.QuadPart +
1082 ExpTimeZoneBias.QuadPart;
1083 #endif
1084
1085 /* Update the system time */
1086 KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
1087
1088 /* Remember this as the boot time */
1089 KeBootTime = UniversalBootTime;
1090 KeBootTimeBias = 0;
1091 }
1092
1093 /* Initialize all processors */
1094 if (!HalAllProcessorsStarted()) KeBugCheck(HAL1_INITIALIZATION_FAILED);
1095
1096 /* FIXME: Print CPU and Memory */
1097
1098 /* Update the progress bar */
1099 InbvUpdateProgressBar(5);
1100
1101 /* Call OB initialization again */
1102 if (!ObInit()) KeBugCheck(OBJECT1_INITIALIZATION_FAILED);
1103
1104 /* Initialize Basic System Objects and Worker Threads */
1105 if (!ExInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 1, 0);
1106
1107 /* Initialize the later stages of the kernel */
1108 if (!KeInitSystem()) KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 2, 0);
1109
1110 /* Call KD Providers at Phase 1 */
1111 if (!KdInitSystem(ExpInitializationPhase, KeLoaderBlock))
1112 {
1113 /* Failed, bugcheck */
1114 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, 0, 0, 3, 0);
1115 }
1116
1117 /* Initialize the SRM in Phase 1 */
1118 if (!SeInit()) KEBUGCHECK(SECURITY1_INITIALIZATION_FAILED);
1119
1120 /* Update the progress bar */
1121 InbvUpdateProgressBar(10);
1122
1123 /* Create SystemRoot Link */
1124 Status = ExpCreateSystemRootLink(LoaderBlock);
1125 if (!NT_SUCCESS(Status))
1126 {
1127 /* Failed to create the system root link */
1128 KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED, Status, 0, 0, 0);
1129 }
1130
1131 /* Set up Region Maps, Sections and the Paging File */
1132 if (!MmInitSystem(1, LoaderBlock)) KeBugCheck(MEMORY1_INITIALIZATION_FAILED);
1133
1134 /* Create NLS section */
1135 ExpInitNls(KeLoaderBlock);
1136
1137 /* Initialize Cache Views */
1138 if (!CcInitializeCacheManager()) KeBugCheck(CACHE_INITIALIZATION_FAILED);
1139
1140 /* Initialize the Registry */
1141 if (!CmInitSystem1()) KeBugCheck(CONFIG_INITIALIZATION_FAILED);
1142
1143 /* Update progress bar */
1144 InbvUpdateProgressBar(15);
1145
1146 /* Update timezone information */
1147 ExRefreshTimeZoneInformation(&SystemBootTime);
1148
1149 /* Initialize the File System Runtime Library */
1150 if (!FsRtlInitSystem()) KeBugCheck(FILE_INITIALIZATION_FAILED);
1151
1152 /* Report all resources used by HAL */
1153 HalReportResourceUsage();
1154
1155 /* Call the debugger DLL once we have KD64 6.0 support */
1156 //KdDebuggerInitialize1(LoaderBlock);
1157
1158 /* Setup PnP Manager in phase 1 */
1159 if (!PpInitSystem()) KeBugCheck(PP1_INITIALIZATION_FAILED);
1160
1161 /* Update progress bar */
1162 InbvUpdateProgressBar(20);
1163
1164 /* Initialize LPC */
1165 if (!LpcInitSystem()) KeBugCheck(LPC_INITIALIZATION_FAILED);
1166
1167 /* Initialize the I/O Subsystem */
1168 if (!IoInitSystem(KeLoaderBlock)) KeBugCheck(IO1_INITIALIZATION_FAILED);
1169
1170 /* Unmap Low memory, and initialize the MPW and Balancer Thread */
1171 MmInitSystem(2, LoaderBlock);
1172
1173 /* Update progress bar */
1174 InbvUpdateProgressBar(80);
1175
1176 /* Initialize VDM support */
1177 KeI386VdmInitialize();
1178
1179 /* Initialize Power Subsystem in Phase 1*/
1180 if (!PoInitSystem(1, AcpiTableDetected)) KeBugCheck(INTERNAL_POWER_ERROR);
1181
1182 /* Initialize the Process Manager at Phase 1 */
1183 if (!PsInitSystem(LoaderBlock)) KeBugCheck(PROCESS1_INITIALIZATION_FAILED);
1184
1185 /* Update progress bar */
1186 InbvUpdateProgressBar(85);
1187
1188 /* Make sure nobody touches the loader block again */
1189 if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
1190 LoaderBlock = Context = NULL;
1191
1192 /* Update progress bar */
1193 InbvUpdateProgressBar(90);
1194
1195 /* Launch initial process */
1196 Status = ExpLoadInitialProcess(ProcessInfo);
1197
1198 /* Update progress bar */
1199 InbvUpdateProgressBar(100);
1200
1201 /* Allow strings to be displayed */
1202 InbvEnableDisplayString(TRUE);
1203
1204 /* Wait 5 seconds for it to initialize */
1205 Timeout.QuadPart = Int32x32To64(5, -10000000);
1206 Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
1207 if (!NoGuiBoot) InbvFinalizeBootLogo();
1208 if (Status == STATUS_SUCCESS)
1209 {
1210 /* Bugcheck the system if SMSS couldn't initialize */
1211 KeBugCheck(SESSION5_INITIALIZATION_FAILED);
1212 }
1213
1214 /* Close process handles */
1215 ZwClose(ProcessInfo->ThreadHandle);
1216 ZwClose(ProcessInfo->ProcessHandle);
1217
1218 /* FIXME: We should free the initial process' memory!*/
1219
1220 /* Increase init phase */
1221 ExpInitializationPhase += 1;
1222
1223 /* Free the process information */
1224 ExFreePool(ProcessInfo);
1225 }
1226
1227 VOID
1228 NTAPI
1229 Phase1Initialization(IN PVOID Context)
1230 {
1231 /* Do the .INIT part of Phase 1 which we can free later */
1232 Phase1InitializationDiscard(Context);
1233
1234 /* Jump into zero page thread */
1235 MmZeroPageThreadMain(NULL);
1236 }
1237