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