[FREELDR] Always change video mode back to text-mode before starting up ReactOS.
[reactos.git] / boot / freeldr / freeldr / ntldr / winldr.c
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();
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 }