98de7f299220c03ee35111880ea9c3bf2a989198
[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 return NULL;
373 }
374
375 /* Get this file's size */
376 Status = ArcGetFileInformation(FileId, &FileInfo);
377 if (Status != ESUCCESS)
378 {
379 ArcClose(FileId);
380 return NULL;
381 }
382 FileSize = FileInfo.EndingAddress.LowPart;
383 *Size = FileSize;
384
385 /* Allocate memory */
386 PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
387 if (PhysicalBase == NULL)
388 {
389 ArcClose(FileId);
390 return NULL;
391 }
392
393 /* Load whole file */
394 Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
395 ArcClose(FileId);
396 if (Status != ESUCCESS)
397 {
398 return NULL;
399 }
400
401 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
402
403 return PhysicalBase;
404 }
405
406 USHORT
407 WinLdrDetectVersion(VOID)
408 {
409 LONG rc;
410 HKEY hKey;
411
412 rc = RegOpenKey(
413 NULL,
414 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
415 &hKey);
416 if (rc != ERROR_SUCCESS)
417 {
418 // Key doesn't exist; assume NT 4.0
419 return _WIN32_WINNT_NT4;
420 }
421
422 // We may here want to read the value of ProductVersion
423 return _WIN32_WINNT_WS03;
424 }
425
426 static
427 BOOLEAN
428 LoadModule(
429 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
430 IN PCCH Path,
431 IN PCCH File,
432 IN PCCH ImportName, // BaseDllName
433 IN TYPE_OF_MEMORY MemoryType,
434 OUT PLDR_DATA_TABLE_ENTRY *Dte,
435 IN ULONG Percentage)
436 {
437 BOOLEAN Success;
438 CHAR FullFileName[MAX_PATH];
439 CHAR ProgressString[256];
440 PVOID BaseAddress = NULL;
441
442 UiDrawBackdrop();
443 RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
444 UiDrawProgressBarCenter(Percentage, 100, ProgressString);
445
446 RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
447 RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
448
449 Success = WinLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
450 if (!Success)
451 {
452 TRACE("Loading %s failed\n", File);
453 return FALSE;
454 }
455 TRACE("%s loaded successfully at %p\n", File, BaseAddress);
456
457 /*
458 * Cheat about the base DLL name if we are loading
459 * the Kernel Debugger Transport DLL, to make the
460 * PE loader happy.
461 */
462 Success = WinLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
463 ImportName,
464 FullFileName,
465 BaseAddress,
466 Dte);
467
468 return Success;
469 }
470
471 static
472 BOOLEAN
473 LoadWindowsCore(IN USHORT OperatingSystemVersion,
474 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
475 IN PCSTR BootOptions,
476 IN PCSTR BootPath,
477 IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
478 {
479 BOOLEAN Success;
480 PCSTR Options;
481 CHAR DirPath[MAX_PATH];
482 CHAR KernelFileName[MAX_PATH];
483 CHAR HalFileName[MAX_PATH];
484 CHAR KdTransportDllName[MAX_PATH];
485 PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
486
487 if (!KernelDTE) return FALSE;
488
489 /* Initialize SystemRoot\System32 path */
490 RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath);
491 RtlStringCbCatA(DirPath, sizeof(DirPath), "system32\\");
492
493 //
494 // TODO: Parse also the separate INI values "Kernel=" and "Hal="
495 //
496
497 /* Default KERNEL and HAL file names */
498 RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
499 RtlStringCbCopyA(HalFileName , sizeof(HalFileName) , "hal.dll");
500
501 /* Find any /KERNEL= or /HAL= switch in the boot options */
502 Options = BootOptions;
503 while (Options)
504 {
505 /* Skip possible initial whitespace */
506 Options += strspn(Options, " \t");
507
508 /* Check whether a new option starts and it is either KERNEL or HAL */
509 if (*Options != '/' || (++Options,
510 !(_strnicmp(Options, "KERNEL=", 7) == 0 ||
511 _strnicmp(Options, "HAL=", 4) == 0)) )
512 {
513 /* Search for another whitespace */
514 Options = strpbrk(Options, " \t");
515 continue;
516 }
517 else
518 {
519 size_t i = strcspn(Options, " \t"); /* Skip whitespace */
520 if (i == 0)
521 {
522 /* Use the default values */
523 break;
524 }
525
526 /* We have found either KERNEL or HAL options */
527 if (_strnicmp(Options, "KERNEL=", 7) == 0)
528 {
529 Options += 7; i -= 7;
530 RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Options, i);
531 _strupr(KernelFileName);
532 }
533 else if (_strnicmp(Options, "HAL=", 4) == 0)
534 {
535 Options += 4; i -= 4;
536 RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Options, i);
537 _strupr(HalFileName);
538 }
539 }
540 }
541
542 TRACE("Kernel file = '%s' ; HAL file = '%s'\n", KernelFileName, HalFileName);
543
544 /* Load the Kernel */
545 LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
546
547 /* Load the HAL */
548 LoadModule(LoaderBlock, DirPath, HalFileName, "hal.dll", LoaderHalCode, &HalDTE, 45);
549
550 /* Load the Kernel Debugger Transport DLL */
551 if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
552 {
553 /*
554 * According to http://www.nynaeve.net/?p=173 :
555 * "[...] Another enhancement that could be done Microsoft-side would be
556 * a better interface for replacing KD transport modules. Right now, due
557 * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
558 * has a hardcoded hack that interprets the KD type in the OS loader options,
559 * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
560 * "kdusb2.dll" modules, and inserts them into the loaded module list under
561 * the name "kdcom.dll". [...]"
562 */
563
564 /*
565 * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
566 * Indeed I want it to be case-insensitive to allow "debugport="
567 * or "DeBuGpOrT=" or... , and I don't want it to match malformed
568 * command-line options, such as:
569 *
570 * "...foo DEBUGPORT=xxx bar..."
571 * "...foo/DEBUGPORT=xxx bar..."
572 * "...foo/DEBUGPORT=bar..."
573 *
574 * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
575 * from the rest by whitespace, unless it begins the command-line, e.g.:
576 *
577 * "/DEBUGPORT=COM1 foo...bar..."
578 * "...foo /DEBUGPORT=USB bar..."
579 * or:
580 * "...foo /DEBUGPORT= bar..."
581 * (in that case, we default the port to COM).
582 */
583 Options = BootOptions;
584 while (Options)
585 {
586 /* Skip possible initial whitespace */
587 Options += strspn(Options, " \t");
588
589 /* Check whether a new option starts and it is the DEBUGPORT one */
590 if (*Options != '/' || _strnicmp(++Options, "DEBUGPORT=", 10) != 0)
591 {
592 /* Search for another whitespace */
593 Options = strpbrk(Options, " \t");
594 continue;
595 }
596 else
597 {
598 /* We found the DEBUGPORT option. Move to the port name. */
599 Options += 10;
600 break;
601 }
602 }
603
604 if (Options)
605 {
606 /*
607 * We have found the DEBUGPORT option. Parse the port name.
608 * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
609 * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
610 */
611 RtlStringCbCopyA(KdTransportDllName, sizeof(KdTransportDllName), "KD");
612 if (_strnicmp(Options, "COM", 3) == 0 && '0' <= Options[3] && Options[3] <= '9')
613 {
614 RtlStringCbCatNA(KdTransportDllName, sizeof(KdTransportDllName), Options, 3);
615 }
616 else
617 {
618 size_t i = strcspn(Options, " \t:"); /* Skip valid separators: whitespace or colon */
619 if (i == 0)
620 RtlStringCbCatA(KdTransportDllName, sizeof(KdTransportDllName), "COM");
621 else
622 RtlStringCbCatNA(KdTransportDllName, sizeof(KdTransportDllName), Options, i);
623 }
624 RtlStringCbCatA(KdTransportDllName, sizeof(KdTransportDllName), ".DLL");
625 _strupr(KdTransportDllName);
626
627 /*
628 * Load the transport DLL. Override the base DLL name of the
629 * loaded transport DLL to the default "KDCOM.DLL" name.
630 */
631 LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60);
632 }
633 }
634
635 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
636 Success = WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
637 Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
638 if (KdComDTE)
639 {
640 Success &= WinLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
641 }
642
643 return Success;
644 }
645
646 ARC_STATUS
647 LoadAndBootWindows(
648 IN ULONG Argc,
649 IN PCHAR Argv[],
650 IN PCHAR Envp[])
651 {
652 PCSTR ArgValue;
653 PCHAR File;
654 BOOLEAN Success;
655 USHORT OperatingSystemVersion;
656 PLOADER_PARAMETER_BLOCK LoaderBlock;
657 CHAR BootPath[MAX_PATH];
658 CHAR FileName[MAX_PATH];
659 CHAR BootOptions[256];
660
661 ArgValue = GetArgumentValue(Argc, Argv, "BootType");
662 if (!ArgValue)
663 {
664 ERR("No 'BootType' value, aborting!\n");
665 return EINVAL;
666 }
667
668 if (_stricmp(ArgValue, "Windows") == 0 ||
669 _stricmp(ArgValue, "Windows2003") == 0)
670 {
671 OperatingSystemVersion = _WIN32_WINNT_WS03;
672 }
673 else if (_stricmp(ArgValue, "WindowsNT40") == 0)
674 {
675 OperatingSystemVersion = _WIN32_WINNT_NT4;
676 }
677 else
678 {
679 ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
680 return EINVAL;
681 }
682
683 UiDrawBackdrop();
684 UiDrawProgressBarCenter(1, 100, "Loading NT...");
685
686 /* Retrieve the system path */
687 *BootPath = ANSI_NULL;
688 ArgValue = GetArgumentValue(Argc, Argv, "SystemPath");
689 if (ArgValue)
690 RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
691
692 /*
693 * Check whether BootPath is a full path
694 * and if not, create a full boot path.
695 *
696 * See FsOpenFile for the technique used.
697 */
698 if (strrchr(BootPath, ')') == NULL)
699 {
700 /* Temporarily save the boot path */
701 RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
702
703 /* This is not a full path. Use the current (i.e. boot) device. */
704 MachDiskGetBootPath(BootPath, sizeof(BootPath));
705
706 /* Append a path separator if needed */
707 if (*FileName != '\\' && *FileName != '/')
708 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
709
710 /* Append the remaining path */
711 RtlStringCbCatA(BootPath, sizeof(BootPath), FileName);
712 }
713
714 /* Append a backslash if needed */
715 if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
716 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
717
718 TRACE("BootPath: '%s'\n", BootPath);
719
720 /* Retrieve the boot options */
721 *BootOptions = ANSI_NULL;
722 ArgValue = GetArgumentValue(Argc, Argv, "Options");
723 if (ArgValue)
724 RtlStringCbCopyA(BootOptions, sizeof(BootOptions), ArgValue);
725
726 /* Append boot-time options */
727 AppendBootTimeOptions(BootOptions);
728
729 TRACE("BootOptions: '%s'\n", BootOptions);
730
731 /* Check if a ramdisk file was given */
732 File = strstr(BootOptions, "/RDPATH=");
733 if (File)
734 {
735 /* Copy the file name and everything else after it */
736 RtlStringCbCopyA(FileName, sizeof(FileName), File + 8);
737
738 /* Null-terminate */
739 *strstr(FileName, " ") = ANSI_NULL;
740
741 /* Load the ramdisk */
742 if (!RamDiskLoadVirtualFile(FileName))
743 {
744 UiMessageBox("Failed to load RAM disk file %s", FileName);
745 return ENOENT;
746 }
747 }
748
749 /* Let user know we started loading */
750 //UiDrawStatusText("Loading...");
751
752 /* Allocate and minimalist-initialize LPB */
753 AllocateAndInitLPB(&LoaderBlock);
754
755 /* Load the system hive */
756 UiDrawBackdrop();
757 UiDrawProgressBarCenter(15, 100, "Loading system hive...");
758 Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
759 TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
760 /* Bail out if failure */
761 if (!Success)
762 return ENOEXEC;
763
764 /* Load NLS data, OEM font, and prepare boot drivers list */
765 Success = WinLdrScanSystemHive(LoaderBlock, BootPath);
766 TRACE("SYSTEM hive %s\n", (Success ? "scanned" : "not scanned"));
767 /* Bail out if failure */
768 if (!Success)
769 return ENOEXEC;
770
771 /* Finish loading */
772 return LoadAndBootWindowsCommon(OperatingSystemVersion,
773 LoaderBlock,
774 BootOptions,
775 BootPath,
776 FALSE);
777 }
778
779 ARC_STATUS
780 LoadAndBootWindowsCommon(
781 USHORT OperatingSystemVersion,
782 PLOADER_PARAMETER_BLOCK LoaderBlock,
783 LPCSTR BootOptions,
784 LPCSTR BootPath,
785 BOOLEAN Setup)
786 {
787 PLOADER_PARAMETER_BLOCK LoaderBlockVA;
788 BOOLEAN Success;
789 PLDR_DATA_TABLE_ENTRY KernelDTE;
790 KERNEL_ENTRY_POINT KiSystemStartup;
791 LPCSTR SystemRoot;
792
793 TRACE("LoadAndBootWindowsCommon()\n");
794
795 #ifdef _M_IX86
796 /* Setup redirection support */
797 WinLdrSetupEms((PCHAR)BootOptions);
798 #endif
799
800 /* Convert BootPath to SystemRoot */
801 SystemRoot = strstr(BootPath, "\\");
802
803 /* Detect hardware */
804 UiDrawBackdrop();
805 UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
806 LoaderBlock->ConfigurationRoot = MachHwDetect();
807
808 if (OperatingSystemVersion == 0)
809 OperatingSystemVersion = WinLdrDetectVersion();
810
811 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
812 Success = LoadWindowsCore(OperatingSystemVersion,
813 LoaderBlock,
814 BootOptions,
815 BootPath,
816 &KernelDTE);
817 if (!Success)
818 {
819 UiMessageBox("Error loading NTOS core.");
820 return ENOEXEC;
821 }
822
823 /* Load boot drivers */
824 UiDrawBackdrop();
825 UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
826 Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
827 TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
828
829 /* Cleanup ini file */
830 IniCleanup();
831
832 /* Initialize Phase 1 - no drivers loading anymore */
833 WinLdrInitializePhase1(LoaderBlock,
834 BootOptions,
835 SystemRoot,
836 BootPath,
837 OperatingSystemVersion);
838
839 /* Save entry-point pointer and Loader block VAs */
840 KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
841 LoaderBlockVA = PaToVa(LoaderBlock);
842
843 /* "Stop all motors", change videomode */
844 MachPrepareForReactOS();
845
846 /* Debugging... */
847 //DumpMemoryAllocMap();
848
849 /* Do the machine specific initialization */
850 WinLdrSetupMachineDependent(LoaderBlock);
851
852 /* Map pages and create memory descriptors */
853 WinLdrSetupMemoryLayout(LoaderBlock);
854
855 /* Set processor context */
856 WinLdrSetProcessorContext();
857
858 /* Save final value of LoaderPagesSpanned */
859 LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
860
861 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
862 KiSystemStartup, LoaderBlockVA);
863
864 // Zero KI_USER_SHARED_DATA page
865 memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
866
867 WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
868 WinLdrpDumpBootDriver(LoaderBlockVA);
869 #ifndef _M_AMD64
870 WinLdrpDumpArcDisks(LoaderBlockVA);
871 #endif
872
873 /* Pass control */
874 (*KiSystemStartup)(LoaderBlockVA);
875 return ESUCCESS;
876 }
877
878 VOID
879 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
880 {
881 PLIST_ENTRY NextMd;
882 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
883
884 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
885
886 while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
887 {
888 MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
889
890 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
891 MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
892
893 NextMd = MemoryDescriptor->ListEntry.Flink;
894 }
895 }
896
897 VOID
898 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
899 {
900 PLIST_ENTRY NextBd;
901 PBOOT_DRIVER_LIST_ENTRY BootDriver;
902
903 NextBd = LoaderBlock->BootDriverListHead.Flink;
904
905 while (NextBd != &LoaderBlock->BootDriverListHead)
906 {
907 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
908
909 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
910 BootDriver->LdrEntry, &BootDriver->RegistryPath);
911
912 NextBd = BootDriver->Link.Flink;
913 }
914 }
915
916 VOID
917 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
918 {
919 PLIST_ENTRY NextBd;
920 PARC_DISK_SIGNATURE ArcDisk;
921
922 NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
923
924 while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
925 {
926 ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
927
928 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
929 ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
930
931 NextBd = ArcDisk->ListEntry.Flink;
932 }
933 }