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