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