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