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