Create a branch for Aleksandar Andrejevic for his work on NTVDM. See http://jira...
[reactos.git] / boot / freeldr / freeldr / windows / winldr.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * Copyright (C) 2006 Aleksey Bragin <aleksey@reactos.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <freeldr.h>
23
24 #include <ndk/ldrtypes.h>
25 #include <debug.h>
26
27 DBG_DEFAULT_CHANNEL(WINDOWS);
28
29 //FIXME: Do a better way to retrieve Arc disk information
30 extern ULONG reactos_disk_count;
31 extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
32
33 extern ULONG LoaderPagesSpanned;
34 extern BOOLEAN AcpiPresent;
35
36 extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
37 extern BOOLEAN WinLdrTerminalConnected;
38 extern void WinLdrSetupEms(IN PCHAR BootOptions);
39
40 PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
41
42 // debug stuff
43 VOID DumpMemoryAllocMap(VOID);
44
45 // Init "phase 0"
46 VOID
47 AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
48 {
49 PLOADER_PARAMETER_BLOCK LoaderBlock;
50
51 /* Allocate and zero-init the LPB */
52 WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK),
53 LoaderSystemBlock);
54 if (WinLdrSystemBlock == NULL)
55 {
56 UiMessageBox("Failed to allocate memory for system block!");
57 return;
58 }
59
60 RtlZeroMemory(WinLdrSystemBlock, sizeof(LOADER_SYSTEM_BLOCK));
61
62 LoaderBlock = &WinLdrSystemBlock->LoaderBlock;
63 LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock;
64
65 /* Init three critical lists, used right away */
66 InitializeListHead(&LoaderBlock->LoadOrderListHead);
67 InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
68 InitializeListHead(&LoaderBlock->BootDriverListHead);
69
70 *OutLoaderBlock = LoaderBlock;
71 }
72
73 // Init "phase 1"
74 VOID
75 WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
76 LPCSTR Options,
77 LPCSTR SystemRoot,
78 LPCSTR BootPath,
79 USHORT VersionToBoot)
80 {
81 /* Examples of correct options and paths */
82 //CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
83 //CHAR Options[] = "/NODEBUG";
84 //CHAR SystemRoot[] = "\\WINNT\\";
85 //CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
86
87 LPSTR LoadOptions, NewLoadOptions;
88 CHAR HalPath[] = "\\";
89 CHAR ArcBoot[256];
90 CHAR MiscFiles[256];
91 ULONG i;
92 ULONG_PTR PathSeparator;
93 PLOADER_PARAMETER_EXTENSION Extension;
94
95 /* Construct SystemRoot and ArcBoot from SystemPath */
96 PathSeparator = strstr(BootPath, "\\") - BootPath;
97 strncpy(ArcBoot, BootPath, PathSeparator);
98 ArcBoot[PathSeparator] = 0;
99
100 TRACE("ArcBoot: %s\n", ArcBoot);
101 TRACE("SystemRoot: %s\n", SystemRoot);
102 TRACE("Options: %s\n", Options);
103
104 /* Fill Arc BootDevice */
105 LoaderBlock->ArcBootDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
106 strncpy(LoaderBlock->ArcBootDeviceName, ArcBoot, MAX_PATH);
107 LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
108
109 /* Fill Arc HalDevice, it matches ArcBoot path */
110 LoaderBlock->ArcHalDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
111 LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
112
113 /* Fill SystemRoot */
114 LoaderBlock->NtBootPathName = WinLdrSystemBlock->NtBootPathName;
115 strncpy(LoaderBlock->NtBootPathName, SystemRoot, MAX_PATH);
116 LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
117
118 /* Fill NtHalPathName */
119 LoaderBlock->NtHalPathName = WinLdrSystemBlock->NtHalPathName;
120 strncpy(LoaderBlock->NtHalPathName, HalPath, MAX_PATH);
121 LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
122
123 /* Fill LoadOptions and strip the '/' commutator symbol in front of each option */
124 NewLoadOptions = LoadOptions = LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions;
125 strncpy(LoaderBlock->LoadOptions, Options, MAX_OPTIONS_LENGTH);
126
127 do
128 {
129 while (*LoadOptions == '/')
130 ++LoadOptions;
131
132 *NewLoadOptions++ = *LoadOptions;
133 } while (*LoadOptions++);
134
135 LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
136
137 /* Arc devices */
138 LoaderBlock->ArcDiskInformation = &WinLdrSystemBlock->ArcDiskInformation;
139 InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
140
141 /* Convert ARC disk information from freeldr to a correct format */
142 for (i = 0; i < reactos_disk_count; i++)
143 {
144 PARC_DISK_SIGNATURE_EX ArcDiskSig;
145
146 /* Allocate the ARC structure */
147 ArcDiskSig = HeapAllocate(FrLdrDefaultHeap,
148 sizeof(ARC_DISK_SIGNATURE_EX),
149 'giSD');
150
151 /* Copy the data over */
152 ArcDiskSig->DiskSignature.Signature = reactos_arc_disk_info[i].Signature;
153 ArcDiskSig->DiskSignature.CheckSum = reactos_arc_disk_info[i].CheckSum;
154
155 /* Copy the ARC Name */
156 strncpy(ArcDiskSig->ArcName, reactos_arc_disk_info[i].ArcName, MAX_PATH);
157 ArcDiskSig->DiskSignature.ArcName = PaToVa(ArcDiskSig->ArcName);
158
159 /* Mark partition table as valid */
160 ArcDiskSig->DiskSignature.ValidPartitionTable = TRUE;
161
162 /* Insert into the list */
163 InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
164 &ArcDiskSig->DiskSignature.ListEntry);
165 }
166
167 /* Convert all list's to Virtual address */
168
169 /* Convert the ArcDisks list to virtual address */
170 List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
171 LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);
172
173 /* Convert configuration entries to VA */
174 ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
175 LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
176
177 /* Convert all DTE into virtual addresses */
178 List_PaToVa(&LoaderBlock->LoadOrderListHead);
179
180 /* this one will be converted right before switching to
181 virtual paging mode */
182 //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
183
184 /* Convert list of boot drivers */
185 List_PaToVa(&LoaderBlock->BootDriverListHead);
186
187 /* Initialize Extension now */
188 Extension = &WinLdrSystemBlock->Extension;
189 Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
190 Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
191 Extension->MinorVersion = VersionToBoot & 0xFF;
192 Extension->Profile.Status = 2;
193
194 /* Check if ACPI is present */
195 if (AcpiPresent)
196 {
197 /* See KiRosFrldrLpbToNtLpb for details */
198 Extension->AcpiTable = (PVOID)1;
199 }
200
201 #ifdef _M_IX86
202 /* Set headless block pointer */
203 if (WinLdrTerminalConnected)
204 {
205 Extension->HeadlessLoaderBlock = &WinLdrSystemBlock->HeadlessLoaderBlock;
206 RtlCopyMemory(Extension->HeadlessLoaderBlock,
207 &LoaderRedirectionInformation,
208 sizeof(HEADLESS_LOADER_BLOCK));
209 Extension->HeadlessLoaderBlock = PaToVa(Extension->HeadlessLoaderBlock);
210 }
211 #endif
212 /* Load drivers database */
213 strcpy(MiscFiles, BootPath);
214 strcat(MiscFiles, "AppPatch\\drvmain.sdb");
215 Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles,
216 &Extension->DrvDBSize,
217 LoaderRegistryData));
218
219 /* Convert extension and setup block pointers */
220 LoaderBlock->Extension = PaToVa(Extension);
221
222 if (LoaderBlock->SetupLdrBlock)
223 LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
224
225 TRACE("WinLdrInitializePhase1() completed\n");
226 }
227
228 static BOOLEAN
229 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
230 LPCSTR BootPath,
231 PUNICODE_STRING FilePath,
232 ULONG Flags,
233 PLDR_DATA_TABLE_ENTRY *DriverDTE)
234 {
235 CHAR FullPath[1024];
236 CHAR DriverPath[1024];
237 CHAR DllName[1024];
238 PCHAR DriverNamePos;
239 BOOLEAN Status;
240 PVOID DriverBase = NULL;
241
242 // Separate the path to file name and directory path
243 _snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
244 DriverNamePos = strrchr(DriverPath, '\\');
245 if (DriverNamePos != NULL)
246 {
247 // Copy the name
248 strcpy(DllName, DriverNamePos+1);
249
250 // Cut out the name from the path
251 *(DriverNamePos+1) = 0;
252 }
253 else
254 {
255 // There is no directory in the path
256 strcpy(DllName, DriverPath);
257 DriverPath[0] = 0;
258 }
259
260 TRACE("DriverPath: %s, DllName: %s, LPB\n", DriverPath, DllName);
261
262 // Check if driver is already loaded
263 Status = WinLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE);
264 if (Status)
265 {
266 // We've got the pointer to its DTE, just return success
267 return TRUE;
268 }
269
270 // It's not loaded, we have to load it
271 _snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
272 Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
273 if (!Status)
274 return FALSE;
275
276 // Allocate a DTE for it
277 Status = WinLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE);
278 if (!Status)
279 {
280 ERR("WinLdrAllocateDataTableEntry() failed\n");
281 return FALSE;
282 }
283
284 // Modify any flags, if needed
285 (*DriverDTE)->Flags |= Flags;
286
287 // Look for any dependencies it may have, and load them too
288 sprintf(FullPath,"%s%s", BootPath, DriverPath);
289 Status = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
290 if (!Status)
291 {
292 ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath);
293 return FALSE;
294 }
295
296 return TRUE;
297 }
298
299 BOOLEAN
300 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
301 LPCSTR BootPath)
302 {
303 PLIST_ENTRY NextBd;
304 PBOOT_DRIVER_LIST_ENTRY BootDriver;
305 BOOLEAN Status;
306
307 // Walk through the boot drivers list
308 NextBd = LoaderBlock->BootDriverListHead.Flink;
309
310 while (NextBd != &LoaderBlock->BootDriverListHead)
311 {
312 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
313
314 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
315 BootDriver->LdrEntry, &BootDriver->RegistryPath);
316
317 // Paths are relative (FIXME: Are they always relative?)
318
319 // Load it
320 Status = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
321 BootPath,
322 &BootDriver->FilePath,
323 0,
324 &BootDriver->LdrEntry);
325
326 // If loading failed - cry loudly
327 //FIXME: Maybe remove it from the list and try to continue?
328 if (!Status)
329 {
330 UiMessageBox("Can't load boot driver!");
331 return FALSE;
332 }
333
334 // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
335 BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
336 BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
337 BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
338
339 NextBd = BootDriver->Link.Flink;
340 }
341
342 return TRUE;
343 }
344
345 PVOID
346 WinLdrLoadModule(PCSTR ModuleName,
347 ULONG *Size,
348 TYPE_OF_MEMORY MemoryType)
349 {
350 ULONG FileId;
351 PVOID PhysicalBase;
352 FILEINFORMATION FileInfo;
353 ULONG FileSize;
354 ULONG Status;
355 ULONG BytesRead;
356
357 //CHAR ProgressString[256];
358
359 /* Inform user we are loading files */
360 //sprintf(ProgressString, "Loading %s...", FileName);
361 //UiDrawProgressBarCenter(1, 100, ProgressString);
362
363 TRACE("Loading module %s\n", ModuleName);
364 *Size = 0;
365
366 /* Open the image file */
367 Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId);
368 if (Status != ESUCCESS)
369 {
370 /* In case of errors, we just return, without complaining to the user */
371 return NULL;
372 }
373
374 /* Get this file's size */
375 Status = ArcGetFileInformation(FileId, &FileInfo);
376 if (Status != ESUCCESS)
377 {
378 ArcClose(FileId);
379 return NULL;
380 }
381 FileSize = FileInfo.EndingAddress.LowPart;
382 *Size = FileSize;
383
384 /* Allocate memory */
385 PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
386 if (PhysicalBase == NULL)
387 {
388 ArcClose(FileId);
389 return NULL;
390 }
391
392 /* Load whole file */
393 Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
394 ArcClose(FileId);
395 if (Status != ESUCCESS)
396 {
397 return NULL;
398 }
399
400 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
401
402 return PhysicalBase;
403 }
404
405 USHORT
406 WinLdrDetectVersion()
407 {
408 LONG rc;
409 FRLDRHKEY hKey;
410
411 rc = RegOpenKey(
412 NULL,
413 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
414 &hKey);
415 if (rc != ERROR_SUCCESS)
416 {
417 // Key doesn't exist; assume NT 4.0
418 return _WIN32_WINNT_NT4;
419 }
420
421 // We may here want to read the value of ProductVersion
422 return _WIN32_WINNT_WS03;
423 }
424
425 static
426 BOOLEAN
427 LoadModule(
428 PLOADER_PARAMETER_BLOCK LoaderBlock,
429 PCCH Path,
430 PCCH File,
431 TYPE_OF_MEMORY MemoryType,
432 PLDR_DATA_TABLE_ENTRY *Dte,
433 BOOLEAN IsKdTransportDll,
434 ULONG Percentage)
435 {
436 BOOLEAN Status;
437 CHAR FullFileName[MAX_PATH];
438 CHAR ProgressString[256];
439 PVOID BaseAdress = NULL;
440
441 UiDrawBackdrop();
442 sprintf(ProgressString, "Loading %s...", File);
443 UiDrawProgressBarCenter(Percentage, 100, ProgressString);
444
445 strcpy(FullFileName, Path);
446 strcat(FullFileName, "SYSTEM32\\");
447 strcat(FullFileName, File);
448
449 Status = WinLdrLoadImage(FullFileName, MemoryType, &BaseAdress);
450 if (!Status)
451 {
452 TRACE("Loading %s failed\n", File);
453 return FALSE;
454 }
455 TRACE("%s loaded successfully at %p\n", File, BaseAdress);
456
457 strcpy(FullFileName, "WINDOWS\\SYSTEM32\\");
458 strcat(FullFileName, File);
459 /*
460 * Cheat about the base DLL name if we are loading
461 * the Kernel Debugger Transport DLL, to make the
462 * PE loader happy.
463 */
464 Status = WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
465 (IsKdTransportDll ? "KDCOM.DLL" : File),
466 FullFileName,
467 BaseAdress,
468 Dte);
469
470 return Status;
471 }
472
473 static
474 BOOLEAN
475 LoadWindowsCore(IN USHORT OperatingSystemVersion,
476 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
477 IN LPCSTR BootOptions,
478 IN LPCSTR BootPath,
479 IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
480 {
481 BOOLEAN Status;
482 CHAR DirPath[MAX_PATH];
483 CHAR KdTransportDllName[MAX_PATH];
484 PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
485
486 if (!KernelDTE) return FALSE;
487
488 /* Load the Kernel */
489 LoadModule(LoaderBlock, BootPath, "NTOSKRNL.EXE", LoaderSystemCode, KernelDTE, FALSE, 30);
490
491 /* Load the HAL */
492 LoadModule(LoaderBlock, BootPath, "HAL.DLL", LoaderHalCode, &HalDTE, FALSE, 45);
493
494 /* Load the Kernel Debugger Transport DLL */
495 if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
496 {
497 /*
498 * According to http://www.nynaeve.net/?p=173 :
499 * "[...] Another enhancement that could be done Microsoft-side would be
500 * a better interface for replacing KD transport modules. Right now, due
501 * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
502 * has a hardcoded hack that interprets the KD type in the OS loader options,
503 * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
504 * "kdusb2.dll" modules, and inserts them into the loaded module list under
505 * the name "kdcom.dll". [...]"
506 */
507
508 /*
509 * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
510 * Indeed I want it to be case-insensitive to allow "debugport="
511 * or "DeBuGpOrT=" or... , and I don't want it to match malformed
512 * command-line options, such as:
513 *
514 * "...foo DEBUGPORT=xxx bar..."
515 * "...foo/DEBUGPORT=xxx bar..."
516 * "...foo/DEBUGPORT=bar..."
517 *
518 * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
519 * from the rest by whitespace, unless it begins the command-line, e.g.:
520 *
521 * "/DEBUGPORT=COM1 foo...bar..."
522 * "...foo /DEBUGPORT=USB bar..."
523 * or:
524 * "...foo /DEBUGPORT= bar..."
525 * (in that case, we default the port to COM).
526 */
527 while (BootOptions)
528 {
529 /* Skip possible initial whitespace */
530 BootOptions += strspn(BootOptions, " \t");
531
532 /* Check whether a new commutator starts and it is the DEBUGPORT one */
533 if (*BootOptions != '/' || _strnicmp(++BootOptions, "DEBUGPORT=", 10) != 0)
534 {
535 /* Search for another whitespace */
536 BootOptions = strpbrk(BootOptions, " \t");
537 continue;
538 }
539 else
540 {
541 /* We found the DEBUGPORT commutator. Move to the port name. */
542 BootOptions += 10;
543 break;
544 }
545 }
546
547 if (BootOptions)
548 {
549 /*
550 * We have found the DEBUGPORT commutator. Parse the port name.
551 * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
552 * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
553 */
554 strcpy(KdTransportDllName, "KD");
555 if (_strnicmp(BootOptions, "COM", 3) == 0 && '0' <= BootOptions[3] && BootOptions[3] <= '9')
556 {
557 strncat(KdTransportDllName, BootOptions, 3);
558 }
559 else
560 {
561 size_t i = strcspn(BootOptions, " \t:"); /* Skip valid separators: whitespace or colon */
562 if (i == 0)
563 strcat(KdTransportDllName, "COM");
564 else
565 strncat(KdTransportDllName, BootOptions, i);
566 }
567 strcat(KdTransportDllName, ".DLL");
568 _strupr(KdTransportDllName);
569
570 /*
571 * Load the transport DLL. Specify it to LoadModule so that it can
572 * change the base DLL name of the loaded transport DLL to the default
573 * "KDCOM.DLL" name, to make the PE loader happy.
574 */
575 LoadModule(LoaderBlock, BootPath, KdTransportDllName, LoaderSystemCode, &KdComDTE, TRUE, 60);
576 }
577 }
578
579 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
580 strcpy(DirPath, BootPath);
581 strcat(DirPath, "system32\\");
582 Status = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
583 Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
584 if (KdComDTE)
585 {
586 Status &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
587 }
588
589 return Status;
590 }
591
592 VOID
593 LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem,
594 IN USHORT OperatingSystemVersion)
595 {
596 ULONG_PTR SectionId;
597 PCSTR SectionName = OperatingSystem->SystemPartition;
598 CHAR SettingsValue[80];
599 BOOLEAN HasSection;
600 CHAR BootPath[MAX_PATH];
601 CHAR FileName[MAX_PATH];
602 CHAR BootOptions[256];
603 PCHAR File;
604 BOOLEAN Status;
605 PLOADER_PARAMETER_BLOCK LoaderBlock;
606
607 // Get OS setting value
608 SettingsValue[0] = ANSI_NULL;
609 IniOpenSection("Operating Systems", &SectionId);
610 IniReadSettingByName(SectionId, SectionName, SettingsValue, sizeof(SettingsValue));
611
612 // Open the operating system section
613 // specified in the .ini file
614 HasSection = IniOpenSection(SectionName, &SectionId);
615
616 UiDrawBackdrop();
617 UiDrawProgressBarCenter(1, 100, "Loading NT...");
618
619 /* Read the system path is set in the .ini file */
620 if (!HasSection ||
621 !IniReadSettingByName(SectionId, "SystemPath", BootPath, sizeof(BootPath)))
622 {
623 strcpy(BootPath, SectionName);
624 }
625
626 /* Special case for LiveCD */
627 if (!_strnicmp(BootPath, "LiveCD", strlen("LiveCD")))
628 {
629 strcpy(FileName, BootPath + strlen("LiveCD"));
630 MachDiskGetBootPath(BootPath, sizeof(BootPath));
631 strcat(BootPath, FileName);
632 }
633
634 /* Append a backslash */
635 if ((strlen(BootPath)==0) || BootPath[strlen(BootPath)] != '\\')
636 strcat(BootPath, "\\");
637
638 /* Read booting options */
639 if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
640 {
641 /* Get options after the title */
642 PCSTR p = SettingsValue;
643 while (*p == ' ' || *p == '"')
644 p++;
645 while (*p != '\0' && *p != '"')
646 p++;
647 strcpy(BootOptions, p);
648 TRACE("BootOptions: '%s'\n", BootOptions);
649 }
650
651 /* Append boot-time options */
652 AppendBootTimeOptions(BootOptions);
653
654 /* Check if a ramdisk file was given */
655 File = strstr(BootOptions, "/RDPATH=");
656 if (File)
657 {
658 /* Copy the file name and everything else after it */
659 strcpy(FileName, File + 8);
660
661 /* Null-terminate */
662 *strstr(FileName, " ") = ANSI_NULL;
663
664 /* Load the ramdisk */
665 RamDiskLoadVirtualFile(FileName);
666 }
667
668 /* Let user know we started loading */
669 //UiDrawStatusText("Loading...");
670
671 TRACE("BootPath: '%s'\n", BootPath);
672
673 /* Allocate and minimalistic-initialize LPB */
674 AllocateAndInitLPB(&LoaderBlock);
675
676 #ifdef _M_IX86
677 /* Setup redirection support */
678 WinLdrSetupEms(BootOptions);
679 #endif
680
681 /* Load Hive */
682 UiDrawBackdrop();
683 UiDrawProgressBarCenter(15, 100, "Loading system hive...");
684 Status = WinLdrInitSystemHive(LoaderBlock, BootPath);
685 TRACE("SYSTEM hive %s\n", (Status ? "loaded" : "not loaded"));
686
687 /* Load NLS data, OEM font, and prepare boot drivers list */
688 Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
689 TRACE("SYSTEM hive %s\n", (Status ? "scanned" : "not scanned"));
690
691 /* Finish loading */
692 LoadAndBootWindowsCommon(OperatingSystemVersion,
693 LoaderBlock,
694 BootOptions,
695 BootPath,
696 0);
697 }
698
699 VOID
700 LoadAndBootWindowsCommon(
701 USHORT OperatingSystemVersion,
702 PLOADER_PARAMETER_BLOCK LoaderBlock,
703 LPCSTR BootOptions,
704 LPCSTR BootPath,
705 BOOLEAN Setup)
706 {
707 PLOADER_PARAMETER_BLOCK LoaderBlockVA;
708 BOOLEAN Status;
709 PLDR_DATA_TABLE_ENTRY KernelDTE;
710 KERNEL_ENTRY_POINT KiSystemStartup;
711 LPCSTR SystemRoot;
712 TRACE("LoadAndBootWindowsCommon()\n");
713
714 /* Convert BootPath to SystemRoot */
715 SystemRoot = strstr(BootPath, "\\");
716
717 /* Detect hardware */
718 LoaderBlock->ConfigurationRoot = MachHwDetect();
719
720 if (OperatingSystemVersion == 0)
721 OperatingSystemVersion = WinLdrDetectVersion();
722
723 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
724 Status = LoadWindowsCore(OperatingSystemVersion,
725 LoaderBlock,
726 BootOptions,
727 BootPath,
728 &KernelDTE);
729 if (!Status)
730 {
731 UiMessageBox("Error loading NTOS core.");
732 return;
733 }
734
735 /* Load boot drivers */
736 UiDrawBackdrop();
737 UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
738 Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
739 TRACE("Boot drivers loaded with status %d\n", Status);
740
741 /* Initialize Phase 1 - no drivers loading anymore */
742 WinLdrInitializePhase1(LoaderBlock,
743 BootOptions,
744 SystemRoot,
745 BootPath,
746 OperatingSystemVersion);
747
748 /* Save entry-point pointer and Loader block VAs */
749 KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
750 LoaderBlockVA = PaToVa(LoaderBlock);
751
752 /* "Stop all motors", change videomode */
753 MachPrepareForReactOS(Setup);
754
755 /* Debugging... */
756 //DumpMemoryAllocMap();
757
758 /* Do the machine specific initialization */
759 WinLdrSetupMachineDependent(LoaderBlock);
760
761 /* Map pages and create memory descriptors */
762 WinLdrSetupMemoryLayout(LoaderBlock);
763
764 /* Set processor context */
765 WinLdrSetProcessorContext();
766
767 /* Save final value of LoaderPagesSpanned */
768 LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
769
770 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
771 KiSystemStartup, LoaderBlockVA);
772
773 // Zero KI_USER_SHARED_DATA page
774 memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
775
776 WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
777 WinLdrpDumpBootDriver(LoaderBlockVA);
778 #ifndef _M_AMD64
779 WinLdrpDumpArcDisks(LoaderBlockVA);
780 #endif
781
782 //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below
783 //while (1) {};
784 /*asm(".intel_syntax noprefix\n");
785 asm("test1:\n");
786 asm("jmp test1\n");
787 asm(".att_syntax\n");*/
788
789 /* Pass control */
790 (*KiSystemStartup)(LoaderBlockVA);
791 }
792
793 VOID
794 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
795 {
796 PLIST_ENTRY NextMd;
797 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
798
799 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
800
801 while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
802 {
803 MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
804
805 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
806 MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
807
808 NextMd = MemoryDescriptor->ListEntry.Flink;
809 }
810 }
811
812 VOID
813 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
814 {
815 PLIST_ENTRY NextBd;
816 PBOOT_DRIVER_LIST_ENTRY BootDriver;
817
818 NextBd = LoaderBlock->BootDriverListHead.Flink;
819
820 while (NextBd != &LoaderBlock->BootDriverListHead)
821 {
822 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
823
824 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
825 BootDriver->LdrEntry, &BootDriver->RegistryPath);
826
827 NextBd = BootDriver->Link.Flink;
828 }
829 }
830
831 VOID
832 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
833 {
834 PLIST_ENTRY NextBd;
835 PARC_DISK_SIGNATURE ArcDisk;
836
837 NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
838
839 while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
840 {
841 ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
842
843 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
844 ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
845
846 NextBd = ArcDisk->ListEntry.Flink;
847 }
848 }