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