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