9d947bbc2932df8639a7ce21dc6a1a5d3bf5b06e
[reactos.git] / reactos / ntoskrnl / ke / main.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: main.c,v 1.94 2001/04/26 03:58:32 phreak Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/main.c
23 * PURPOSE: Initalizes the kernel
24 * PROGRAMMER: David Welch (welch@cwcom.net)
25 * UPDATE HISTORY:
26 * 28/05/98: Created
27 */
28
29 /* INCLUDES *****************************************************************/
30
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"
46
47 #define NDEBUG
48 #include <internal/debug.h>
49
50 /* GLOBALS *******************************************************************/
51
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;
63
64 /* FUNCTIONS ****************************************************************/
65
66 static VOID
67 CreateSystemRootLink (PCSZ ParameterLine)
68 {
69 UNICODE_STRING LinkName;
70 UNICODE_STRING DeviceName;
71 UNICODE_STRING ArcName;
72 UNICODE_STRING BootPath;
73 PCHAR ParamBuffer;
74 PWCHAR ArcNameBuffer;
75 PCHAR p;
76 NTSTATUS Status;
77 ULONG Length;
78 OBJECT_ATTRIBUTES ObjectAttributes;
79 HANDLE Handle;
80
81 /* create local parameter line copy */
82 ParamBuffer = ExAllocatePool (PagedPool, 256);
83 strcpy (ParamBuffer, (char *)ParameterLine);
84
85 DPRINT("%s\n", ParamBuffer);
86 /* Format: <arc_name>\<path> [options...] */
87
88 /* cut options off */
89 p = strchr (ParamBuffer, ' ');
90 if (p)
91 *p = 0;
92 DPRINT("%s\n", ParamBuffer);
93
94 /* extract path */
95 p = strchr (ParamBuffer, '\\');
96 if (p)
97 {
98 DPRINT("Boot path: %s\n", p);
99 RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
100 *p = 0;
101 }
102 else
103 {
104 DPRINT("Boot path: %s\n", "\\");
105 RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
106 }
107 DPRINT("Arc name: %s\n", ParamBuffer);
108
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);
115
116 /* free ParamBuffer */
117 ExFreePool (ParamBuffer);
118
119 /* allocate device name string */
120 DeviceName.Length = 0;
121 DeviceName.MaximumLength = 256 * sizeof(WCHAR);
122 DeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
123
124 InitializeObjectAttributes (&ObjectAttributes,
125 &ArcName,
126 0,
127 NULL,
128 NULL);
129
130 Status = NtOpenSymbolicLinkObject (&Handle,
131 SYMBOLIC_LINK_ALL_ACCESS,
132 &ObjectAttributes);
133 if (!NT_SUCCESS(Status))
134 {
135 RtlFreeUnicodeString (&BootPath);
136 RtlFreeUnicodeString (&DeviceName);
137 DbgPrint("NtOpenSymbolicLinkObject() '%wZ' failed (Status %x)\n",
138 &ArcName,
139 Status);
140 RtlFreeUnicodeString (&ArcName);
141
142 KeBugCheck (0x0);
143 }
144 RtlFreeUnicodeString (&ArcName);
145
146 Status = NtQuerySymbolicLinkObject (Handle,
147 &DeviceName,
148 &Length);
149 NtClose (Handle);
150 if (!NT_SUCCESS(Status))
151 {
152 RtlFreeUnicodeString (&BootPath);
153 RtlFreeUnicodeString (&DeviceName);
154 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
155 Status);
156
157 KeBugCheck (0x0);
158 }
159 DPRINT("Length: %lu DeviceName: %wZ\n", Length, &DeviceName);
160
161 RtlAppendUnicodeStringToString (&DeviceName,
162 &BootPath);
163
164 RtlFreeUnicodeString (&BootPath);
165 DPRINT("DeviceName: %wZ\n", &DeviceName);
166
167 /* create the '\SystemRoot' link */
168 RtlInitUnicodeString (&LinkName,
169 L"\\SystemRoot");
170
171 Status = IoCreateSymbolicLink (&LinkName,
172 &DeviceName);
173 RtlFreeUnicodeString (&DeviceName);
174 if (!NT_SUCCESS(Status))
175 {
176 DbgPrint("IoCreateSymbolicLink() failed (Status %x)\n",
177 Status);
178
179 KeBugCheck (0x0);
180 }
181
182 /* Check if '\SystemRoot'(LinkName) can be opened, otherwise crash it! */
183 InitializeObjectAttributes (&ObjectAttributes,
184 &LinkName,
185 0,
186 NULL,
187 NULL);
188
189 Status = NtOpenSymbolicLinkObject (&Handle,
190 SYMBOLIC_LINK_ALL_ACCESS,
191 &ObjectAttributes);
192 if (!NT_SUCCESS(Status))
193 {
194 DbgPrint("NtOpenSymbolicLinkObject() failed to open '\\SystemRoot' (Status %x)\n",
195 Status);
196 KeBugCheck (0x0);
197 }
198 NtClose(Handle);
199 }
200
201
202 static VOID
203 InitSystemSharedUserPage (PCSZ ParameterLine)
204 {
205 PKUSER_SHARED_DATA SharedPage;
206
207 UNICODE_STRING ArcDeviceName;
208 UNICODE_STRING ArcName;
209 UNICODE_STRING BootPath;
210 UNICODE_STRING DriveDeviceName;
211 UNICODE_STRING DriveName;
212 WCHAR DriveNameBuffer[20];
213 PCHAR ParamBuffer;
214 PWCHAR ArcNameBuffer;
215 PCHAR p;
216 NTSTATUS Status;
217 ULONG Length;
218 OBJECT_ATTRIBUTES ObjectAttributes;
219 HANDLE Handle;
220 ULONG i;
221 BOOLEAN BootDriveFound;
222
223 SharedPage = (PKUSER_SHARED_DATA)KERNEL_SHARED_DATA_BASE;
224 SharedPage->DosDeviceMap = 0;
225 SharedPage->NtProductType = NtProductWinNt;
226 for (i = 0; i < 32; i++)
227 {
228 SharedPage->DosDeviceDriveType[i] = 0;
229 }
230
231 BootDriveFound = FALSE;
232
233 /*
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...]"
238 */
239
240 /* create local parameter line copy */
241 ParamBuffer = ExAllocatePool (PagedPool, 256);
242 strcpy (ParamBuffer, (char *)ParameterLine);
243 DPRINT("%s\n", ParamBuffer);
244
245 /* cut options off */
246 p = strchr (ParamBuffer, ' ');
247 if (p)
248 {
249 *p = 0;
250 }
251 DPRINT("%s\n", ParamBuffer);
252
253 /* extract path */
254 p = strchr (ParamBuffer, '\\');
255 if (p)
256 {
257 DPRINT("Boot path: %s\n", p);
258 RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
259 *p = 0;
260 }
261 else
262 {
263 DPRINT("Boot path: %s\n", "\\");
264 RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
265 }
266 DPRINT("Arc name: %s\n", ParamBuffer);
267
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);
273
274 /* free ParamBuffer */
275 ExFreePool (ParamBuffer);
276
277 /* allocate arc device name string */
278 ArcDeviceName.Length = 0;
279 ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
280 ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
281
282 InitializeObjectAttributes (&ObjectAttributes,
283 &ArcName,
284 0,
285 NULL,
286 NULL);
287
288 Status = NtOpenSymbolicLinkObject (&Handle,
289 SYMBOLIC_LINK_ALL_ACCESS,
290 &ObjectAttributes);
291 RtlFreeUnicodeString (&ArcName);
292 if (!NT_SUCCESS(Status))
293 {
294 RtlFreeUnicodeString (&BootPath);
295 RtlFreeUnicodeString (&ArcDeviceName);
296 DbgPrint("NtOpenSymbolicLinkObject() failed (Status %x)\n",
297 Status);
298
299 KeBugCheck (0x0);
300 }
301
302 Status = NtQuerySymbolicLinkObject (Handle,
303 &ArcDeviceName,
304 &Length);
305 NtClose (Handle);
306 if (!NT_SUCCESS(Status))
307 {
308 RtlFreeUnicodeString (&BootPath);
309 RtlFreeUnicodeString (&ArcDeviceName);
310 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
311 Status);
312
313 KeBugCheck (0x0);
314 }
315 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
316
317
318 /* allocate device name string */
319 DriveDeviceName.Length = 0;
320 DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
321 DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
322
323 for (i = 0; i < 26; i++)
324 {
325 swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
326 RtlInitUnicodeString (&DriveName,
327 DriveNameBuffer);
328
329 InitializeObjectAttributes (&ObjectAttributes,
330 &DriveName,
331 0,
332 NULL,
333 NULL);
334
335 Status = NtOpenSymbolicLinkObject (&Handle,
336 SYMBOLIC_LINK_ALL_ACCESS,
337 &ObjectAttributes);
338 if (!NT_SUCCESS(Status))
339 {
340 DPRINT("Failed to open link %wZ\n",
341 &DriveName);
342 continue;
343 }
344
345 Status = NtQuerySymbolicLinkObject (Handle,
346 &DriveDeviceName,
347 &Length);
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT("Failed query open link %wZ\n",
351 &DriveName);
352 continue;
353 }
354 DPRINT("Opened link: %wZ ==> %wZ\n",
355 &DriveName, &DriveDeviceName);
356
357 if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE))
358 {
359 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
360 swprintf (SharedPage->NtSystemRoot,
361 L"%C:%wZ", 'A' + i, &BootPath);
362
363 BootDriveFound = TRUE;
364 }
365
366 NtClose (Handle);
367
368 /* set bit in dos drives bitmap (drive available) */
369 SharedPage->DosDeviceMap |= (1<<i);
370 }
371
372 RtlFreeUnicodeString (&BootPath);
373 RtlFreeUnicodeString (&DriveDeviceName);
374 RtlFreeUnicodeString (&ArcDeviceName);
375
376 DPRINT("DosDeviceMap: 0x%x\n", SharedPage->DosDeviceMap);
377
378 if (BootDriveFound == FALSE)
379 {
380 DbgPrint("No system drive found!\n");
381 KeBugCheck (0x0);
382 }
383 }
384
385 VOID
386 ExpInitializeExecutive(VOID)
387 {
388 ULONG i;
389 ULONG start;
390 PCHAR name;
391 CHAR str[50];
392
393 /*
394 * Fail at runtime if someone has changed various structures without
395 * updating the offsets used for the assembler code.
396 */
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);
408
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);
412
413 LdrInit1();
414
415 KeLowerIrql(DISPATCH_LEVEL);
416
417 NtEarlyInitVdm();
418
419 MmInit1(FirstKrnlPhysAddr, LastKrnlPhysAddr, LastKernelAddress);
420
421 /*
422 * Initialize the kernel debugger
423 */
424 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
425 if (KdPollBreakIn ())
426 {
427 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
428 }
429
430 MmInit2();
431 KeInit2();
432
433 KeLowerIrql(PASSIVE_LEVEL);
434
435 ObInit();
436 PiInitProcessManager();
437
438 /*
439 * Display version number and copyright/warranty message
440 */
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 "
447 "under certain\n");
448 HalDisplayString("conditions. There is absolutely no warranty for "
449 "ReactOS.\n");
450
451 /* Initialize all processors */
452 KeNumberProcessors = 0;
453
454 while (!HalAllProcessorsStarted())
455 {
456 if (KeNumberProcessors != 0)
457 {
458 KePrepareForApplicationProcessorInit(KeNumberProcessors);
459 PsPrepareForApplicationProcessorInit(KeNumberProcessors);
460 }
461 HalInitializeProcessor(KeNumberProcessors);
462 KeNumberProcessors++;
463 }
464
465 if (KeNumberProcessors > 1)
466 {
467 sprintf(str, "Found %d system processors.\n",
468 KeNumberProcessors);
469 }
470 else
471 {
472 strcpy(str, "Found 1 system processor.\n");
473 }
474 HalDisplayString(str);
475
476 /*
477 * Initialize various critical subsystems
478 */
479 HalInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
480
481 ExInit();
482 IoInit();
483 LdrInitModuleManagement();
484 CmInitializeRegistry();
485 NtInit();
486 MmInit3();
487
488 /* Report all resources used by hal */
489 HalReportResourceUsage ();
490
491 /*
492 * Enter the kernel debugger before starting up the boot drivers
493 */
494 #ifdef KDBG
495 KdbEnter();
496 #endif /* KDBG */
497
498 /*
499 * Initalize services loaded at boot time
500 */
501 DPRINT1("%d files loaded\n",KeLoaderBlock.ModsCount);
502 for (i=0; i < KeLoaderBlock.ModsCount; i++)
503 {
504 DPRINT1("module: %s\n", KeLoaderModules[i].String);
505 }
506
507 /* Pass 1: load registry chunks passed in */
508 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
509 {
510 start = KeLoaderModules[i].ModStart;
511 if (strcmp ((PCHAR) start, "REGEDIT4") == 0)
512 {
513 DPRINT1("process registry chunk at %08lx\n", start);
514 CmImportHive((PCHAR) start);
515 }
516 }
517
518 /* Pass 2: process boot loaded drivers */
519 for (i=1; i < KeLoaderBlock.ModsCount; i++)
520 {
521 start = KeLoaderModules[i].ModStart;
522 name = (PCHAR)KeLoaderModules[i].String;
523 if (strcmp ((PCHAR) start, "REGEDIT4") != 0)
524 {
525 DPRINT1("process module '%s' at %08lx\n", name, start);
526 LdrProcessDriver((PVOID)start, name);
527 }
528 }
529
530 /* Create the SystemRoot symbolic link */
531 DbgPrint("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
532
533 CreateSystemRootLink ((PUCHAR)KeLoaderBlock.CommandLine);
534
535 #ifdef DBGPRINT_FILE_LOG
536 /* On the assumption that we can now access disks start up the debug
537 logger thread */
538 DebugLogInit2();
539 #endif /* DBGPRINT_FILE_LOG */
540
541
542 CmInitializeRegistry2();
543
544 /*
545 * Load Auto configured drivers
546 */
547 LdrLoadAutoConfigDrivers();
548
549 /*
550 * Assign drive letters
551 */
552 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock,
553 NULL,
554 NULL,
555 NULL);
556
557 /*
558 * Initialize shared user page:
559 * - set dos system path, dos device map, etc.
560 */
561 InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
562
563 /*
564 * Launch initial process
565 */
566 LdrLoadInitialProcess();
567
568 PsTerminateSystemThread(STATUS_SUCCESS);
569 }
570
571 VOID
572 KiSystemStartup(BOOLEAN BootProcessor)
573 {
574 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
575 if (BootProcessor)
576 {
577 /* Never returns */
578 ExpInitializeExecutive();
579 KeBugCheck(0);
580 }
581 /* Do application processor initialization */
582 KeApplicationProcessorInit();
583 PsApplicationProcessorInit();
584 KeLowerIrql(PASSIVE_LEVEL);
585 PsIdleThreadMain(NULL);
586 KeBugCheck(0);
587 for(;;);
588 }
589
590 VOID
591 _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
592 /*
593 * FUNCTION: Called by the boot loader to start the kernel
594 * ARGUMENTS:
595 * LoaderBlock = Pointer to boot parameters initialized by the boot
596 * loader
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.
599 */
600 {
601 ULONG i;
602 ULONG last_kernel_address;
603 extern ULONG _bss_end__;
604
605 /*
606 * Copy the parameters to a local buffer because lowmem will go away
607 */
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;
613
614 /*
615 * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
616 * This should be done by the boot loader.
617 */
618 strcpy (KeLoaderCommandLine,
619 "multi(0)disk(0)rdisk(0)partition(1)\\reactos /DEBUGPORT=SCREEN");
620 strcat (KeLoaderCommandLine, (PUCHAR)KeLoaderBlock.CommandLine);
621
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++)
628 {
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];
635 }
636
637 last_kernel_address = KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd;
638
639 FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000;
640 LastKrnlPhysAddr = last_kernel_address - 0xc0000000 + 0x200000;
641 LastKernelAddress = last_kernel_address;
642
643 KeInit1();
644
645 KiSystemStartup(1);
646 }
647
648 /* EOF */
649