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>
9 #include <ndk/ldrtypes.h>
14 DBG_DEFAULT_CHANNEL(WINDOWS
);
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
[];
20 extern ULONG LoaderPagesSpanned
;
21 extern BOOLEAN AcpiPresent
;
23 extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation
;
24 extern BOOLEAN WinLdrTerminalConnected
;
25 extern void WinLdrSetupEms(IN PCHAR BootOptions
);
27 PLOADER_SYSTEM_BLOCK WinLdrSystemBlock
;
29 BOOLEAN VirtualBias
= FALSE
;
30 BOOLEAN SosEnabled
= FALSE
;
31 BOOLEAN PaeEnabled
= FALSE
;
32 BOOLEAN PaeDisabled
= FALSE
;
33 BOOLEAN SafeBoot
= FALSE
;
34 BOOLEAN BootLogo
= FALSE
;
35 BOOLEAN NoexecuteDisabled
= FALSE
;
36 BOOLEAN NoexecuteEnabled
= FALSE
;
39 VOID
DumpMemoryAllocMap(VOID
);
44 IN USHORT VersionToBoot
,
45 OUT PLOADER_PARAMETER_BLOCK
* OutLoaderBlock
)
47 PLOADER_PARAMETER_BLOCK LoaderBlock
;
48 PLOADER_PARAMETER_EXTENSION Extension
;
50 /* Allocate and zero-init the Loader Parameter Block */
51 WinLdrSystemBlock
= MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK
),
53 if (WinLdrSystemBlock
== NULL
)
55 UiMessageBox("Failed to allocate memory for system block!");
59 RtlZeroMemory(WinLdrSystemBlock
, sizeof(LOADER_SYSTEM_BLOCK
));
61 LoaderBlock
= &WinLdrSystemBlock
->LoaderBlock
;
62 LoaderBlock
->NlsData
= &WinLdrSystemBlock
->NlsDataBlock
;
64 /* Initialize the Loader Block Extension */
65 Extension
= &WinLdrSystemBlock
->Extension
;
66 LoaderBlock
->Extension
= Extension
;
67 Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
68 Extension
->MajorVersion
= (VersionToBoot
& 0xFF00) >> 8;
69 Extension
->MinorVersion
= (VersionToBoot
& 0xFF);
71 /* Init three critical lists, used right away */
72 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
73 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
74 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
76 *OutLoaderBlock
= LoaderBlock
;
81 WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock
,
88 * Examples of correct options and paths:
89 * CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
90 * CHAR Options[] = "/NODEBUG";
91 * CHAR SystemRoot[] = "\\WINNT\\";
92 * CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
95 PSTR LoadOptions
, NewLoadOptions
;
96 CHAR HalPath
[] = "\\";
97 CHAR ArcBoot
[MAX_PATH
+1];
98 CHAR MiscFiles
[MAX_PATH
+1];
100 ULONG_PTR PathSeparator
;
101 PLOADER_PARAMETER_EXTENSION Extension
;
103 /* Construct SystemRoot and ArcBoot from SystemPath */
104 PathSeparator
= strstr(BootPath
, "\\") - BootPath
;
105 RtlStringCbCopyNA(ArcBoot
, sizeof(ArcBoot
), BootPath
, PathSeparator
);
107 TRACE("ArcBoot: '%s'\n", ArcBoot
);
108 TRACE("SystemRoot: '%s'\n", SystemRoot
);
109 TRACE("Options: '%s'\n", Options
);
111 /* Fill ARC BootDevice */
112 LoaderBlock
->ArcBootDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
113 RtlStringCbCopyA(LoaderBlock
->ArcBootDeviceName
, sizeof(WinLdrSystemBlock
->ArcBootDeviceName
), ArcBoot
);
114 LoaderBlock
->ArcBootDeviceName
= PaToVa(LoaderBlock
->ArcBootDeviceName
);
118 // SetupBlock->ArcSetupDeviceName must be the path to the setup **SOURCE**,
119 // and not the setup boot path. Indeed they may differ!!
121 if (LoaderBlock
->SetupLdrBlock
)
123 PSETUP_LOADER_BLOCK SetupBlock
= LoaderBlock
->SetupLdrBlock
;
125 /* Adjust the ARC path in the setup block - Matches ArcBoot path */
126 SetupBlock
->ArcSetupDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
127 SetupBlock
->ArcSetupDeviceName
= PaToVa(SetupBlock
->ArcSetupDeviceName
);
129 /* Convert the setup block pointer */
130 LoaderBlock
->SetupLdrBlock
= PaToVa(LoaderBlock
->SetupLdrBlock
);
133 /* Fill ARC HalDevice, it matches ArcBoot path */
134 LoaderBlock
->ArcHalDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
135 LoaderBlock
->ArcHalDeviceName
= PaToVa(LoaderBlock
->ArcHalDeviceName
);
137 /* Fill SystemRoot */
138 LoaderBlock
->NtBootPathName
= WinLdrSystemBlock
->NtBootPathName
;
139 RtlStringCbCopyA(LoaderBlock
->NtBootPathName
, sizeof(WinLdrSystemBlock
->NtBootPathName
), SystemRoot
);
140 LoaderBlock
->NtBootPathName
= PaToVa(LoaderBlock
->NtBootPathName
);
142 /* Fill NtHalPathName */
143 LoaderBlock
->NtHalPathName
= WinLdrSystemBlock
->NtHalPathName
;
144 RtlStringCbCopyA(LoaderBlock
->NtHalPathName
, sizeof(WinLdrSystemBlock
->NtHalPathName
), HalPath
);
145 LoaderBlock
->NtHalPathName
= PaToVa(LoaderBlock
->NtHalPathName
);
147 /* Fill LoadOptions and strip the '/' switch symbol in front of each option */
148 NewLoadOptions
= LoadOptions
= LoaderBlock
->LoadOptions
= WinLdrSystemBlock
->LoadOptions
;
149 RtlStringCbCopyA(LoaderBlock
->LoadOptions
, sizeof(WinLdrSystemBlock
->LoadOptions
), Options
);
153 while (*LoadOptions
== '/')
156 *NewLoadOptions
++ = *LoadOptions
;
157 } while (*LoadOptions
++);
159 LoaderBlock
->LoadOptions
= PaToVa(LoaderBlock
->LoadOptions
);
162 LoaderBlock
->ArcDiskInformation
= &WinLdrSystemBlock
->ArcDiskInformation
;
163 InitializeListHead(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
165 /* Convert ARC disk information from freeldr to a correct format */
166 for (i
= 0; i
< reactos_disk_count
; i
++)
168 PARC_DISK_SIGNATURE_EX ArcDiskSig
;
170 /* Allocate the ARC structure */
171 ArcDiskSig
= FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX
), 'giSD');
173 /* Copy the data over */
174 RtlCopyMemory(ArcDiskSig
, &reactos_arc_disk_info
[i
], sizeof(ARC_DISK_SIGNATURE_EX
));
176 /* Set the ARC Name pointer */
177 ArcDiskSig
->DiskSignature
.ArcName
= PaToVa(ArcDiskSig
->ArcName
);
179 /* Insert into the list */
180 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
181 &ArcDiskSig
->DiskSignature
.ListEntry
);
184 /* Convert all lists to Virtual address */
186 /* Convert the ArcDisks list to virtual address */
187 List_PaToVa(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
188 LoaderBlock
->ArcDiskInformation
= PaToVa(LoaderBlock
->ArcDiskInformation
);
190 /* Convert configuration entries to VA */
191 ConvertConfigToVA(LoaderBlock
->ConfigurationRoot
);
192 LoaderBlock
->ConfigurationRoot
= PaToVa(LoaderBlock
->ConfigurationRoot
);
194 /* Convert all DTE into virtual addresses */
195 List_PaToVa(&LoaderBlock
->LoadOrderListHead
);
197 /* This one will be converted right before switching to virtual paging mode */
198 //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
200 /* Convert list of boot drivers */
201 List_PaToVa(&LoaderBlock
->BootDriverListHead
);
203 Extension
= LoaderBlock
->Extension
;
205 /* FIXME! HACK value for docking profile */
206 Extension
->Profile
.Status
= 2;
208 /* Check if FreeLdr detected a ACPI table */
211 /* Set the pointer to something for compatibility */
212 Extension
->AcpiTable
= (PVOID
)1;
213 // FIXME: Extension->AcpiTableSize;
217 /* Set headless block pointer */
218 if (WinLdrTerminalConnected
)
220 Extension
->HeadlessLoaderBlock
= &WinLdrSystemBlock
->HeadlessLoaderBlock
;
221 RtlCopyMemory(Extension
->HeadlessLoaderBlock
,
222 &LoaderRedirectionInformation
,
223 sizeof(HEADLESS_LOADER_BLOCK
));
224 Extension
->HeadlessLoaderBlock
= PaToVa(Extension
->HeadlessLoaderBlock
);
227 /* Load drivers database */
228 RtlStringCbCopyA(MiscFiles
, sizeof(MiscFiles
), BootPath
);
229 RtlStringCbCatA(MiscFiles
, sizeof(MiscFiles
), "AppPatch\\drvmain.sdb");
230 Extension
->DrvDBImage
= PaToVa(WinLdrLoadModule(MiscFiles
,
231 &Extension
->DrvDBSize
,
232 LoaderRegistryData
));
234 /* Convert the extension block pointer */
235 LoaderBlock
->Extension
= PaToVa(LoaderBlock
->Extension
);
237 TRACE("WinLdrInitializePhase1() completed\n");
241 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead
,
243 PUNICODE_STRING FilePath
,
245 PLDR_DATA_TABLE_ENTRY
*DriverDTE
)
248 CHAR DriverPath
[1024];
252 PVOID DriverBase
= NULL
;
254 // Separate the path to file name and directory path
255 RtlStringCbPrintfA(DriverPath
, sizeof(DriverPath
), "%wZ", FilePath
);
256 DriverNamePos
= strrchr(DriverPath
, '\\');
257 if (DriverNamePos
!= NULL
)
260 RtlStringCbCopyA(DllName
, sizeof(DllName
), DriverNamePos
+1);
262 // Cut out the name from the path
263 *(DriverNamePos
+1) = ANSI_NULL
;
267 // There is no directory in the path
268 RtlStringCbCopyA(DllName
, sizeof(DllName
), DriverPath
);
269 *DriverPath
= ANSI_NULL
;
272 TRACE("DriverPath: '%s', DllName: '%s', LPB\n", DriverPath
, DllName
);
274 // Check if driver is already loaded
275 Success
= PeLdrCheckForLoadedDll(LoadOrderListHead
, DllName
, DriverDTE
);
278 // We've got the pointer to its DTE, just return success
282 // It's not loaded, we have to load it
283 RtlStringCbPrintfA(FullPath
, sizeof(FullPath
), "%s%wZ", BootPath
, FilePath
);
284 Success
= PeLdrLoadImage(FullPath
, LoaderBootDriver
, &DriverBase
);
288 // Allocate a DTE for it
289 Success
= PeLdrAllocateDataTableEntry(LoadOrderListHead
, DllName
, DllName
, DriverBase
, DriverDTE
);
292 ERR("PeLdrAllocateDataTableEntry() failed\n");
296 // Modify any flags, if needed
297 (*DriverDTE
)->Flags
|= Flags
;
299 // Look for any dependencies it may have, and load them too
300 RtlStringCbPrintfA(FullPath
, sizeof(FullPath
), "%s%s", BootPath
, DriverPath
);
301 Success
= PeLdrScanImportDescriptorTable(LoadOrderListHead
, FullPath
, *DriverDTE
);
304 ERR("PeLdrScanImportDescriptorTable() failed for %s\n", FullPath
);
312 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock
,
316 PBOOT_DRIVER_LIST_ENTRY BootDriver
;
320 // Walk through the boot drivers list
321 NextBd
= LoaderBlock
->BootDriverListHead
.Flink
;
323 while (NextBd
!= &LoaderBlock
->BootDriverListHead
)
325 BootDriver
= CONTAINING_RECORD(NextBd
, BOOT_DRIVER_LIST_ENTRY
, Link
);
327 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver
->FilePath
,
328 BootDriver
->LdrEntry
, &BootDriver
->RegistryPath
);
330 // Paths are relative (FIXME: Are they always relative?)
333 Success
= WinLdrLoadDeviceDriver(&LoaderBlock
->LoadOrderListHead
,
335 &BootDriver
->FilePath
,
337 &BootDriver
->LdrEntry
);
341 // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
342 BootDriver
->RegistryPath
.Buffer
= PaToVa(BootDriver
->RegistryPath
.Buffer
);
343 BootDriver
->FilePath
.Buffer
= PaToVa(BootDriver
->FilePath
.Buffer
);
344 BootDriver
->LdrEntry
= PaToVa(BootDriver
->LdrEntry
);
348 // Loading failed - cry loudly
349 ERR("Can't load boot driver '%wZ'!\n", &BootDriver
->FilePath
);
350 UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver
->FilePath
);
353 // Remove it from the list and try to continue
354 RemoveEntryList(NextBd
);
357 NextBd
= BootDriver
->Link
.Flink
;
364 WinLdrLoadModule(PCSTR ModuleName
,
366 TYPE_OF_MEMORY MemoryType
)
370 FILEINFORMATION FileInfo
;
375 //CHAR ProgressString[256];
377 /* Inform user we are loading files */
379 //RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", FileName);
380 //UiDrawProgressBarCenter(1, 100, ProgressString);
382 TRACE("Loading module %s\n", ModuleName
);
385 /* Open the image file */
386 Status
= ArcOpen((PSTR
)ModuleName
, OpenReadOnly
, &FileId
);
387 if (Status
!= ESUCCESS
)
389 /* In case of errors, we just return, without complaining to the user */
390 WARN("Error while opening '%s', Status: %u\n", ModuleName
, Status
);
394 /* Retrieve its size */
395 Status
= ArcGetFileInformation(FileId
, &FileInfo
);
396 if (Status
!= ESUCCESS
)
401 FileSize
= FileInfo
.EndingAddress
.LowPart
;
404 /* Allocate memory */
405 PhysicalBase
= MmAllocateMemoryWithType(FileSize
, MemoryType
);
406 if (PhysicalBase
== NULL
)
408 ERR("Could not allocate memory for '%s'\n", ModuleName
);
413 /* Load the whole file */
414 Status
= ArcRead(FileId
, PhysicalBase
, FileSize
, &BytesRead
);
416 if (Status
!= ESUCCESS
)
418 WARN("Error while reading '%s', Status: %u\n", ModuleName
, Status
);
422 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName
, PhysicalBase
, FileSize
);
428 WinLdrDetectVersion(VOID
)
433 rc
= RegOpenKey(NULL
,
434 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
436 if (rc
!= ERROR_SUCCESS
)
438 /* Key doesn't exist; assume NT 4.0 */
439 return _WIN32_WINNT_NT4
;
442 /* We may here want to read the value of ProductVersion */
443 return _WIN32_WINNT_WS03
;
449 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
452 IN PCCH ImportName
, // BaseDllName
453 IN TYPE_OF_MEMORY MemoryType
,
454 OUT PLDR_DATA_TABLE_ENTRY
*Dte
,
458 CHAR FullFileName
[MAX_PATH
];
459 CHAR ProgressString
[256];
460 PVOID BaseAddress
= NULL
;
463 RtlStringCbPrintfA(ProgressString
, sizeof(ProgressString
), "Loading %s...", File
);
464 UiDrawProgressBarCenter(Percentage
, 100, ProgressString
);
466 RtlStringCbCopyA(FullFileName
, sizeof(FullFileName
), Path
);
467 RtlStringCbCatA(FullFileName
, sizeof(FullFileName
), File
);
469 Success
= PeLdrLoadImage(FullFileName
, MemoryType
, &BaseAddress
);
472 TRACE("Loading %s failed\n", File
);
475 TRACE("%s loaded successfully at %p\n", File
, BaseAddress
);
478 * Cheat about the base DLL name if we are loading
479 * the Kernel Debugger Transport DLL, to make the
482 Success
= PeLdrAllocateDataTableEntry(&LoaderBlock
->LoadOrderListHead
,
493 LoadWindowsCore(IN USHORT OperatingSystemVersion
,
494 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
495 IN PCSTR BootOptions
,
497 IN OUT PLDR_DATA_TABLE_ENTRY
* KernelDTE
)
501 CHAR DirPath
[MAX_PATH
];
502 CHAR HalFileName
[MAX_PATH
];
503 CHAR KernelFileName
[MAX_PATH
];
504 CHAR KdTransportDllName
[MAX_PATH
];
505 PLDR_DATA_TABLE_ENTRY HalDTE
, KdComDTE
= NULL
;
507 if (!KernelDTE
) return FALSE
;
509 /* Initialize SystemRoot\System32 path */
510 RtlStringCbCopyA(DirPath
, sizeof(DirPath
), BootPath
);
511 RtlStringCbCatA(DirPath
, sizeof(DirPath
), "system32\\");
514 * Default HAL and KERNEL file names.
515 * See the following links to know how the file names are actually chosen:
516 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/detecthal.htm
517 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/hal.htm
518 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/kernel.htm
520 RtlStringCbCopyA(HalFileName
, sizeof(HalFileName
) , "hal.dll");
521 RtlStringCbCopyA(KernelFileName
, sizeof(KernelFileName
), "ntoskrnl.exe");
523 /* Find any "/HAL=" or "/KERNEL=" switch in the boot options */
524 Options
= BootOptions
;
527 /* Skip possible initial whitespace */
528 Options
+= strspn(Options
, " \t");
530 /* Check whether a new option starts and it is either HAL or KERNEL */
531 if (*Options
!= '/' || (++Options
,
532 !(_strnicmp(Options
, "HAL=", 4) == 0 ||
533 _strnicmp(Options
, "KERNEL=", 7) == 0)) )
535 /* Search for another whitespace */
536 Options
= strpbrk(Options
, " \t");
541 size_t i
= strcspn(Options
, " \t"); /* Skip whitespace */
544 /* Use the default values */
548 /* We have found either HAL or KERNEL options */
549 if (_strnicmp(Options
, "HAL=", 4) == 0)
551 Options
+= 4; i
-= 4;
552 RtlStringCbCopyNA(HalFileName
, sizeof(HalFileName
), Options
, i
);
553 _strupr(HalFileName
);
555 else if (_strnicmp(Options
, "KERNEL=", 7) == 0)
557 Options
+= 7; i
-= 7;
558 RtlStringCbCopyNA(KernelFileName
, sizeof(KernelFileName
), Options
, i
);
559 _strupr(KernelFileName
);
564 TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName
, KernelFileName
);
566 /* Load the Kernel */
567 LoadModule(LoaderBlock
, DirPath
, KernelFileName
, "ntoskrnl.exe", LoaderSystemCode
, KernelDTE
, 30);
570 LoadModule(LoaderBlock
, DirPath
, HalFileName
, "hal.dll", LoaderHalCode
, &HalDTE
, 45);
572 /* Load the Kernel Debugger Transport DLL */
573 if (OperatingSystemVersion
> _WIN32_WINNT_WIN2K
)
576 * According to http://www.nynaeve.net/?p=173 :
577 * "[...] Another enhancement that could be done Microsoft-side would be
578 * a better interface for replacing KD transport modules. Right now, due
579 * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
580 * has a hardcoded hack that interprets the KD type in the OS loader options,
581 * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
582 * "kdusb2.dll" modules, and inserts them into the loaded module list under
583 * the name "kdcom.dll". [...]"
587 * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
588 * Indeed I want it to be case-insensitive to allow "debugport="
589 * or "DeBuGpOrT=" or... , and I don't want it to match malformed
590 * command-line options, such as:
592 * "...foo DEBUGPORT=xxx bar..."
593 * "...foo/DEBUGPORT=xxx bar..."
594 * "...foo/DEBUGPORT=bar..."
596 * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
597 * from the rest by whitespace, unless it begins the command-line, e.g.:
599 * "/DEBUGPORT=COM1 foo...bar..."
600 * "...foo /DEBUGPORT=USB bar..."
602 * "...foo /DEBUGPORT= bar..."
603 * (in that case, we default the port to COM).
605 Options
= BootOptions
;
608 /* Skip possible initial whitespace */
609 Options
+= strspn(Options
, " \t");
611 /* Check whether a new option starts and it is the DEBUGPORT one */
612 if (*Options
!= '/' || _strnicmp(++Options
, "DEBUGPORT=", 10) != 0)
614 /* Search for another whitespace */
615 Options
= strpbrk(Options
, " \t");
620 /* We found the DEBUGPORT option. Move to the port name. */
629 * We have found the DEBUGPORT option. Parse the port name.
630 * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
631 * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
633 RtlStringCbCopyA(KdTransportDllName
, sizeof(KdTransportDllName
), "KD");
634 if (_strnicmp(Options
, "COM", 3) == 0 && '0' <= Options
[3] && Options
[3] <= '9')
636 RtlStringCbCatNA(KdTransportDllName
, sizeof(KdTransportDllName
), Options
, 3);
640 size_t i
= strcspn(Options
, " \t:"); /* Skip valid separators: whitespace or colon */
642 RtlStringCbCatA(KdTransportDllName
, sizeof(KdTransportDllName
), "COM");
644 RtlStringCbCatNA(KdTransportDllName
, sizeof(KdTransportDllName
), Options
, i
);
646 RtlStringCbCatA(KdTransportDllName
, sizeof(KdTransportDllName
), ".DLL");
647 _strupr(KdTransportDllName
);
650 * Load the transport DLL. Override the base DLL name of the
651 * loaded transport DLL to the default "KDCOM.DLL" name.
653 LoadModule(LoaderBlock
, DirPath
, KdTransportDllName
, "kdcom.dll", LoaderSystemCode
, &KdComDTE
, 60);
657 /* Parse the boot options */
658 Options
= BootOptions
;
659 TRACE("LoadWindowsCore: BootOptions '%s'\n", BootOptions
);
662 /* Skip possible initial whitespace */
663 Options
+= strspn(Options
, " \t");
665 /* Check whether a new option starts */
670 if (_strnicmp(Options
, "3GB", 3) == 0)
672 /* We found the 3GB option. */
673 FIXME("LoadWindowsCore: 3GB - TRUE (not implemented)\n");
676 if (_strnicmp(Options
, "SOS", 3) == 0)
678 /* We found the SOS option. */
679 FIXME("LoadWindowsCore: SOS - TRUE (not implemented)\n");
682 if (OperatingSystemVersion
> _WIN32_WINNT_NT4
)
684 if (_strnicmp(Options
, "SAFEBOOT", 8) == 0)
686 /* We found the SAFEBOOT option. */
687 FIXME("LoadWindowsCore: SAFEBOOT - TRUE (not implemented)\n");
690 if (_strnicmp(Options
, "PAE", 3) == 0)
692 /* We found the PAE option. */
693 FIXME("LoadWindowsCore: PAE - TRUE (not implemented)\n");
697 if (OperatingSystemVersion
> _WIN32_WINNT_WIN2K
)
699 if (_strnicmp(Options
, "NOPAE", 5) == 0)
701 /* We found the NOPAE option. */
702 FIXME("LoadWindowsCore: NOPAE - TRUE (not implemented)\n");
705 if (_strnicmp(Options
, "BOOTLOGO", 8) == 0)
707 /* We found the BOOTLOGO option. */
708 FIXME("LoadWindowsCore: BOOTLOGO - TRUE (not implemented)\n");
711 if (!LoaderBlock
->SetupLdrBlock
)
713 if (_strnicmp(Options
, "NOEXECUTE=ALWAYSOFF", 19) == 0)
715 /* We found the NOEXECUTE=ALWAYSOFF option. */
716 FIXME("LoadWindowsCore: NOEXECUTE=ALWAYSOFF - TRUE (not implemented)\n");
717 NoexecuteDisabled
= TRUE
;
719 else if (_strnicmp(Options
, "NOEXECUTE", 9) == 0)
721 /* We found the NOEXECUTE option. */
722 FIXME("LoadWindowsCore: NOEXECUTE - TRUE (not implemented)\n");
723 NoexecuteEnabled
= TRUE
;
726 if (_strnicmp(Options
, "EXECUTE", 7) == 0)
728 /* We found the EXECUTE option. */
729 FIXME("LoadWindowsCore: EXECUTE - TRUE (not implemented)\n");
730 NoexecuteDisabled
= TRUE
;
736 /* Search for another whitespace */
737 Options
= strpbrk(Options
, " \t");
743 NoexecuteDisabled
= TRUE
;
746 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
747 Success
= PeLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, *KernelDTE
);
748 Success
&= PeLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, HalDTE
);
751 Success
&= PeLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, KdComDTE
);
760 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
761 IN USHORT OperatingSystemVersion
,
769 WCHAR szFileName
[80];
770 CHAR ErrataFilePath
[MAX_PATH
];
772 /* Open either the 'BiosInfo' (Windows <= 2003) or the 'Errata' (Vista+) key */
773 if (OperatingSystemVersion
>= _WIN32_WINNT_VISTA
)
775 rc
= RegOpenKey(NULL
,
776 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Errata",
779 else // (OperatingSystemVersion <= _WIN32_WINNT_WS03)
781 rc
= RegOpenKey(NULL
,
782 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\BiosInfo",
785 if (rc
!= ERROR_SUCCESS
)
787 WARN("Could not open the BiosInfo/Errata registry key (Error %u)\n", (int)rc
);
791 /* Retrieve the INF file name value */
792 BufferSize
= sizeof(szFileName
);
793 rc
= RegQueryValue(hKey
, L
"InfName", NULL
, (PUCHAR
)szFileName
, &BufferSize
);
794 if (rc
!= ERROR_SUCCESS
)
796 WARN("Could not retrieve the InfName value (Error %u)\n", (int)rc
);
800 // TODO: "SystemBiosDate"
802 RtlStringCbPrintfA(ErrataFilePath
, sizeof(ErrataFilePath
), "%s%s%S",
803 SystemRoot
, "inf\\", szFileName
);
805 /* Load the INF file */
806 PhysicalBase
= WinLdrLoadModule(ErrataFilePath
, &FileSize
, LoaderRegistryData
);
809 WARN("Could not load '%s'\n", ErrataFilePath
);
813 LoaderBlock
->Extension
->EmInfFileImage
= PaToVa(PhysicalBase
);
814 LoaderBlock
->Extension
->EmInfFileSize
= FileSize
;
827 PCSTR SystemPartition
;
830 USHORT OperatingSystemVersion
;
831 PLOADER_PARAMETER_BLOCK LoaderBlock
;
832 CHAR BootPath
[MAX_PATH
];
833 CHAR FileName
[MAX_PATH
];
834 CHAR BootOptions
[256];
836 /* Retrieve the (mandatory) boot type */
837 ArgValue
= GetArgumentValue(Argc
, Argv
, "BootType");
838 if (!ArgValue
|| !*ArgValue
)
840 ERR("No 'BootType' value, aborting!\n");
844 /* Convert it to an OS version */
845 if (_stricmp(ArgValue
, "Windows") == 0 ||
846 _stricmp(ArgValue
, "Windows2003") == 0)
848 OperatingSystemVersion
= _WIN32_WINNT_WS03
;
850 else if (_stricmp(ArgValue
, "WindowsNT40") == 0)
852 OperatingSystemVersion
= _WIN32_WINNT_NT4
;
856 ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue
);
860 /* Retrieve the (mandatory) system partition */
861 SystemPartition
= GetArgumentValue(Argc
, Argv
, "SystemPartition");
862 if (!SystemPartition
|| !*SystemPartition
)
864 ERR("No 'SystemPartition' specified, aborting!\n");
869 UiDrawProgressBarCenter(1, 100, "Loading NT...");
871 /* Retrieve the system path */
872 *BootPath
= ANSI_NULL
;
873 ArgValue
= GetArgumentValue(Argc
, Argv
, "SystemPath");
875 RtlStringCbCopyA(BootPath
, sizeof(BootPath
), ArgValue
);
878 * Check whether BootPath is a full path
879 * and if not, create a full boot path.
881 * See FsOpenFile for the technique used.
883 if (strrchr(BootPath
, ')') == NULL
)
885 /* Temporarily save the boot path */
886 RtlStringCbCopyA(FileName
, sizeof(FileName
), BootPath
);
888 /* This is not a full path: prepend the SystemPartition */
889 RtlStringCbCopyA(BootPath
, sizeof(BootPath
), SystemPartition
);
891 /* Append a path separator if needed */
892 if (*FileName
!= '\\' && *FileName
!= '/')
893 RtlStringCbCatA(BootPath
, sizeof(BootPath
), "\\");
895 /* Append the remaining path */
896 RtlStringCbCatA(BootPath
, sizeof(BootPath
), FileName
);
899 /* Append a path separator if needed */
900 if (!*BootPath
|| BootPath
[strlen(BootPath
) - 1] != '\\')
901 RtlStringCbCatA(BootPath
, sizeof(BootPath
), "\\");
903 TRACE("BootPath: '%s'\n", BootPath
);
905 /* Retrieve the boot options */
906 *BootOptions
= ANSI_NULL
;
907 ArgValue
= GetArgumentValue(Argc
, Argv
, "Options");
908 if (ArgValue
&& *ArgValue
)
909 RtlStringCbCopyA(BootOptions
, sizeof(BootOptions
), ArgValue
);
911 /* Append boot-time options */
912 AppendBootTimeOptions(BootOptions
);
915 * Set "/HAL=" and "/KERNEL=" options if needed.
916 * If already present on the standard "Options=" option line, they take
917 * precedence over those passed via the separate "Hal=" and "Kernel="
920 if (strstr(BootOptions
, "/HAL=") != 0)
923 * Not found in the options, try to retrieve the
924 * separate value and append it to the options.
926 ArgValue
= GetArgumentValue(Argc
, Argv
, "Hal");
927 if (ArgValue
&& *ArgValue
)
929 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), " /HAL=");
930 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), ArgValue
);
933 if (strstr(BootOptions
, "/KERNEL=") != 0)
936 * Not found in the options, try to retrieve the
937 * separate value and append it to the options.
939 ArgValue
= GetArgumentValue(Argc
, Argv
, "Kernel");
940 if (ArgValue
&& *ArgValue
)
942 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), " /KERNEL=");
943 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), ArgValue
);
947 TRACE("BootOptions: '%s'\n", BootOptions
);
949 /* Check if a ramdisk file was given */
950 File
= strstr(BootOptions
, "/RDPATH=");
953 /* Load the ramdisk */
954 Status
= RamDiskInitialize(FALSE
, BootOptions
, SystemPartition
);
955 if (Status
!= ESUCCESS
)
958 UiMessageBox("Failed to load RAM disk file '%.*s'",
959 strcspn(File
, " \t"), File
);
964 /* Let user know we started loading */
965 //UiDrawStatusText("Loading...");
967 /* Allocate and minimally-initialize the Loader Parameter Block */
968 AllocateAndInitLPB(OperatingSystemVersion
, &LoaderBlock
);
970 /* Load the system hive */
972 UiDrawProgressBarCenter(15, 100, "Loading system hive...");
973 Success
= WinLdrInitSystemHive(LoaderBlock
, BootPath
, FALSE
);
974 TRACE("SYSTEM hive %s\n", (Success
? "loaded" : "not loaded"));
975 /* Bail out if failure */
979 /* Fixup the version number using data from the registry */
980 if (OperatingSystemVersion
== 0)
981 OperatingSystemVersion
= WinLdrDetectVersion();
982 LoaderBlock
->Extension
->MajorVersion
= (OperatingSystemVersion
& 0xFF00) >> 8;
983 LoaderBlock
->Extension
->MinorVersion
= (OperatingSystemVersion
& 0xFF);
985 /* Load NLS data, OEM font, and prepare boot drivers list */
986 Success
= WinLdrScanSystemHive(LoaderBlock
, BootPath
);
987 TRACE("SYSTEM hive %s\n", (Success
? "scanned" : "not scanned"));
988 /* Bail out if failure */
992 /* Load the Firmware Errata file */
993 Success
= WinLdrInitErrataInf(LoaderBlock
, OperatingSystemVersion
, BootPath
);
994 TRACE("Firmware Errata file %s\n", (Success
? "loaded" : "not loaded"));
995 /* Not necessarily fatal if not found - carry on going */
998 return LoadAndBootWindowsCommon(OperatingSystemVersion
,
1006 LoadAndBootWindowsCommon(
1007 USHORT OperatingSystemVersion
,
1008 PLOADER_PARAMETER_BLOCK LoaderBlock
,
1013 PLOADER_PARAMETER_BLOCK LoaderBlockVA
;
1015 PLDR_DATA_TABLE_ENTRY KernelDTE
;
1016 KERNEL_ENTRY_POINT KiSystemStartup
;
1019 TRACE("LoadAndBootWindowsCommon()\n");
1021 ASSERT(OperatingSystemVersion
!= 0);
1024 /* Setup redirection support */
1025 WinLdrSetupEms((PCHAR
)BootOptions
);
1028 /* Convert BootPath to SystemRoot */
1029 SystemRoot
= strstr(BootPath
, "\\");
1031 /* Detect hardware */
1033 UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
1034 LoaderBlock
->ConfigurationRoot
= MachHwDetect();
1036 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
1037 Success
= LoadWindowsCore(OperatingSystemVersion
,
1044 UiMessageBox("Error loading NTOS core.");
1048 /* Load boot drivers */
1050 UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
1051 Success
= WinLdrLoadBootDrivers(LoaderBlock
, BootPath
);
1052 TRACE("Boot drivers loading %s\n", Success
? "successful" : "failed");
1054 /* Cleanup ini file */
1057 /* Initialize Phase 1 - no drivers loading anymore */
1058 WinLdrInitializePhase1(LoaderBlock
,
1062 OperatingSystemVersion
);
1064 /* Save entry-point pointer and Loader block VAs */
1065 KiSystemStartup
= (KERNEL_ENTRY_POINT
)KernelDTE
->EntryPoint
;
1066 LoaderBlockVA
= PaToVa(LoaderBlock
);
1068 /* "Stop all motors", change videomode */
1069 MachPrepareForReactOS();
1072 //DumpMemoryAllocMap();
1074 /* Do the machine specific initialization */
1075 WinLdrSetupMachineDependent(LoaderBlock
);
1077 /* Map pages and create memory descriptors */
1078 WinLdrSetupMemoryLayout(LoaderBlock
);
1080 /* Set processor context */
1081 WinLdrSetProcessorContext();
1083 /* Save final value of LoaderPagesSpanned */
1084 LoaderBlock
->Extension
->LoaderPagesSpanned
= LoaderPagesSpanned
;
1086 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
1087 KiSystemStartup
, LoaderBlockVA
);
1089 /* Zero KI_USER_SHARED_DATA page */
1090 RtlZeroMemory((PVOID
)KI_USER_SHARED_DATA
, MM_PAGE_SIZE
);
1092 WinLdrpDumpMemoryDescriptors(LoaderBlockVA
);
1093 WinLdrpDumpBootDriver(LoaderBlockVA
);
1095 WinLdrpDumpArcDisks(LoaderBlockVA
);
1099 (*KiSystemStartup
)(LoaderBlockVA
);
1104 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock
)
1107 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
;
1109 NextMd
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
1111 while (NextMd
!= &LoaderBlock
->MemoryDescriptorListHead
)
1113 MemoryDescriptor
= CONTAINING_RECORD(NextMd
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
1115 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor
->BasePage
,
1116 MemoryDescriptor
->PageCount
, MemoryDescriptor
->MemoryType
);
1118 NextMd
= MemoryDescriptor
->ListEntry
.Flink
;
1123 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock
)
1126 PBOOT_DRIVER_LIST_ENTRY BootDriver
;
1128 NextBd
= LoaderBlock
->BootDriverListHead
.Flink
;
1130 while (NextBd
!= &LoaderBlock
->BootDriverListHead
)
1132 BootDriver
= CONTAINING_RECORD(NextBd
, BOOT_DRIVER_LIST_ENTRY
, Link
);
1134 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver
->FilePath
,
1135 BootDriver
->LdrEntry
, &BootDriver
->RegistryPath
);
1137 NextBd
= BootDriver
->Link
.Flink
;
1142 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock
)
1145 PARC_DISK_SIGNATURE ArcDisk
;
1147 NextBd
= LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
.Flink
;
1149 while (NextBd
!= &LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
)
1151 ArcDisk
= CONTAINING_RECORD(NextBd
, ARC_DISK_SIGNATURE
, ListEntry
);
1153 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
1154 ArcDisk
->ArcName
, ArcDisk
->CheckSum
, ArcDisk
->Signature
);
1156 NextBd
= ArcDisk
->ListEntry
.Flink
;