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