1 /* 2 * FreeLoader 3 * 4 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 5 * Copyright (C) 2006 Aleksey Bragin <aleksey@reactos.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 22 #include <freeldr.h> 23 #include "winldr.h" 24 #include "registry.h" 25 26 #include <ndk/ldrtypes.h> 27 28 #include <debug.h> 29 DBG_DEFAULT_CHANNEL(WINDOWS); 30 31 // FIXME: Find a better way to retrieve ARC disk information 32 extern ULONG reactos_disk_count; 33 extern ARC_DISK_SIGNATURE_EX reactos_arc_disk_info[]; 34 35 extern ULONG LoaderPagesSpanned; 36 extern BOOLEAN AcpiPresent; 37 38 extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation; 39 extern BOOLEAN WinLdrTerminalConnected; 40 extern void WinLdrSetupEms(IN PCHAR BootOptions); 41 42 PLOADER_SYSTEM_BLOCK WinLdrSystemBlock; 43 44 // debug stuff 45 VOID DumpMemoryAllocMap(VOID); 46 47 // Init "phase 0" 48 VOID 49 AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock) 50 { 51 PLOADER_PARAMETER_BLOCK LoaderBlock; 52 53 /* Allocate and zero-init the LPB */ 54 WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK), 55 LoaderSystemBlock); 56 if (WinLdrSystemBlock == NULL) 57 { 58 UiMessageBox("Failed to allocate memory for system block!"); 59 return; 60 } 61 62 RtlZeroMemory(WinLdrSystemBlock, sizeof(LOADER_SYSTEM_BLOCK)); 63 64 LoaderBlock = &WinLdrSystemBlock->LoaderBlock; 65 LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock; 66 67 /* Init three critical lists, used right away */ 68 InitializeListHead(&LoaderBlock->LoadOrderListHead); 69 InitializeListHead(&LoaderBlock->MemoryDescriptorListHead); 70 InitializeListHead(&LoaderBlock->BootDriverListHead); 71 72 *OutLoaderBlock = LoaderBlock; 73 } 74 75 // Init "phase 1" 76 VOID 77 WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, 78 LPCSTR Options, 79 LPCSTR SystemRoot, 80 LPCSTR BootPath, 81 USHORT VersionToBoot) 82 { 83 /* Examples of correct options and paths */ 84 //CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200"; 85 //CHAR Options[] = "/NODEBUG"; 86 //CHAR SystemRoot[] = "\\WINNT\\"; 87 //CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)"; 88 89 LPSTR LoadOptions, NewLoadOptions; 90 CHAR HalPath[] = "\\"; 91 CHAR ArcBoot[256]; 92 CHAR MiscFiles[256]; 93 ULONG i; 94 ULONG_PTR PathSeparator; 95 PLOADER_PARAMETER_EXTENSION Extension; 96 97 /* Construct SystemRoot and ArcBoot from SystemPath */ 98 PathSeparator = strstr(BootPath, "\\") - BootPath; 99 strncpy(ArcBoot, BootPath, PathSeparator); 100 ArcBoot[PathSeparator] = ANSI_NULL; 101 102 TRACE("ArcBoot: %s\n", ArcBoot); 103 TRACE("SystemRoot: %s\n", SystemRoot); 104 TRACE("Options: %s\n", Options); 105 106 /* Fill Arc BootDevice */ 107 LoaderBlock->ArcBootDeviceName = WinLdrSystemBlock->ArcBootDeviceName; 108 strncpy(LoaderBlock->ArcBootDeviceName, ArcBoot, MAX_PATH); 109 LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName); 110 111 /* Fill Arc HalDevice, it matches ArcBoot path */ 112 LoaderBlock->ArcHalDeviceName = WinLdrSystemBlock->ArcBootDeviceName; 113 LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName); 114 115 /* Fill SystemRoot */ 116 LoaderBlock->NtBootPathName = WinLdrSystemBlock->NtBootPathName; 117 strncpy(LoaderBlock->NtBootPathName, SystemRoot, MAX_PATH); 118 LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName); 119 120 /* Fill NtHalPathName */ 121 LoaderBlock->NtHalPathName = WinLdrSystemBlock->NtHalPathName; 122 strncpy(LoaderBlock->NtHalPathName, HalPath, MAX_PATH); 123 LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName); 124 125 /* Fill LoadOptions and strip the '/' commutator symbol in front of each option */ 126 NewLoadOptions = LoadOptions = LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions; 127 strncpy(LoaderBlock->LoadOptions, Options, MAX_OPTIONS_LENGTH); 128 129 do 130 { 131 while (*LoadOptions == '/') 132 ++LoadOptions; 133 134 *NewLoadOptions++ = *LoadOptions; 135 } while (*LoadOptions++); 136 137 LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions); 138 139 /* Arc devices */ 140 LoaderBlock->ArcDiskInformation = &WinLdrSystemBlock->ArcDiskInformation; 141 InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); 142 143 /* Convert ARC disk information from freeldr to a correct format */ 144 for (i = 0; i < reactos_disk_count; i++) 145 { 146 PARC_DISK_SIGNATURE_EX ArcDiskSig; 147 148 /* Allocate the ARC structure */ 149 ArcDiskSig = FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX), 'giSD'); 150 151 /* Copy the data over */ 152 RtlCopyMemory(ArcDiskSig, &reactos_arc_disk_info[i], sizeof(ARC_DISK_SIGNATURE_EX)); 153 154 /* Set the ARC Name pointer */ 155 ArcDiskSig->DiskSignature.ArcName = PaToVa(ArcDiskSig->ArcName); 156 157 /* Insert into the list */ 158 InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead, 159 &ArcDiskSig->DiskSignature.ListEntry); 160 } 161 162 /* Convert all list's to Virtual address */ 163 164 /* Convert the ArcDisks list to virtual address */ 165 List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); 166 LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation); 167 168 /* Convert configuration entries to VA */ 169 ConvertConfigToVA(LoaderBlock->ConfigurationRoot); 170 LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot); 171 172 /* Convert all DTE into virtual addresses */ 173 List_PaToVa(&LoaderBlock->LoadOrderListHead); 174 175 /* This one will be converted right before switching to virtual paging mode */ 176 //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead); 177 178 /* Convert list of boot drivers */ 179 List_PaToVa(&LoaderBlock->BootDriverListHead); 180 181 /* Initialize Extension now */ 182 Extension = &WinLdrSystemBlock->Extension; 183 Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION); 184 Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8; 185 Extension->MinorVersion = VersionToBoot & 0xFF; 186 Extension->Profile.Status = 2; 187 188 /* Check if FreeLdr detected a ACPI table */ 189 if (AcpiPresent) 190 { 191 /* Set the pointer to something for compatibility */ 192 Extension->AcpiTable = (PVOID)1; 193 // FIXME: Extension->AcpiTableSize; 194 } 195 196 #ifdef _M_IX86 197 /* Set headless block pointer */ 198 if (WinLdrTerminalConnected) 199 { 200 Extension->HeadlessLoaderBlock = &WinLdrSystemBlock->HeadlessLoaderBlock; 201 RtlCopyMemory(Extension->HeadlessLoaderBlock, 202 &LoaderRedirectionInformation, 203 sizeof(HEADLESS_LOADER_BLOCK)); 204 Extension->HeadlessLoaderBlock = PaToVa(Extension->HeadlessLoaderBlock); 205 } 206 #endif 207 /* Load drivers database */ 208 strcpy(MiscFiles, BootPath); 209 strcat(MiscFiles, "AppPatch\\drvmain.sdb"); 210 Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles, 211 &Extension->DrvDBSize, 212 LoaderRegistryData)); 213 214 /* Convert extension and setup block pointers */ 215 LoaderBlock->Extension = PaToVa(Extension); 216 217 if (LoaderBlock->SetupLdrBlock) 218 LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock); 219 220 TRACE("WinLdrInitializePhase1() completed\n"); 221 } 222 223 static BOOLEAN 224 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead, 225 LPCSTR BootPath, 226 PUNICODE_STRING FilePath, 227 ULONG Flags, 228 PLDR_DATA_TABLE_ENTRY *DriverDTE) 229 { 230 CHAR FullPath[1024]; 231 CHAR DriverPath[1024]; 232 CHAR DllName[1024]; 233 PCHAR DriverNamePos; 234 BOOLEAN Success; 235 PVOID DriverBase = NULL; 236 237 // Separate the path to file name and directory path 238 _snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath); 239 DriverNamePos = strrchr(DriverPath, '\\'); 240 if (DriverNamePos != NULL) 241 { 242 // Copy the name 243 strcpy(DllName, DriverNamePos+1); 244 245 // Cut out the name from the path 246 *(DriverNamePos+1) = 0; 247 } 248 else 249 { 250 // There is no directory in the path 251 strcpy(DllName, DriverPath); 252 DriverPath[0] = ANSI_NULL; 253 } 254 255 TRACE("DriverPath: %s, DllName: %s, LPB\n", DriverPath, DllName); 256 257 // Check if driver is already loaded 258 Success = WinLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE); 259 if (Success) 260 { 261 // We've got the pointer to its DTE, just return success 262 return TRUE; 263 } 264 265 // It's not loaded, we have to load it 266 _snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath); 267 Success = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); 268 if (!Success) 269 return FALSE; 270 271 // Allocate a DTE for it 272 Success = WinLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE); 273 if (!Success) 274 { 275 ERR("WinLdrAllocateDataTableEntry() failed\n"); 276 return FALSE; 277 } 278 279 // Modify any flags, if needed 280 (*DriverDTE)->Flags |= Flags; 281 282 // Look for any dependencies it may have, and load them too 283 sprintf(FullPath,"%s%s", BootPath, DriverPath); 284 Success = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE); 285 if (!Success) 286 { 287 ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath); 288 return FALSE; 289 } 290 291 return TRUE; 292 } 293 294 BOOLEAN 295 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock, 296 LPCSTR BootPath) 297 { 298 PLIST_ENTRY NextBd; 299 PBOOT_DRIVER_LIST_ENTRY BootDriver; 300 BOOLEAN Success; 301 BOOLEAN ret = TRUE; 302 303 // Walk through the boot drivers list 304 NextBd = LoaderBlock->BootDriverListHead.Flink; 305 306 while (NextBd != &LoaderBlock->BootDriverListHead) 307 { 308 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link); 309 310 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, 311 BootDriver->LdrEntry, &BootDriver->RegistryPath); 312 313 // Paths are relative (FIXME: Are they always relative?) 314 315 // Load it 316 Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead, 317 BootPath, 318 &BootDriver->FilePath, 319 0, 320 &BootDriver->LdrEntry); 321 322 if (Success) 323 { 324 // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore 325 BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer); 326 BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer); 327 BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry); 328 } 329 else 330 { 331 // Loading failed - cry loudly 332 ERR("Can't load boot driver '%wZ'!\n", &BootDriver->FilePath); 333 UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver->FilePath); 334 ret = FALSE; 335 336 // Remove it from the list and try to continue 337 RemoveEntryList(NextBd); 338 } 339 340 NextBd = BootDriver->Link.Flink; 341 } 342 343 return ret; 344 } 345 346 PVOID 347 WinLdrLoadModule(PCSTR ModuleName, 348 ULONG *Size, 349 TYPE_OF_MEMORY MemoryType) 350 { 351 ULONG FileId; 352 PVOID PhysicalBase; 353 FILEINFORMATION FileInfo; 354 ULONG FileSize; 355 ARC_STATUS Status; 356 ULONG BytesRead; 357 358 //CHAR ProgressString[256]; 359 360 /* Inform user we are loading files */ 361 //UiDrawBackdrop(); 362 //sprintf(ProgressString, "Loading %s...", FileName); 363 //UiDrawProgressBarCenter(1, 100, ProgressString); 364 365 TRACE("Loading module %s\n", ModuleName); 366 *Size = 0; 367 368 /* Open the image file */ 369 Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId); 370 if (Status != ESUCCESS) 371 { 372 /* In case of errors, we just return, without complaining to the user */ 373 return NULL; 374 } 375 376 /* Get this file's size */ 377 Status = ArcGetFileInformation(FileId, &FileInfo); 378 if (Status != ESUCCESS) 379 { 380 ArcClose(FileId); 381 return NULL; 382 } 383 FileSize = FileInfo.EndingAddress.LowPart; 384 *Size = FileSize; 385 386 /* Allocate memory */ 387 PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType); 388 if (PhysicalBase == NULL) 389 { 390 ArcClose(FileId); 391 return NULL; 392 } 393 394 /* Load whole file */ 395 Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead); 396 ArcClose(FileId); 397 if (Status != ESUCCESS) 398 { 399 return NULL; 400 } 401 402 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize); 403 404 return PhysicalBase; 405 } 406 407 USHORT 408 WinLdrDetectVersion(VOID) 409 { 410 LONG rc; 411 HKEY hKey; 412 413 rc = RegOpenKey( 414 NULL, 415 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server", 416 &hKey); 417 if (rc != ERROR_SUCCESS) 418 { 419 // Key doesn't exist; assume NT 4.0 420 return _WIN32_WINNT_NT4; 421 } 422 423 // We may here want to read the value of ProductVersion 424 return _WIN32_WINNT_WS03; 425 } 426 427 static 428 BOOLEAN 429 LoadModule( 430 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, 431 IN PCCH Path, 432 IN PCCH File, 433 IN PCCH ImportName, // BaseDllName 434 IN TYPE_OF_MEMORY MemoryType, 435 OUT PLDR_DATA_TABLE_ENTRY *Dte, 436 IN ULONG Percentage) 437 { 438 BOOLEAN Success; 439 CHAR FullFileName[MAX_PATH]; 440 CHAR ProgressString[256]; 441 PVOID BaseAddress = NULL; 442 443 UiDrawBackdrop(); 444 sprintf(ProgressString, "Loading %s...", File); 445 UiDrawProgressBarCenter(Percentage, 100, ProgressString); 446 447 strcpy(FullFileName, Path); 448 strcat(FullFileName, File); 449 450 Success = WinLdrLoadImage(FullFileName, MemoryType, &BaseAddress); 451 if (!Success) 452 { 453 TRACE("Loading %s failed\n", File); 454 return FALSE; 455 } 456 TRACE("%s loaded successfully at %p\n", File, BaseAddress); 457 458 /* 459 * Cheat about the base DLL name if we are loading 460 * the Kernel Debugger Transport DLL, to make the 461 * PE loader happy. 462 */ 463 Success = WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead, 464 ImportName, 465 FullFileName, 466 BaseAddress, 467 Dte); 468 469 return Success; 470 } 471 472 static 473 BOOLEAN 474 LoadWindowsCore(IN USHORT OperatingSystemVersion, 475 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, 476 IN PCSTR BootOptions, 477 IN PCSTR BootPath, 478 IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE) 479 { 480 BOOLEAN Success; 481 PCSTR Options; 482 CHAR DirPath[MAX_PATH]; 483 CHAR KernelFileName[MAX_PATH]; 484 CHAR HalFileName[MAX_PATH]; 485 CHAR KdTransportDllName[MAX_PATH]; 486 PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL; 487 488 if (!KernelDTE) return FALSE; 489 490 /* Initialize SystemRoot\System32 path */ 491 strcpy(DirPath, BootPath); 492 strcat(DirPath, "system32\\"); 493 494 // 495 // TODO: Parse also the separate INI values "Kernel=" and "Hal=" 496 // 497 498 /* Default KERNEL and HAL file names */ 499 strcpy(KernelFileName, "ntoskrnl.exe"); 500 strcpy(HalFileName , "hal.dll"); 501 502 /* Find any /KERNEL= or /HAL= switch in the boot options */ 503 Options = BootOptions; 504 while (Options) 505 { 506 /* Skip possible initial whitespace */ 507 Options += strspn(Options, " \t"); 508 509 /* Check whether a new commutator starts and it is either KERNEL or HAL */ 510 if (*Options != '/' || (++Options, 511 !(_strnicmp(Options, "KERNEL=", 7) == 0 || 512 _strnicmp(Options, "HAL=", 4) == 0)) ) 513 { 514 /* Search for another whitespace */ 515 Options = strpbrk(Options, " \t"); 516 continue; 517 } 518 else 519 { 520 size_t i = strcspn(Options, " \t"); /* Skip whitespace */ 521 if (i == 0) 522 { 523 /* Use the default values */ 524 break; 525 } 526 527 /* We have found either KERNEL or HAL commutator */ 528 if (_strnicmp(Options, "KERNEL=", 7) == 0) 529 { 530 Options += 7; i -= 7; 531 strncpy(KernelFileName, Options, i); 532 KernelFileName[i] = ANSI_NULL; 533 _strupr(KernelFileName); 534 } 535 else if (_strnicmp(Options, "HAL=", 4) == 0) 536 { 537 Options += 4; i -= 4; 538 strncpy(HalFileName, Options, i); 539 HalFileName[i] = ANSI_NULL; 540 _strupr(HalFileName); 541 } 542 } 543 } 544 545 TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName); 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 /* 568 * This loop replaces a dumb call to strstr(..., "DEBUGPORT="). 569 * Indeed I want it to be case-insensitive to allow "debugport=" 570 * or "DeBuGpOrT=" or... , and I don't want it to match malformed 571 * command-line options, such as: 572 * 573 * "...foo DEBUGPORT=xxx bar..." 574 * "...foo/DEBUGPORT=xxx bar..." 575 * "...foo/DEBUGPORT=bar..." 576 * 577 * i.e. the "DEBUGPORT=" switch must start with a slash and be separated 578 * from the rest by whitespace, unless it begins the command-line, e.g.: 579 * 580 * "/DEBUGPORT=COM1 foo...bar..." 581 * "...foo /DEBUGPORT=USB bar..." 582 * or: 583 * "...foo /DEBUGPORT= bar..." 584 * (in that case, we default the port to COM). 585 */ 586 Options = BootOptions; 587 while (Options) 588 { 589 /* Skip possible initial whitespace */ 590 Options += strspn(Options, " \t"); 591 592 /* Check whether a new commutator starts and it is the DEBUGPORT one */ 593 if (*Options != '/' || _strnicmp(++Options, "DEBUGPORT=", 10) != 0) 594 { 595 /* Search for another whitespace */ 596 Options = strpbrk(Options, " \t"); 597 continue; 598 } 599 else 600 { 601 /* We found the DEBUGPORT commutator. Move to the port name. */ 602 Options += 10; 603 break; 604 } 605 } 606 607 if (Options) 608 { 609 /* 610 * We have found the DEBUGPORT commutator. Parse the port name. 611 * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO 612 * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM". 613 */ 614 strcpy(KdTransportDllName, "KD"); 615 if (_strnicmp(Options, "COM", 3) == 0 && '0' <= Options[3] && Options[3] <= '9') 616 { 617 strncat(KdTransportDllName, Options, 3); 618 } 619 else 620 { 621 size_t i = strcspn(Options, " \t:"); /* Skip valid separators: whitespace or colon */ 622 if (i == 0) 623 strcat(KdTransportDllName, "COM"); 624 else 625 strncat(KdTransportDllName, Options, i); 626 } 627 strcat(KdTransportDllName, ".DLL"); 628 _strupr(KdTransportDllName); 629 630 /* 631 * Load the transport DLL. Override the base DLL name of the 632 * loaded transport DLL to the default "KDCOM.DLL" name. 633 */ 634 LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60); 635 } 636 } 637 638 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */ 639 Success = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE); 640 Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE); 641 if (KdComDTE) 642 { 643 Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE); 644 } 645 646 return Success; 647 } 648 649 VOID 650 LoadAndBootWindows(IN OperatingSystemItem* OperatingSystem, 651 IN USHORT OperatingSystemVersion) 652 { 653 ULONG_PTR SectionId; 654 PCSTR SectionName = OperatingSystem->SystemPartition; 655 CHAR SettingsValue[80]; 656 BOOLEAN HasSection; 657 CHAR BootPath[MAX_PATH]; 658 CHAR FileName[MAX_PATH]; 659 CHAR BootOptions[256]; 660 PCHAR File; 661 BOOLEAN Success; 662 PLOADER_PARAMETER_BLOCK LoaderBlock; 663 664 /* Get OS setting value */ 665 SettingsValue[0] = ANSI_NULL; 666 IniOpenSection("Operating Systems", &SectionId); 667 IniReadSettingByName(SectionId, SectionName, SettingsValue, sizeof(SettingsValue)); 668 669 /* Open the operating system section specified in the .ini file */ 670 HasSection = IniOpenSection(SectionName, &SectionId); 671 672 UiDrawBackdrop(); 673 UiDrawProgressBarCenter(1, 100, "Loading NT..."); 674 675 /* Read the system path is set in the .ini file */ 676 if (!HasSection || 677 !IniReadSettingByName(SectionId, "SystemPath", BootPath, sizeof(BootPath))) 678 { 679 strcpy(BootPath, SectionName); 680 } 681 682 /* 683 * Check whether BootPath is a full path 684 * and if not, create a full boot path. 685 * 686 * See FsOpenFile for the technique used. 687 */ 688 if (strrchr(BootPath, ')') == NULL) 689 { 690 /* Temporarily save the boot path */ 691 strcpy(FileName, BootPath); 692 693 /* This is not a full path. Use the current (i.e. boot) device. */ 694 MachDiskGetBootPath(BootPath, sizeof(BootPath)); 695 696 /* Append a path separator if needed */ 697 if (FileName[0] != '\\' && FileName[0] != '/') 698 strcat(BootPath, "\\"); 699 700 /* Append the remaining path */ 701 strcat(BootPath, FileName); 702 } 703 704 /* Append a backslash if needed */ 705 if ((BootPath[0] == 0) || BootPath[strlen(BootPath) - 1] != '\\') 706 strcat(BootPath, "\\"); 707 708 /* Read booting options */ 709 if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions))) 710 { 711 /* Get options after the title */ 712 PCSTR p = SettingsValue; 713 while (*p == ' ' || *p == '"') 714 p++; 715 while (*p != '\0' && *p != '"') 716 p++; 717 strcpy(BootOptions, p); 718 TRACE("BootOptions: '%s'\n", BootOptions); 719 } 720 721 /* Append boot-time options */ 722 AppendBootTimeOptions(BootOptions); 723 724 /* Check if a ramdisk file was given */ 725 File = strstr(BootOptions, "/RDPATH="); 726 if (File) 727 { 728 /* Copy the file name and everything else after it */ 729 strcpy(FileName, File + 8); 730 731 /* Null-terminate */ 732 *strstr(FileName, " ") = ANSI_NULL; 733 734 /* Load the ramdisk */ 735 if (!RamDiskLoadVirtualFile(FileName)) 736 { 737 UiMessageBox("Failed to load RAM disk file %s", FileName); 738 return; 739 } 740 } 741 742 /* Let user know we started loading */ 743 //UiDrawStatusText("Loading..."); 744 745 TRACE("BootPath: '%s'\n", BootPath); 746 747 /* Allocate and minimalist-initialize LPB */ 748 AllocateAndInitLPB(&LoaderBlock); 749 750 /* Load the system hive */ 751 UiDrawBackdrop(); 752 UiDrawProgressBarCenter(15, 100, "Loading system hive..."); 753 Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE); 754 TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded")); 755 /* Bail out if failure */ 756 if (!Success) 757 return; 758 759 /* Load NLS data, OEM font, and prepare boot drivers list */ 760 Success = WinLdrScanSystemHive(LoaderBlock, BootPath); 761 TRACE("SYSTEM hive %s\n", (Success ? "scanned" : "not scanned")); 762 /* Bail out if failure */ 763 if (!Success) 764 return; 765 766 /* Finish loading */ 767 LoadAndBootWindowsCommon(OperatingSystemVersion, 768 LoaderBlock, 769 BootOptions, 770 BootPath, 771 FALSE); 772 } 773 774 VOID 775 LoadAndBootWindowsCommon( 776 USHORT OperatingSystemVersion, 777 PLOADER_PARAMETER_BLOCK LoaderBlock, 778 LPCSTR BootOptions, 779 LPCSTR BootPath, 780 BOOLEAN Setup) 781 { 782 PLOADER_PARAMETER_BLOCK LoaderBlockVA; 783 BOOLEAN Success; 784 PLDR_DATA_TABLE_ENTRY KernelDTE; 785 KERNEL_ENTRY_POINT KiSystemStartup; 786 LPCSTR SystemRoot; 787 TRACE("LoadAndBootWindowsCommon()\n"); 788 789 #ifdef _M_IX86 790 /* Setup redirection support */ 791 WinLdrSetupEms((PCHAR)BootOptions); 792 #endif 793 794 /* Convert BootPath to SystemRoot */ 795 SystemRoot = strstr(BootPath, "\\"); 796 797 /* Detect hardware */ 798 UiDrawBackdrop(); 799 UiDrawProgressBarCenter(20, 100, "Detecting hardware..."); 800 LoaderBlock->ConfigurationRoot = MachHwDetect(); 801 802 if (OperatingSystemVersion == 0) 803 OperatingSystemVersion = WinLdrDetectVersion(); 804 805 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */ 806 Success = LoadWindowsCore(OperatingSystemVersion, 807 LoaderBlock, 808 BootOptions, 809 BootPath, 810 &KernelDTE); 811 if (!Success) 812 { 813 UiMessageBox("Error loading NTOS core."); 814 return; 815 } 816 817 /* Load boot drivers */ 818 UiDrawBackdrop(); 819 UiDrawProgressBarCenter(100, 100, "Loading boot drivers..."); 820 Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath); 821 TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed"); 822 823 /* Initialize Phase 1 - no drivers loading anymore */ 824 WinLdrInitializePhase1(LoaderBlock, 825 BootOptions, 826 SystemRoot, 827 BootPath, 828 OperatingSystemVersion); 829 830 /* Save entry-point pointer and Loader block VAs */ 831 KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint; 832 LoaderBlockVA = PaToVa(LoaderBlock); 833 834 /* "Stop all motors", change videomode */ 835 MachPrepareForReactOS(Setup); 836 837 /* Cleanup ini file */ 838 IniCleanup(); 839 840 /* Debugging... */ 841 //DumpMemoryAllocMap(); 842 843 /* Do the machine specific initialization */ 844 WinLdrSetupMachineDependent(LoaderBlock); 845 846 /* Map pages and create memory descriptors */ 847 WinLdrSetupMemoryLayout(LoaderBlock); 848 849 /* Set processor context */ 850 WinLdrSetProcessorContext(); 851 852 /* Save final value of LoaderPagesSpanned */ 853 LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned; 854 855 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", 856 KiSystemStartup, LoaderBlockVA); 857 858 // Zero KI_USER_SHARED_DATA page 859 memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE); 860 861 WinLdrpDumpMemoryDescriptors(LoaderBlockVA); 862 WinLdrpDumpBootDriver(LoaderBlockVA); 863 #ifndef _M_AMD64 864 WinLdrpDumpArcDisks(LoaderBlockVA); 865 #endif 866 867 /* Pass control */ 868 (*KiSystemStartup)(LoaderBlockVA); 869 } 870 871 VOID 872 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock) 873 { 874 PLIST_ENTRY NextMd; 875 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; 876 877 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 878 879 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) 880 { 881 MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); 882 883 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage, 884 MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType); 885 886 NextMd = MemoryDescriptor->ListEntry.Flink; 887 } 888 } 889 890 VOID 891 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock) 892 { 893 PLIST_ENTRY NextBd; 894 PBOOT_DRIVER_LIST_ENTRY BootDriver; 895 896 NextBd = LoaderBlock->BootDriverListHead.Flink; 897 898 while (NextBd != &LoaderBlock->BootDriverListHead) 899 { 900 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link); 901 902 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, 903 BootDriver->LdrEntry, &BootDriver->RegistryPath); 904 905 NextBd = BootDriver->Link.Flink; 906 } 907 } 908 909 VOID 910 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock) 911 { 912 PLIST_ENTRY NextBd; 913 PARC_DISK_SIGNATURE ArcDisk; 914 915 NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink; 916 917 while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead) 918 { 919 ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry); 920 921 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n", 922 ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature); 923 924 NextBd = ArcDisk->ListEntry.Flink; 925 } 926 } 927