9993ff9860ec66aafd1cd96467adf7125c7776e8
[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.85 2001/03/27 21:43:42 dwelch 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
46 #define NDEBUG
47 #include <internal/debug.h>
48
49 /* GLOBALS *******************************************************************/
50
51 ULONG EXPORTED NtBuildNumber = KERNEL_VERSION_BUILD;
52 ULONG EXPORTED NtGlobalFlag = 0;
53 CHAR EXPORTED KeNumberProcessors = 1;
54 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
55 static LOADER_MODULE KeLoaderModules[64];
56 static UCHAR KeLoaderModuleStrings[64][256];
57 static UCHAR KeLoaderCommandLine[256];
58
59 /* FUNCTIONS ****************************************************************/
60
61 static VOID
62 CreateSystemRootLink (PCSZ ParameterLine)
63 {
64 UNICODE_STRING LinkName;
65 UNICODE_STRING DeviceName;
66 UNICODE_STRING ArcName;
67 UNICODE_STRING BootPath;
68 PCHAR ParamBuffer;
69 PWCHAR ArcNameBuffer;
70 PCHAR p;
71 NTSTATUS Status;
72 ULONG Length;
73 OBJECT_ATTRIBUTES ObjectAttributes;
74 HANDLE Handle;
75
76 /* create local parameter line copy */
77 ParamBuffer = ExAllocatePool (PagedPool, 256);
78 strcpy (ParamBuffer, (char *)ParameterLine);
79
80 DPRINT("%s\n", ParamBuffer);
81 /* Format: <arc_name>\<path> [options...] */
82
83 /* cut options off */
84 p = strchr (ParamBuffer, ' ');
85 if (p)
86 *p = 0;
87 DPRINT("%s\n", ParamBuffer);
88
89 /* extract path */
90 p = strchr (ParamBuffer, '\\');
91 if (p)
92 {
93 DPRINT("Boot path: %s\n", p);
94 RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
95 *p = 0;
96 }
97 else
98 {
99 DPRINT("Boot path: %s\n", "\\");
100 RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
101 }
102 DPRINT("Arc name: %s\n", ParamBuffer);
103
104 /* Only arc name left - build full arc name */
105 ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
106 swprintf (ArcNameBuffer,
107 L"\\ArcName\\%S", ParamBuffer);
108 RtlInitUnicodeString (&ArcName, ArcNameBuffer);
109 DPRINT1("Arc name: %wZ\n", &ArcName);
110
111 /* free ParamBuffer */
112 ExFreePool (ParamBuffer);
113
114 /* allocate device name string */
115 DeviceName.Length = 0;
116 DeviceName.MaximumLength = 256 * sizeof(WCHAR);
117 DeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
118
119 InitializeObjectAttributes (&ObjectAttributes,
120 &ArcName,
121 0,
122 NULL,
123 NULL);
124
125 Status = NtOpenSymbolicLinkObject (&Handle,
126 SYMBOLIC_LINK_ALL_ACCESS,
127 &ObjectAttributes);
128 if (!NT_SUCCESS(Status))
129 {
130 RtlFreeUnicodeString (&BootPath);
131 RtlFreeUnicodeString (&DeviceName);
132 DbgPrint("NtOpenSymbolicLinkObject() '%wZ' failed (Status %x)\n",
133 &ArcName,
134 Status);
135 RtlFreeUnicodeString (&ArcName);
136
137 KeBugCheck (0x0);
138 }
139 RtlFreeUnicodeString (&ArcName);
140
141 Status = NtQuerySymbolicLinkObject (Handle,
142 &DeviceName,
143 &Length);
144 NtClose (Handle);
145 if (!NT_SUCCESS(Status))
146 {
147 RtlFreeUnicodeString (&BootPath);
148 RtlFreeUnicodeString (&DeviceName);
149 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
150 Status);
151
152 KeBugCheck (0x0);
153 }
154 DPRINT("Length: %lu DeviceName: %wZ\n", Length, &DeviceName);
155
156 RtlAppendUnicodeStringToString (&DeviceName,
157 &BootPath);
158
159 RtlFreeUnicodeString (&BootPath);
160 DPRINT("DeviceName: %wZ\n", &DeviceName);
161
162 /* create the '\SystemRoot' link */
163 RtlInitUnicodeString (&LinkName,
164 L"\\SystemRoot");
165
166 Status = IoCreateSymbolicLink (&LinkName,
167 &DeviceName);
168 RtlFreeUnicodeString (&DeviceName);
169 if (!NT_SUCCESS(Status))
170 {
171 DbgPrint("IoCreateSymbolicLink() failed (Status %x)\n",
172 Status);
173
174 KeBugCheck (0x0);
175 }
176
177 /* Check if '\SystemRoot'(LinkName) can be opened, otherwise crash it! */
178 InitializeObjectAttributes (&ObjectAttributes,
179 &LinkName,
180 0,
181 NULL,
182 NULL);
183
184 Status = NtOpenSymbolicLinkObject (&Handle,
185 SYMBOLIC_LINK_ALL_ACCESS,
186 &ObjectAttributes);
187 if (!NT_SUCCESS(Status))
188 {
189 DbgPrint("NtOpenSymbolicLinkObject() failed to open '\\SystemRoot' (Status %x)\n",
190 Status);
191 KeBugCheck (0x0);
192 }
193 NtClose(Handle);
194 }
195
196
197 static VOID
198 InitSystemSharedUserPage (PCSZ ParameterLine)
199 {
200 PKUSER_SHARED_DATA SharedPage;
201
202 UNICODE_STRING ArcDeviceName;
203 UNICODE_STRING ArcName;
204 UNICODE_STRING BootPath;
205 UNICODE_STRING DriveDeviceName;
206 UNICODE_STRING DriveName;
207 WCHAR DriveNameBuffer[20];
208 PCHAR ParamBuffer;
209 PWCHAR ArcNameBuffer;
210 PCHAR p;
211 NTSTATUS Status;
212 ULONG Length;
213 OBJECT_ATTRIBUTES ObjectAttributes;
214 HANDLE Handle;
215 ULONG i;
216 BOOLEAN BootDriveFound;
217
218 SharedPage = (PKUSER_SHARED_DATA)KERNEL_SHARED_DATA_BASE;
219 SharedPage->DosDeviceMap = 0;
220 SharedPage->NtProductType = NtProductWinNt;
221 for (i = 0; i < 32; i++)
222 {
223 SharedPage->DosDeviceDriveType[i] = 0;
224 }
225
226 BootDriveFound = FALSE;
227
228 /*
229 * Retrieve the current dos system path
230 * (e.g.: C:\reactos) from the given arc path
231 * (e.g.: multi(0)disk(0)rdisk(0)partititon(1)\reactos)
232 * Format: "<arc_name>\<path> [options...]"
233 */
234
235 /* create local parameter line copy */
236 ParamBuffer = ExAllocatePool (PagedPool, 256);
237 strcpy (ParamBuffer, (char *)ParameterLine);
238 DPRINT("%s\n", ParamBuffer);
239
240 /* cut options off */
241 p = strchr (ParamBuffer, ' ');
242 if (p)
243 {
244 *p = 0;
245 }
246 DPRINT("%s\n", ParamBuffer);
247
248 /* extract path */
249 p = strchr (ParamBuffer, '\\');
250 if (p)
251 {
252 DPRINT("Boot path: %s\n", p);
253 RtlCreateUnicodeStringFromAsciiz (&BootPath, p);
254 *p = 0;
255 }
256 else
257 {
258 DPRINT("Boot path: %s\n", "\\");
259 RtlCreateUnicodeStringFromAsciiz (&BootPath, "\\");
260 }
261 DPRINT("Arc name: %s\n", ParamBuffer);
262
263 /* Only arc name left - build full arc name */
264 ArcNameBuffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
265 swprintf (ArcNameBuffer, L"\\ArcName\\%S", ParamBuffer);
266 RtlInitUnicodeString (&ArcName, ArcNameBuffer);
267 DPRINT("Arc name: %wZ\n", &ArcName);
268
269 /* free ParamBuffer */
270 ExFreePool (ParamBuffer);
271
272 /* allocate arc device name string */
273 ArcDeviceName.Length = 0;
274 ArcDeviceName.MaximumLength = 256 * sizeof(WCHAR);
275 ArcDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
276
277 InitializeObjectAttributes (&ObjectAttributes,
278 &ArcName,
279 0,
280 NULL,
281 NULL);
282
283 Status = NtOpenSymbolicLinkObject (&Handle,
284 SYMBOLIC_LINK_ALL_ACCESS,
285 &ObjectAttributes);
286 RtlFreeUnicodeString (&ArcName);
287 if (!NT_SUCCESS(Status))
288 {
289 RtlFreeUnicodeString (&BootPath);
290 RtlFreeUnicodeString (&ArcDeviceName);
291 DbgPrint("NtOpenSymbolicLinkObject() failed (Status %x)\n",
292 Status);
293
294 KeBugCheck (0x0);
295 }
296
297 Status = NtQuerySymbolicLinkObject (Handle,
298 &ArcDeviceName,
299 &Length);
300 NtClose (Handle);
301 if (!NT_SUCCESS(Status))
302 {
303 RtlFreeUnicodeString (&BootPath);
304 RtlFreeUnicodeString (&ArcDeviceName);
305 DbgPrint("NtQuerySymbolicObject() failed (Status %x)\n",
306 Status);
307
308 KeBugCheck (0x0);
309 }
310 DPRINT("Length: %lu ArcDeviceName: %wZ\n", Length, &ArcDeviceName);
311
312
313 /* allocate device name string */
314 DriveDeviceName.Length = 0;
315 DriveDeviceName.MaximumLength = 256 * sizeof(WCHAR);
316 DriveDeviceName.Buffer = ExAllocatePool (PagedPool, 256 * sizeof(WCHAR));
317
318 for (i = 0; i < 26; i++)
319 {
320 swprintf (DriveNameBuffer, L"\\??\\%C:", 'A' + i);
321 RtlInitUnicodeString (&DriveName,
322 DriveNameBuffer);
323
324 InitializeObjectAttributes (&ObjectAttributes,
325 &DriveName,
326 0,
327 NULL,
328 NULL);
329
330 Status = NtOpenSymbolicLinkObject (&Handle,
331 SYMBOLIC_LINK_ALL_ACCESS,
332 &ObjectAttributes);
333 if (!NT_SUCCESS(Status))
334 {
335 DPRINT("Failed to open link %wZ\n",
336 &DriveName);
337 continue;
338 }
339
340 Status = NtQuerySymbolicLinkObject (Handle,
341 &DriveDeviceName,
342 &Length);
343 if (!NT_SUCCESS(Status))
344 {
345 DPRINT("Failed query open link %wZ\n",
346 &DriveName);
347 continue;
348 }
349 DPRINT("Opened link: %wZ ==> %wZ\n",
350 &DriveName, &DriveDeviceName);
351
352 if (!RtlCompareUnicodeString (&ArcDeviceName, &DriveDeviceName, FALSE))
353 {
354 DPRINT("DOS Boot path: %c:%wZ\n", 'A' + i, &BootPath);
355 swprintf (SharedPage->NtSystemRoot,
356 L"%C:%wZ", 'A' + i, &BootPath);
357
358 BootDriveFound = TRUE;
359 }
360
361 NtClose (Handle);
362
363 /* set bit in dos drives bitmap (drive available) */
364 SharedPage->DosDeviceMap |= (1<<i);
365 }
366
367 RtlFreeUnicodeString (&BootPath);
368 RtlFreeUnicodeString (&DriveDeviceName);
369 RtlFreeUnicodeString (&ArcDeviceName);
370
371 DPRINT("DosDeviceMap: 0x%x\n", SharedPage->DosDeviceMap);
372
373 if (BootDriveFound == FALSE)
374 {
375 DbgPrint("No system drive found!\n");
376 KeBugCheck (0x0);
377 }
378 }
379
380 VOID
381 _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
382 /*
383 * FUNCTION: Called by the boot loader to start the kernel
384 * ARGUMENTS:
385 * LoaderBlock = Pointer to boot parameters initialized by the boot
386 * loader
387 * NOTE: The boot parameters are stored in low memory which will become
388 * invalid after the memory managment is initialized so we make a local copy.
389 */
390 {
391 ULONG i;
392 ULONG last_kernel_address;
393 ULONG start;
394 PCHAR name;
395 extern ULONG _bss_end__;
396
397 /*
398 * Copy the parameters to a local buffer because lowmem will go away
399 */
400 memcpy (&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
401 memcpy (&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr,
402 sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
403 KeLoaderBlock.ModsCount++;
404 KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
405
406 /*
407 * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
408 * This should be done by the boot loader.
409 */
410 strcpy (KeLoaderCommandLine,
411 "multi(0)disk(0)rdisk(0)partition(1)\\reactos ");
412 strcat (KeLoaderCommandLine, (PUCHAR)KeLoaderBlock.CommandLine);
413
414 KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
415 strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
416 KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
417 KeLoaderModules[0].ModStart = 0xC0000000;
418 KeLoaderModules[0].ModEnd = PAGE_ROUND_UP((ULONG)&_bss_end__);
419 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
420 {
421 strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
422 KeLoaderModules[i].ModStart -= 0x200000;
423 KeLoaderModules[i].ModStart += 0xc0000000;
424 KeLoaderModules[i].ModEnd -= 0x200000;
425 KeLoaderModules[i].ModEnd += 0xc0000000;
426 KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
427 }
428
429 /*
430 * Initialization phase 0
431 */
432 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
433 KeInit1();
434 LdrInit1();
435 KeLowerIrql(DISPATCH_LEVEL);
436
437 /*
438 * Display version number and copyright/warranty message
439 */
440 HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build "
441 KERNEL_VERSION_BUILD_STR")\n");
442 HalDisplayString(RES_STR_LEGAL_COPYRIGHT);
443 HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
444 "Public License, and you\n");
445 HalDisplayString("are welcome to change it and/or distribute copies of it "
446 "under certain\n");
447 HalDisplayString("conditions. There is absolutely no warranty for ReactOS.\n");
448
449 /*
450 * Fail at runtime if someone has changed various structures without
451 * updating the offsets used for the assembler code
452 */
453 assert(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
454 assert(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
455 assert(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
456 assert(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
457 assert(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
458 assert(FIELD_OFFSET(ETHREAD, ThreadsProcess) == ETHREAD_THREADS_PROCESS);
459 assert(FIELD_OFFSET(KPROCESS, PageTableDirectory) ==
460 KPROCESS_PAGE_TABLE_DIRECTORY);
461 assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
462 assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
463 assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
464
465 last_kernel_address = KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd;
466
467 NtEarlyInitVdm();
468 MmInit1(KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000,
469 last_kernel_address - 0xc0000000 + 0x200000,
470 last_kernel_address);
471
472 /*
473 * Initialize the kernel debugger
474 */
475 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
476 if (KdPollBreakIn ())
477 {
478 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
479 }
480
481 /*
482 * Initialization phase 1
483 * Initalize various critical subsystems
484 */
485 HalInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
486 MmInit2();
487 KeInit2();
488
489 /*
490 * Allow interrupts
491 */
492 KeLowerIrql(PASSIVE_LEVEL);
493
494 ObInit();
495 PiInitProcessManager();
496 ExInit();
497 IoInit();
498 LdrInitModuleManagement();
499 CmInitializeRegistry();
500 NtInit();
501 MmInit3();
502
503 /* Report all resources used by hal */
504 HalReportResourceUsage ();
505
506 /*
507 * Initalize services loaded at boot time
508 */
509 DPRINT1("%d files loaded\n",KeLoaderBlock.ModsCount);
510 for (i=0; i < KeLoaderBlock.ModsCount; i++)
511 {
512 DPRINT1("module: %s\n", KeLoaderModules[i].String);
513 }
514
515 /* Pass 1: load registry chunks passed in */
516 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
517 {
518 start = KeLoaderModules[i].ModStart;
519 if (strcmp ((PCHAR) start, "REGEDIT4") == 0)
520 {
521 DPRINT1("process registry chunk at %08lx\n", start);
522 CmImportHive((PCHAR) start);
523 }
524 }
525
526 /* Pass 2: process boot loaded drivers */
527 for (i=1; i < KeLoaderBlock.ModsCount; i++)
528 {
529 start = KeLoaderModules[i].ModStart;
530 name = (PCHAR)KeLoaderModules[i].String;
531 if (strcmp ((PCHAR) start, "REGEDIT4") != 0)
532 {
533 DPRINT1("process module '%s' at %08lx\n", name, start);
534 LdrProcessDriver((PVOID)start, name);
535 }
536 }
537
538 /* Create the SystemRoot symbolic link */
539 DbgPrint("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
540 CreateSystemRootLink ((PUCHAR)KeLoaderBlock.CommandLine);
541
542 #ifdef DBGPRINT_FILE_LOG
543 /* On the assumption that we can now access disks start up the debug
544 logger thread */
545 DebugLogInit2();
546 #endif /* DBGPRINT_FILE_LOG */
547
548 CmInitializeRegistry2();
549
550 /*
551 * Load Auto configured drivers
552 */
553 LdrLoadAutoConfigDrivers();
554
555 /*
556 * Assign drive letters
557 */
558 IoAssignDriveLetters ((PLOADER_PARAMETER_BLOCK)&KeLoaderBlock,
559 NULL,
560 NULL,
561 NULL);
562
563 /*
564 * Initialize shared user page:
565 * - set dos system path, dos device map, etc.
566 */
567 InitSystemSharedUserPage ((PUCHAR)KeLoaderBlock.CommandLine);
568
569 /*
570 * Launch initial process
571 */
572 LdrLoadInitialProcess();
573
574 DbgPrint("Finished main()\n");
575 PsTerminateSystemThread(STATUS_SUCCESS);
576 }
577
578 /* EOF */
579