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
;
30 VOID
DumpMemoryAllocMap(VOID
);
34 AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK
*OutLoaderBlock
)
36 PLOADER_PARAMETER_BLOCK LoaderBlock
;
38 /* Allocate and zero-init the LPB */
39 WinLdrSystemBlock
= MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK
),
41 if (WinLdrSystemBlock
== NULL
)
43 UiMessageBox("Failed to allocate memory for system block!");
47 RtlZeroMemory(WinLdrSystemBlock
, sizeof(LOADER_SYSTEM_BLOCK
));
49 LoaderBlock
= &WinLdrSystemBlock
->LoaderBlock
;
50 LoaderBlock
->NlsData
= &WinLdrSystemBlock
->NlsDataBlock
;
52 /* Init three critical lists, used right away */
53 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
54 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
55 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
57 *OutLoaderBlock
= LoaderBlock
;
62 WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock
,
69 * Examples of correct options and paths:
70 * CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
71 * CHAR Options[] = "/NODEBUG";
72 * CHAR SystemRoot[] = "\\WINNT\\";
73 * CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
76 PSTR LoadOptions
, NewLoadOptions
;
77 CHAR HalPath
[] = "\\";
78 CHAR ArcBoot
[MAX_PATH
+1];
79 CHAR MiscFiles
[MAX_PATH
+1];
81 ULONG_PTR PathSeparator
;
82 PLOADER_PARAMETER_EXTENSION Extension
;
84 /* Construct SystemRoot and ArcBoot from SystemPath */
85 PathSeparator
= strstr(BootPath
, "\\") - BootPath
;
86 RtlStringCbCopyNA(ArcBoot
, sizeof(ArcBoot
), BootPath
, PathSeparator
);
88 TRACE("ArcBoot: '%s'\n", ArcBoot
);
89 TRACE("SystemRoot: '%s'\n", SystemRoot
);
90 TRACE("Options: '%s'\n", Options
);
92 /* Fill ARC BootDevice */
93 LoaderBlock
->ArcBootDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
94 RtlStringCbCopyA(LoaderBlock
->ArcBootDeviceName
, sizeof(WinLdrSystemBlock
->ArcBootDeviceName
), ArcBoot
);
95 LoaderBlock
->ArcBootDeviceName
= PaToVa(LoaderBlock
->ArcBootDeviceName
);
99 // SetupBlock->ArcSetupDeviceName must be the path to the setup **SOURCE**,
100 // and not the setup boot path. Indeed they may differ!!
102 /* If we have a setup block, adjust also its ARC path */
103 if (LoaderBlock
->SetupLdrBlock
)
105 PSETUP_LOADER_BLOCK SetupBlock
= LoaderBlock
->SetupLdrBlock
;
107 /* Matches ArcBoot path */
108 SetupBlock
->ArcSetupDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
109 SetupBlock
->ArcSetupDeviceName
= PaToVa(SetupBlock
->ArcSetupDeviceName
);
111 /* Note: LoaderBlock->SetupLdrBlock is PaToVa'ed at the end of this function */
114 /* Fill ARC HalDevice, it matches ArcBoot path */
115 LoaderBlock
->ArcHalDeviceName
= WinLdrSystemBlock
->ArcBootDeviceName
;
116 LoaderBlock
->ArcHalDeviceName
= PaToVa(LoaderBlock
->ArcHalDeviceName
);
118 /* Fill SystemRoot */
119 LoaderBlock
->NtBootPathName
= WinLdrSystemBlock
->NtBootPathName
;
120 RtlStringCbCopyA(LoaderBlock
->NtBootPathName
, sizeof(WinLdrSystemBlock
->NtBootPathName
), SystemRoot
);
121 LoaderBlock
->NtBootPathName
= PaToVa(LoaderBlock
->NtBootPathName
);
123 /* Fill NtHalPathName */
124 LoaderBlock
->NtHalPathName
= WinLdrSystemBlock
->NtHalPathName
;
125 RtlStringCbCopyA(LoaderBlock
->NtHalPathName
, sizeof(WinLdrSystemBlock
->NtHalPathName
), HalPath
);
126 LoaderBlock
->NtHalPathName
= PaToVa(LoaderBlock
->NtHalPathName
);
128 /* Fill LoadOptions and strip the '/' switch symbol in front of each option */
129 NewLoadOptions
= LoadOptions
= LoaderBlock
->LoadOptions
= WinLdrSystemBlock
->LoadOptions
;
130 RtlStringCbCopyA(LoaderBlock
->LoadOptions
, sizeof(WinLdrSystemBlock
->LoadOptions
), Options
);
134 while (*LoadOptions
== '/')
137 *NewLoadOptions
++ = *LoadOptions
;
138 } while (*LoadOptions
++);
140 LoaderBlock
->LoadOptions
= PaToVa(LoaderBlock
->LoadOptions
);
143 LoaderBlock
->ArcDiskInformation
= &WinLdrSystemBlock
->ArcDiskInformation
;
144 InitializeListHead(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
146 /* Convert ARC disk information from freeldr to a correct format */
147 for (i
= 0; i
< reactos_disk_count
; i
++)
149 PARC_DISK_SIGNATURE_EX ArcDiskSig
;
151 /* Allocate the ARC structure */
152 ArcDiskSig
= FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX
), 'giSD');
154 /* Copy the data over */
155 RtlCopyMemory(ArcDiskSig
, &reactos_arc_disk_info
[i
], sizeof(ARC_DISK_SIGNATURE_EX
));
157 /* Set the ARC Name pointer */
158 ArcDiskSig
->DiskSignature
.ArcName
= PaToVa(ArcDiskSig
->ArcName
);
160 /* Insert into the list */
161 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
162 &ArcDiskSig
->DiskSignature
.ListEntry
);
165 /* Convert all list's to Virtual address */
167 /* Convert the ArcDisks list to virtual address */
168 List_PaToVa(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
169 LoaderBlock
->ArcDiskInformation
= PaToVa(LoaderBlock
->ArcDiskInformation
);
171 /* Convert configuration entries to VA */
172 ConvertConfigToVA(LoaderBlock
->ConfigurationRoot
);
173 LoaderBlock
->ConfigurationRoot
= PaToVa(LoaderBlock
->ConfigurationRoot
);
175 /* Convert all DTE into virtual addresses */
176 List_PaToVa(&LoaderBlock
->LoadOrderListHead
);
178 /* This one will be converted right before switching to virtual paging mode */
179 //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
181 /* Convert list of boot drivers */
182 List_PaToVa(&LoaderBlock
->BootDriverListHead
);
184 /* Initialize Extension now */
185 Extension
= &WinLdrSystemBlock
->Extension
;
186 Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
187 Extension
->MajorVersion
= (VersionToBoot
& 0xFF00) >> 8;
188 Extension
->MinorVersion
= VersionToBoot
& 0xFF;
189 Extension
->Profile
.Status
= 2;
191 /* Check if FreeLdr detected a ACPI table */
194 /* Set the pointer to something for compatibility */
195 Extension
->AcpiTable
= (PVOID
)1;
196 // FIXME: Extension->AcpiTableSize;
200 /* Set headless block pointer */
201 if (WinLdrTerminalConnected
)
203 Extension
->HeadlessLoaderBlock
= &WinLdrSystemBlock
->HeadlessLoaderBlock
;
204 RtlCopyMemory(Extension
->HeadlessLoaderBlock
,
205 &LoaderRedirectionInformation
,
206 sizeof(HEADLESS_LOADER_BLOCK
));
207 Extension
->HeadlessLoaderBlock
= PaToVa(Extension
->HeadlessLoaderBlock
);
210 /* Load drivers database */
211 RtlStringCbCopyA(MiscFiles
, sizeof(MiscFiles
), BootPath
);
212 RtlStringCbCatA(MiscFiles
, sizeof(MiscFiles
), "AppPatch\\drvmain.sdb");
213 Extension
->DrvDBImage
= PaToVa(WinLdrLoadModule(MiscFiles
,
214 &Extension
->DrvDBSize
,
215 LoaderRegistryData
));
217 /* Convert extension and setup block pointers */
218 LoaderBlock
->Extension
= PaToVa(Extension
);
220 if (LoaderBlock
->SetupLdrBlock
)
221 LoaderBlock
->SetupLdrBlock
= PaToVa(LoaderBlock
->SetupLdrBlock
);
223 TRACE("WinLdrInitializePhase1() completed\n");
227 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead
,
229 PUNICODE_STRING FilePath
,
231 PLDR_DATA_TABLE_ENTRY
*DriverDTE
)
234 CHAR DriverPath
[1024];
238 PVOID DriverBase
= NULL
;
240 // Separate the path to file name and directory path
241 RtlStringCbPrintfA(DriverPath
, sizeof(DriverPath
), "%wZ", FilePath
);
242 DriverNamePos
= strrchr(DriverPath
, '\\');
243 if (DriverNamePos
!= NULL
)
246 RtlStringCbCopyA(DllName
, sizeof(DllName
), DriverNamePos
+1);
248 // Cut out the name from the path
249 *(DriverNamePos
+1) = ANSI_NULL
;
253 // There is no directory in the path
254 RtlStringCbCopyA(DllName
, sizeof(DllName
), DriverPath
);
255 *DriverPath
= ANSI_NULL
;
258 TRACE("DriverPath: '%s', DllName: '%s', LPB\n", DriverPath
, DllName
);
260 // Check if driver is already loaded
261 Success
= WinLdrCheckForLoadedDll(LoadOrderListHead
, DllName
, DriverDTE
);
264 // We've got the pointer to its DTE, just return success
268 // It's not loaded, we have to load it
269 RtlStringCbPrintfA(FullPath
, sizeof(FullPath
), "%s%wZ", BootPath
, FilePath
);
270 Success
= WinLdrLoadImage(FullPath
, LoaderBootDriver
, &DriverBase
);
274 // Allocate a DTE for it
275 Success
= WinLdrAllocateDataTableEntry(LoadOrderListHead
, DllName
, DllName
, DriverBase
, DriverDTE
);
278 ERR("WinLdrAllocateDataTableEntry() failed\n");
282 // Modify any flags, if needed
283 (*DriverDTE
)->Flags
|= Flags
;
285 // Look for any dependencies it may have, and load them too
286 RtlStringCbPrintfA(FullPath
, sizeof(FullPath
), "%s%s", BootPath
, DriverPath
);
287 Success
= WinLdrScanImportDescriptorTable(LoadOrderListHead
, FullPath
, *DriverDTE
);
290 ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath
);
298 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock
,
302 PBOOT_DRIVER_LIST_ENTRY BootDriver
;
306 // Walk through the boot drivers list
307 NextBd
= LoaderBlock
->BootDriverListHead
.Flink
;
309 while (NextBd
!= &LoaderBlock
->BootDriverListHead
)
311 BootDriver
= CONTAINING_RECORD(NextBd
, BOOT_DRIVER_LIST_ENTRY
, Link
);
313 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver
->FilePath
,
314 BootDriver
->LdrEntry
, &BootDriver
->RegistryPath
);
316 // Paths are relative (FIXME: Are they always relative?)
319 Success
= WinLdrLoadDeviceDriver(&LoaderBlock
->LoadOrderListHead
,
321 &BootDriver
->FilePath
,
323 &BootDriver
->LdrEntry
);
327 // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
328 BootDriver
->RegistryPath
.Buffer
= PaToVa(BootDriver
->RegistryPath
.Buffer
);
329 BootDriver
->FilePath
.Buffer
= PaToVa(BootDriver
->FilePath
.Buffer
);
330 BootDriver
->LdrEntry
= PaToVa(BootDriver
->LdrEntry
);
334 // Loading failed - cry loudly
335 ERR("Can't load boot driver '%wZ'!\n", &BootDriver
->FilePath
);
336 UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver
->FilePath
);
339 // Remove it from the list and try to continue
340 RemoveEntryList(NextBd
);
343 NextBd
= BootDriver
->Link
.Flink
;
350 WinLdrLoadModule(PCSTR ModuleName
,
352 TYPE_OF_MEMORY MemoryType
)
356 FILEINFORMATION FileInfo
;
361 //CHAR ProgressString[256];
363 /* Inform user we are loading files */
365 //RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", FileName);
366 //UiDrawProgressBarCenter(1, 100, ProgressString);
368 TRACE("Loading module %s\n", ModuleName
);
371 /* Open the image file */
372 Status
= ArcOpen((PSTR
)ModuleName
, OpenReadOnly
, &FileId
);
373 if (Status
!= ESUCCESS
)
375 /* In case of errors, we just return, without complaining to the user */
376 WARN("Error while opening '%s', Status: %u\n", ModuleName
, Status
);
380 /* Get this file's size */
381 Status
= ArcGetFileInformation(FileId
, &FileInfo
);
382 if (Status
!= ESUCCESS
)
387 FileSize
= FileInfo
.EndingAddress
.LowPart
;
390 /* Allocate memory */
391 PhysicalBase
= MmAllocateMemoryWithType(FileSize
, MemoryType
);
392 if (PhysicalBase
== NULL
)
398 /* Load whole file */
399 Status
= ArcRead(FileId
, PhysicalBase
, FileSize
, &BytesRead
);
401 if (Status
!= ESUCCESS
)
403 WARN("Error while reading '%s', Status: %u\n", ModuleName
, Status
);
407 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName
, PhysicalBase
, FileSize
);
413 WinLdrDetectVersion(VOID
)
418 rc
= RegOpenKey(NULL
,
419 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
421 if (rc
!= ERROR_SUCCESS
)
423 /* Key doesn't exist; assume NT 4.0 */
424 return _WIN32_WINNT_NT4
;
427 /* We may here want to read the value of ProductVersion */
428 return _WIN32_WINNT_WS03
;
434 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
437 IN PCCH ImportName
, // BaseDllName
438 IN TYPE_OF_MEMORY MemoryType
,
439 OUT PLDR_DATA_TABLE_ENTRY
*Dte
,
443 CHAR FullFileName
[MAX_PATH
];
444 CHAR ProgressString
[256];
445 PVOID BaseAddress
= NULL
;
448 RtlStringCbPrintfA(ProgressString
, sizeof(ProgressString
), "Loading %s...", File
);
449 UiDrawProgressBarCenter(Percentage
, 100, ProgressString
);
451 RtlStringCbCopyA(FullFileName
, sizeof(FullFileName
), Path
);
452 RtlStringCbCatA(FullFileName
, sizeof(FullFileName
), File
);
454 Success
= WinLdrLoadImage(FullFileName
, MemoryType
, &BaseAddress
);
457 TRACE("Loading %s failed\n", File
);
460 TRACE("%s loaded successfully at %p\n", File
, BaseAddress
);
463 * Cheat about the base DLL name if we are loading
464 * the Kernel Debugger Transport DLL, to make the
467 Success
= WinLdrAllocateDataTableEntry(&LoaderBlock
->LoadOrderListHead
,
478 LoadWindowsCore(IN USHORT OperatingSystemVersion
,
479 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
480 IN PCSTR BootOptions
,
482 IN OUT PLDR_DATA_TABLE_ENTRY
* KernelDTE
)
486 CHAR DirPath
[MAX_PATH
];
487 CHAR HalFileName
[MAX_PATH
];
488 CHAR KernelFileName
[MAX_PATH
];
489 CHAR KdTransportDllName
[MAX_PATH
];
490 PLDR_DATA_TABLE_ENTRY HalDTE
, KdComDTE
= NULL
;
492 if (!KernelDTE
) return FALSE
;
494 /* Initialize SystemRoot\System32 path */
495 RtlStringCbCopyA(DirPath
, sizeof(DirPath
), BootPath
);
496 RtlStringCbCatA(DirPath
, sizeof(DirPath
), "system32\\");
499 * Default HAL and KERNEL file names.
500 * See the following links to know how the file names are actually chosen:
501 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/detecthal.htm
502 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/hal.htm
503 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/kernel.htm
505 RtlStringCbCopyA(HalFileName
, sizeof(HalFileName
) , "hal.dll");
506 RtlStringCbCopyA(KernelFileName
, sizeof(KernelFileName
), "ntoskrnl.exe");
508 /* Find any "/HAL=" or "/KERNEL=" switch in the boot options */
509 Options
= BootOptions
;
512 /* Skip possible initial whitespace */
513 Options
+= strspn(Options
, " \t");
515 /* Check whether a new option starts and it is either HAL or KERNEL */
516 if (*Options
!= '/' || (++Options
,
517 !(_strnicmp(Options
, "HAL=", 4) == 0 ||
518 _strnicmp(Options
, "KERNEL=", 7) == 0)) )
520 /* Search for another whitespace */
521 Options
= strpbrk(Options
, " \t");
526 size_t i
= strcspn(Options
, " \t"); /* Skip whitespace */
529 /* Use the default values */
533 /* We have found either HAL or KERNEL options */
534 if (_strnicmp(Options
, "HAL=", 4) == 0)
536 Options
+= 4; i
-= 4;
537 RtlStringCbCopyNA(HalFileName
, sizeof(HalFileName
), Options
, i
);
538 _strupr(HalFileName
);
540 else if (_strnicmp(Options
, "KERNEL=", 7) == 0)
542 Options
+= 7; i
-= 7;
543 RtlStringCbCopyNA(KernelFileName
, sizeof(KernelFileName
), Options
, i
);
544 _strupr(KernelFileName
);
549 TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName
, KernelFileName
);
551 /* Load the Kernel */
552 LoadModule(LoaderBlock
, DirPath
, KernelFileName
, "ntoskrnl.exe", LoaderSystemCode
, KernelDTE
, 30);
555 LoadModule(LoaderBlock
, DirPath
, HalFileName
, "hal.dll", LoaderHalCode
, &HalDTE
, 45);
557 /* Load the Kernel Debugger Transport DLL */
558 if (OperatingSystemVersion
> _WIN32_WINNT_WIN2K
)
561 * According to http://www.nynaeve.net/?p=173 :
562 * "[...] Another enhancement that could be done Microsoft-side would be
563 * a better interface for replacing KD transport modules. Right now, due
564 * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
565 * has a hardcoded hack that interprets the KD type in the OS loader options,
566 * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
567 * "kdusb2.dll" modules, and inserts them into the loaded module list under
568 * the name "kdcom.dll". [...]"
572 * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
573 * Indeed I want it to be case-insensitive to allow "debugport="
574 * or "DeBuGpOrT=" or... , and I don't want it to match malformed
575 * command-line options, such as:
577 * "...foo DEBUGPORT=xxx bar..."
578 * "...foo/DEBUGPORT=xxx bar..."
579 * "...foo/DEBUGPORT=bar..."
581 * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
582 * from the rest by whitespace, unless it begins the command-line, e.g.:
584 * "/DEBUGPORT=COM1 foo...bar..."
585 * "...foo /DEBUGPORT=USB bar..."
587 * "...foo /DEBUGPORT= bar..."
588 * (in that case, we default the port to COM).
590 Options
= BootOptions
;
593 /* Skip possible initial whitespace */
594 Options
+= strspn(Options
, " \t");
596 /* Check whether a new option starts and it is the DEBUGPORT one */
597 if (*Options
!= '/' || _strnicmp(++Options
, "DEBUGPORT=", 10) != 0)
599 /* Search for another whitespace */
600 Options
= strpbrk(Options
, " \t");
605 /* We found the DEBUGPORT option. Move to the port name. */
614 * We have found the DEBUGPORT option. Parse the port name.
615 * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
616 * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
618 RtlStringCbCopyA(KdTransportDllName
, sizeof(KdTransportDllName
), "KD");
619 if (_strnicmp(Options
, "COM", 3) == 0 && '0' <= Options
[3] && Options
[3] <= '9')
621 RtlStringCbCatNA(KdTransportDllName
, sizeof(KdTransportDllName
), Options
, 3);
625 size_t i
= strcspn(Options
, " \t:"); /* Skip valid separators: whitespace or colon */
627 RtlStringCbCatA(KdTransportDllName
, sizeof(KdTransportDllName
), "COM");
629 RtlStringCbCatNA(KdTransportDllName
, sizeof(KdTransportDllName
), Options
, i
);
631 RtlStringCbCatA(KdTransportDllName
, sizeof(KdTransportDllName
), ".DLL");
632 _strupr(KdTransportDllName
);
635 * Load the transport DLL. Override the base DLL name of the
636 * loaded transport DLL to the default "KDCOM.DLL" name.
638 LoadModule(LoaderBlock
, DirPath
, KdTransportDllName
, "kdcom.dll", LoaderSystemCode
, &KdComDTE
, 60);
642 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
643 Success
= WinLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, *KernelDTE
);
644 Success
&= WinLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, HalDTE
);
647 Success
&= WinLdrScanImportDescriptorTable(&LoaderBlock
->LoadOrderListHead
, DirPath
, KdComDTE
);
661 PCSTR SystemPartition
;
664 USHORT OperatingSystemVersion
;
665 PLOADER_PARAMETER_BLOCK LoaderBlock
;
666 CHAR BootPath
[MAX_PATH
];
667 CHAR FileName
[MAX_PATH
];
668 CHAR BootOptions
[256];
670 /* Retrieve the (mandatory) boot type */
671 ArgValue
= GetArgumentValue(Argc
, Argv
, "BootType");
672 if (!ArgValue
|| !*ArgValue
)
674 ERR("No 'BootType' value, aborting!\n");
678 /* Convert it to an OS version */
679 if (_stricmp(ArgValue
, "Windows") == 0 ||
680 _stricmp(ArgValue
, "Windows2003") == 0)
682 OperatingSystemVersion
= _WIN32_WINNT_WS03
;
684 else if (_stricmp(ArgValue
, "WindowsNT40") == 0)
686 OperatingSystemVersion
= _WIN32_WINNT_NT4
;
690 ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue
);
694 /* Retrieve the (mandatory) system partition */
695 SystemPartition
= GetArgumentValue(Argc
, Argv
, "SystemPartition");
696 if (!SystemPartition
|| !*SystemPartition
)
698 ERR("No 'SystemPartition' specified, aborting!\n");
703 UiDrawProgressBarCenter(1, 100, "Loading NT...");
705 /* Retrieve the system path */
706 *BootPath
= ANSI_NULL
;
707 ArgValue
= GetArgumentValue(Argc
, Argv
, "SystemPath");
709 RtlStringCbCopyA(BootPath
, sizeof(BootPath
), ArgValue
);
712 * Check whether BootPath is a full path
713 * and if not, create a full boot path.
715 * See FsOpenFile for the technique used.
717 if (strrchr(BootPath
, ')') == NULL
)
719 /* Temporarily save the boot path */
720 RtlStringCbCopyA(FileName
, sizeof(FileName
), BootPath
);
722 /* This is not a full path: prepend the SystemPartition */
723 RtlStringCbCopyA(BootPath
, sizeof(BootPath
), SystemPartition
);
725 /* Append a path separator if needed */
726 if (*FileName
!= '\\' && *FileName
!= '/')
727 RtlStringCbCatA(BootPath
, sizeof(BootPath
), "\\");
729 /* Append the remaining path */
730 RtlStringCbCatA(BootPath
, sizeof(BootPath
), FileName
);
733 /* Append a path separator if needed */
734 if (!*BootPath
|| BootPath
[strlen(BootPath
) - 1] != '\\')
735 RtlStringCbCatA(BootPath
, sizeof(BootPath
), "\\");
737 TRACE("BootPath: '%s'\n", BootPath
);
739 /* Retrieve the boot options */
740 *BootOptions
= ANSI_NULL
;
741 ArgValue
= GetArgumentValue(Argc
, Argv
, "Options");
742 if (ArgValue
&& *ArgValue
)
743 RtlStringCbCopyA(BootOptions
, sizeof(BootOptions
), ArgValue
);
745 /* Append boot-time options */
746 AppendBootTimeOptions(BootOptions
);
749 * Set "/HAL=" and "/KERNEL=" options if needed.
750 * If already present on the standard "Options=" option line, they take
751 * precedence over those passed via the separate "Hal=" and "Kernel="
754 if (strstr(BootOptions
, "/HAL=") != 0)
757 * Not found in the options, try to retrieve the
758 * separate value and append it to the options.
760 ArgValue
= GetArgumentValue(Argc
, Argv
, "Hal");
761 if (ArgValue
&& *ArgValue
)
763 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), " /HAL=");
764 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), ArgValue
);
767 if (strstr(BootOptions
, "/KERNEL=") != 0)
770 * Not found in the options, try to retrieve the
771 * separate value and append it to the options.
773 ArgValue
= GetArgumentValue(Argc
, Argv
, "Kernel");
774 if (ArgValue
&& *ArgValue
)
776 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), " /KERNEL=");
777 RtlStringCbCatA(BootOptions
, sizeof(BootOptions
), ArgValue
);
781 TRACE("BootOptions: '%s'\n", BootOptions
);
783 /* Check if a ramdisk file was given */
784 File
= strstr(BootOptions
, "/RDPATH=");
787 /* Copy the file name and everything else after it */
788 RtlStringCbCopyA(FileName
, sizeof(FileName
), File
+ 8);
791 *strstr(FileName
, " ") = ANSI_NULL
;
793 /* Load the ramdisk */
794 Status
= RamDiskLoadVirtualFile(FileName
, SystemPartition
);
795 if (Status
!= ESUCCESS
)
797 UiMessageBox("Failed to load RAM disk file %s", FileName
);
802 /* Let user know we started loading */
803 //UiDrawStatusText("Loading...");
805 /* Allocate and minimalist-initialize LPB */
806 AllocateAndInitLPB(&LoaderBlock
);
808 /* Load the system hive */
810 UiDrawProgressBarCenter(15, 100, "Loading system hive...");
811 Success
= WinLdrInitSystemHive(LoaderBlock
, BootPath
, FALSE
);
812 TRACE("SYSTEM hive %s\n", (Success
? "loaded" : "not loaded"));
813 /* Bail out if failure */
817 /* Load NLS data, OEM font, and prepare boot drivers list */
818 Success
= WinLdrScanSystemHive(LoaderBlock
, BootPath
);
819 TRACE("SYSTEM hive %s\n", (Success
? "scanned" : "not scanned"));
820 /* Bail out if failure */
825 return LoadAndBootWindowsCommon(OperatingSystemVersion
,
833 LoadAndBootWindowsCommon(
834 USHORT OperatingSystemVersion
,
835 PLOADER_PARAMETER_BLOCK LoaderBlock
,
840 PLOADER_PARAMETER_BLOCK LoaderBlockVA
;
842 PLDR_DATA_TABLE_ENTRY KernelDTE
;
843 KERNEL_ENTRY_POINT KiSystemStartup
;
846 TRACE("LoadAndBootWindowsCommon()\n");
849 /* Setup redirection support */
850 WinLdrSetupEms((PCHAR
)BootOptions
);
853 /* Convert BootPath to SystemRoot */
854 SystemRoot
= strstr(BootPath
, "\\");
856 /* Detect hardware */
858 UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
859 LoaderBlock
->ConfigurationRoot
= MachHwDetect();
861 if (OperatingSystemVersion
== 0)
862 OperatingSystemVersion
= WinLdrDetectVersion();
864 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
865 Success
= LoadWindowsCore(OperatingSystemVersion
,
872 UiMessageBox("Error loading NTOS core.");
876 /* Load boot drivers */
878 UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
879 Success
= WinLdrLoadBootDrivers(LoaderBlock
, BootPath
);
880 TRACE("Boot drivers loading %s\n", Success
? "successful" : "failed");
882 /* Cleanup ini file */
885 /* Initialize Phase 1 - no drivers loading anymore */
886 WinLdrInitializePhase1(LoaderBlock
,
890 OperatingSystemVersion
);
892 /* Save entry-point pointer and Loader block VAs */
893 KiSystemStartup
= (KERNEL_ENTRY_POINT
)KernelDTE
->EntryPoint
;
894 LoaderBlockVA
= PaToVa(LoaderBlock
);
896 /* "Stop all motors", change videomode */
897 MachPrepareForReactOS();
900 //DumpMemoryAllocMap();
902 /* Do the machine specific initialization */
903 WinLdrSetupMachineDependent(LoaderBlock
);
905 /* Map pages and create memory descriptors */
906 WinLdrSetupMemoryLayout(LoaderBlock
);
908 /* Set processor context */
909 WinLdrSetProcessorContext();
911 /* Save final value of LoaderPagesSpanned */
912 LoaderBlock
->Extension
->LoaderPagesSpanned
= LoaderPagesSpanned
;
914 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
915 KiSystemStartup
, LoaderBlockVA
);
917 // Zero KI_USER_SHARED_DATA page
918 memset((PVOID
)KI_USER_SHARED_DATA
, 0, MM_PAGE_SIZE
);
920 WinLdrpDumpMemoryDescriptors(LoaderBlockVA
);
921 WinLdrpDumpBootDriver(LoaderBlockVA
);
923 WinLdrpDumpArcDisks(LoaderBlockVA
);
927 (*KiSystemStartup
)(LoaderBlockVA
);
932 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock
)
935 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
;
937 NextMd
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
939 while (NextMd
!= &LoaderBlock
->MemoryDescriptorListHead
)
941 MemoryDescriptor
= CONTAINING_RECORD(NextMd
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
943 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor
->BasePage
,
944 MemoryDescriptor
->PageCount
, MemoryDescriptor
->MemoryType
);
946 NextMd
= MemoryDescriptor
->ListEntry
.Flink
;
951 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock
)
954 PBOOT_DRIVER_LIST_ENTRY BootDriver
;
956 NextBd
= LoaderBlock
->BootDriverListHead
.Flink
;
958 while (NextBd
!= &LoaderBlock
->BootDriverListHead
)
960 BootDriver
= CONTAINING_RECORD(NextBd
, BOOT_DRIVER_LIST_ENTRY
, Link
);
962 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver
->FilePath
,
963 BootDriver
->LdrEntry
, &BootDriver
->RegistryPath
);
965 NextBd
= BootDriver
->Link
.Flink
;
970 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock
)
973 PARC_DISK_SIGNATURE ArcDisk
;
975 NextBd
= LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
.Flink
;
977 while (NextBd
!= &LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
)
979 ArcDisk
= CONTAINING_RECORD(NextBd
, ARC_DISK_SIGNATURE
, ListEntry
);
981 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
982 ArcDisk
->ArcName
, ArcDisk
->CheckSum
, ArcDisk
->Signature
);
984 NextBd
= ArcDisk
->ListEntry
.Flink
;