1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Windows-compatible NT OS Loader.
5 * COPYRIGHT: Copyright 2006-2019 Aleksey Bragin <aleksey@reactos.org>
6 */
7
8 #include <freeldr.h>
9 #include <ndk/ldrtypes.h>
10 #include "winldr.h"
11 #include "ntldropts.h"
12 #include "registry.h"
13 #include <internal/cmboot.h>
14
15 #include <debug.h>
16 DBG_DEFAULT_CHANNEL(WINDOWS);
17
18 // FIXME: Find a better way to retrieve ARC disk information
19 extern ULONG reactos_disk_count;
20 extern ARC_DISK_SIGNATURE_EX reactos_arc_disk_info[];
21
22 extern ULONG LoaderPagesSpanned;
23 extern BOOLEAN AcpiPresent;
24
25 extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
26 extern BOOLEAN WinLdrTerminalConnected;
27 extern VOID WinLdrSetupEms(IN PCSTR BootOptions);
28
29 PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
30 /**/PCWSTR BootFileSystem = NULL;/**/
31
32 BOOLEAN VirtualBias = FALSE;
33 BOOLEAN SosEnabled = FALSE;
34 BOOLEAN SafeBoot = FALSE;
35 BOOLEAN BootLogo = FALSE;
36 #ifdef _M_IX86
37 BOOLEAN PaeModeOn = FALSE;
38 #endif
39 BOOLEAN NoExecuteEnabled = FALSE;
40
41 // debug stuff
42 VOID DumpMemoryAllocMap(VOID);
43
44 /* PE loader import-DLL loading callback */
45 static VOID
46 NTAPI
NtLdrImportDllLoadCallback(_In_ PCSTR FileName)47 NtLdrImportDllLoadCallback(
48 _In_ PCSTR FileName)
49 {
50 NtLdrOutputLoadMsg(FileName, NULL);
51 }
52
53 VOID
NtLdrOutputLoadMsg(_In_ PCSTR FileName,_In_opt_ PCSTR Description)54 NtLdrOutputLoadMsg(
55 _In_ PCSTR FileName,
56 _In_opt_ PCSTR Description)
57 {
58 if (SosEnabled)
59 {
60 printf(" %s\n", FileName);
61 TRACE("Loading: %s\n", FileName);
62 }
63 else
64 {
65 /* Inform the user we load a file */
66 CHAR ProgressString[256];
67
68 RtlStringCbPrintfA(ProgressString, sizeof(ProgressString),
69 "Loading %s...",
70 (Description ? Description : FileName));
71 // UiSetProgressBarText(ProgressString);
72 // UiIndicateProgress();
73 UiDrawStatusText(ProgressString);
74 }
75 }
76
77 // Init "phase 0"
78 VOID
AllocateAndInitLPB(IN USHORT VersionToBoot,OUT PLOADER_PARAMETER_BLOCK * OutLoaderBlock)79 AllocateAndInitLPB(
80 IN USHORT VersionToBoot,
81 OUT PLOADER_PARAMETER_BLOCK* OutLoaderBlock)
82 {
83 PLOADER_PARAMETER_BLOCK LoaderBlock;
84 PLOADER_PARAMETER_EXTENSION Extension;
85
86 /* Allocate and zero-init the Loader Parameter Block */
87 WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK),
88 LoaderSystemBlock);
89 if (WinLdrSystemBlock == NULL)
90 {
91 UiMessageBox("Failed to allocate memory for system block!");
92 return;
93 }
94
95 RtlZeroMemory(WinLdrSystemBlock, sizeof(LOADER_SYSTEM_BLOCK));
96
97 LoaderBlock = &WinLdrSystemBlock->LoaderBlock;
98 LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock;
99
100 /* Initialize the Loader Block Extension */
101 Extension = &WinLdrSystemBlock->Extension;
102 LoaderBlock->Extension = Extension;
103 Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
104 Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
105 Extension->MinorVersion = (VersionToBoot & 0xFF);
106
107 /* Init three critical lists, used right away */
108 InitializeListHead(&LoaderBlock->LoadOrderListHead);
109 InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
110 InitializeListHead(&LoaderBlock->BootDriverListHead);
111
112 *OutLoaderBlock = LoaderBlock;
113 }
114
115 // Init "phase 1"
116 VOID
WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,PCSTR Options,PCSTR SystemRoot,PCSTR BootPath,USHORT VersionToBoot)117 WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
118 PCSTR Options,
119 PCSTR SystemRoot,
120 PCSTR BootPath,
121 USHORT VersionToBoot)
122 {
123 /*
124 * Examples of correct options and paths:
125 * CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
126 * CHAR Options[] = "/NODEBUG";
127 * CHAR SystemRoot[] = "\\WINNT\\";
128 * CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
129 */
130
131 PSTR LoadOptions, NewLoadOptions;
132 CHAR HalPath[] = "\\";
133 CHAR ArcBoot[MAX_PATH+1];
134 CHAR MiscFiles[MAX_PATH+1];
135 ULONG i;
136 ULONG_PTR PathSeparator;
137 PLOADER_PARAMETER_EXTENSION Extension;
138
139 /* Construct SystemRoot and ArcBoot from SystemPath */
140 PathSeparator = strstr(BootPath, "\\") - BootPath;
141 RtlStringCbCopyNA(ArcBoot, sizeof(ArcBoot), BootPath, PathSeparator);
142
143 TRACE("ArcBoot: '%s'\n", ArcBoot);
144 TRACE("SystemRoot: '%s'\n", SystemRoot);
145 TRACE("Options: '%s'\n", Options);
146
147 /* Fill ARC BootDevice */
148 LoaderBlock->ArcBootDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
149 RtlStringCbCopyA(LoaderBlock->ArcBootDeviceName, sizeof(WinLdrSystemBlock->ArcBootDeviceName), ArcBoot);
150 LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
151
152 //
153 // IMPROVE!!
154 // SetupBlock->ArcSetupDeviceName must be the path to the setup **SOURCE**,
155 // and not the setup boot path. Indeed they may differ!!
156 //
157 if (LoaderBlock->SetupLdrBlock)
158 {
159 PSETUP_LOADER_BLOCK SetupBlock = LoaderBlock->SetupLdrBlock;
160
161 /* Adjust the ARC path in the setup block - Matches ArcBoot path */
162 SetupBlock->ArcSetupDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
163 SetupBlock->ArcSetupDeviceName = PaToVa(SetupBlock->ArcSetupDeviceName);
164
165 /* Convert the setup block pointer */
166 LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
167 }
168
169 /* Fill ARC HalDevice, it matches ArcBoot path */
170 LoaderBlock->ArcHalDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
171 LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
172
173 /* Fill SystemRoot */
174 LoaderBlock->NtBootPathName = WinLdrSystemBlock->NtBootPathName;
175 RtlStringCbCopyA(LoaderBlock->NtBootPathName, sizeof(WinLdrSystemBlock->NtBootPathName), SystemRoot);
176 LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
177
178 /* Fill NtHalPathName */
179 LoaderBlock->NtHalPathName = WinLdrSystemBlock->NtHalPathName;
180 RtlStringCbCopyA(LoaderBlock->NtHalPathName, sizeof(WinLdrSystemBlock->NtHalPathName), HalPath);
181 LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
182
183 /* Fill LoadOptions and strip the '/' switch symbol in front of each option */
184 NewLoadOptions = LoadOptions = LoaderBlock->LoadOptions = WinLdrSystemBlock->LoadOptions;
185 RtlStringCbCopyA(LoaderBlock->LoadOptions, sizeof(WinLdrSystemBlock->LoadOptions), Options);
186
187 do
188 {
189 while (*LoadOptions == '/')
190 ++LoadOptions;
191
192 *NewLoadOptions++ = *LoadOptions;
193 } while (*LoadOptions++);
194
195 LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
196
197 /* ARC devices */
198 LoaderBlock->ArcDiskInformation = &WinLdrSystemBlock->ArcDiskInformation;
199 InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
200
201 /* Convert ARC disk information from freeldr to a correct format */
202 for (i = 0; i < reactos_disk_count; i++)
203 {
204 PARC_DISK_SIGNATURE_EX ArcDiskSig;
205
206 /* Allocate the ARC structure */
207 ArcDiskSig = FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX), 'giSD');
208 if (!ArcDiskSig)
209 {
210 ERR("Failed to allocate ARC structure! Ignoring remaining ARC disks. (i = %lu, DiskCount = %lu)\n",
211 i, reactos_disk_count);
212 break;
213 }
214
215 /* Copy the data over */
216 RtlCopyMemory(ArcDiskSig, &reactos_arc_disk_info[i], sizeof(ARC_DISK_SIGNATURE_EX));
217
218 /* Set the ARC Name pointer */
219 ArcDiskSig->DiskSignature.ArcName = PaToVa(ArcDiskSig->ArcName);
220
221 /* Insert into the list */
222 InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
223 &ArcDiskSig->DiskSignature.ListEntry);
224 }
225
226 /* Convert all lists to Virtual address */
227
228 /* Convert the ArcDisks list to virtual address */
229 List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
230 LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);
231
232 /* Convert configuration entries to VA */
233 ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
234 LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
235
236 /* Convert all DTE into virtual addresses */
237 List_PaToVa(&LoaderBlock->LoadOrderListHead);
238
239 /* This one will be converted right before switching to virtual paging mode */
240 //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
241
242 /* Convert list of boot drivers */
243 List_PaToVa(&LoaderBlock->BootDriverListHead);
244
245 Extension = LoaderBlock->Extension;
246
247 /* FIXME! HACK value for docking profile */
248 Extension->Profile.Status = 2;
249
250 /* Check if FreeLdr detected a ACPI table */
251 if (AcpiPresent)
252 {
253 /* Set the pointer to something for compatibility */
254 Extension->AcpiTable = (PVOID)1;
255 // FIXME: Extension->AcpiTableSize;
256 }
257
258 if (VersionToBoot >= _WIN32_WINNT_VISTA)
259 {
260 Extension->BootViaWinload = 1;
261 Extension->LoaderPerformanceData = PaToVa(&WinLdrSystemBlock->LoaderPerformanceData);
262
263 InitializeListHead(&Extension->BootApplicationPersistentData);
264 List_PaToVa(&Extension->BootApplicationPersistentData);
265 }
266
267 #ifdef _M_IX86
268 /* Set headless block pointer */
269 if (WinLdrTerminalConnected)
270 {
271 Extension->HeadlessLoaderBlock = &WinLdrSystemBlock->HeadlessLoaderBlock;
272 RtlCopyMemory(Extension->HeadlessLoaderBlock,
273 &LoaderRedirectionInformation,
274 sizeof(HEADLESS_LOADER_BLOCK));
275 Extension->HeadlessLoaderBlock = PaToVa(Extension->HeadlessLoaderBlock);
276 }
277 #endif
278 /* Load drivers database */
279 RtlStringCbCopyA(MiscFiles, sizeof(MiscFiles), BootPath);
280 RtlStringCbCatA(MiscFiles, sizeof(MiscFiles), "AppPatch\\drvmain.sdb");
281 Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles,
282 &Extension->DrvDBSize,
283 LoaderRegistryData));
284
285 /* Convert the extension block pointer */
286 LoaderBlock->Extension = PaToVa(LoaderBlock->Extension);
287
288 TRACE("WinLdrInitializePhase1() completed\n");
289 }
290
291 static BOOLEAN
WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,PCSTR BootPath,PUNICODE_STRING FilePath,ULONG Flags,PLDR_DATA_TABLE_ENTRY * DriverDTE)292 WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead,
293 PCSTR BootPath,
294 PUNICODE_STRING FilePath,
295 ULONG Flags,
296 PLDR_DATA_TABLE_ENTRY *DriverDTE)
297 {
298 CHAR FullPath[1024];
299 CHAR DriverPath[1024];
300 CHAR DllName[1024];
301 PCHAR DriverNamePos;
302 BOOLEAN Success;
303 PVOID DriverBase = NULL;
304
305 // Separate the path to file name and directory path
306 RtlStringCbPrintfA(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
307 DriverNamePos = strrchr(DriverPath, '\\');
308 if (DriverNamePos != NULL)
309 {
310 // Copy the name
311 RtlStringCbCopyA(DllName, sizeof(DllName), DriverNamePos+1);
312
313 // Cut out the name from the path
314 *(DriverNamePos+1) = ANSI_NULL;
315 }
316 else
317 {
318 // There is no directory in the path
319 RtlStringCbCopyA(DllName, sizeof(DllName), DriverPath);
320 *DriverPath = ANSI_NULL;
321 }
322
323 TRACE("DriverPath: '%s', DllName: '%s', LPB\n", DriverPath, DllName);
324
325 // Check if driver is already loaded
326 Success = PeLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE);
327 if (Success)
328 {
329 // We've got the pointer to its DTE, just return success
330 return TRUE;
331 }
332
333 // It's not loaded, we have to load it
334 RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
335
336 NtLdrOutputLoadMsg(FullPath, NULL);
337 Success = PeLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
338 if (!Success)
339 {
340 ERR("PeLdrLoadImage('%s') failed\n", DllName);
341 return FALSE;
342 }
343
344 // Allocate a DTE for it
345 Success = PeLdrAllocateDataTableEntry(LoadOrderListHead,
346 DllName,
347 DllName,
348 PaToVa(DriverBase),
349 DriverDTE);
350 if (!Success)
351 {
352 /* Cleanup and bail out */
353 ERR("PeLdrAllocateDataTableEntry('%s') failed\n", DllName);
354 MmFreeMemory(DriverBase);
355 return FALSE;
356 }
357
358 /* Init security cookie */
359 PeLdrInitSecurityCookie(*DriverDTE);
360
361 // Modify any flags, if needed
362 (*DriverDTE)->Flags |= Flags;
363
364 // Look for any dependencies it may have, and load them too
365 RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%s", BootPath, DriverPath);
366 Success = PeLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
367 if (!Success)
368 {
369 /* Cleanup and bail out */
370 ERR("PeLdrScanImportDescriptorTable('%s') failed\n", FullPath);
371 PeLdrFreeDataTableEntry(*DriverDTE);
372 MmFreeMemory(DriverBase);
373 return FALSE;
374 }
375
376 return TRUE;
377 }
378
379 BOOLEAN
WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,PCSTR BootPath)380 WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
381 PCSTR BootPath)
382 {
383 PLIST_ENTRY NextBd;
384 PBOOT_DRIVER_NODE DriverNode;
385 PBOOT_DRIVER_LIST_ENTRY BootDriver;
386 BOOLEAN Success;
387 BOOLEAN ret = TRUE;
388
389 /* Walk through the boot drivers list */
390 NextBd = LoaderBlock->BootDriverListHead.Flink;
391 while (NextBd != &LoaderBlock->BootDriverListHead)
392 {
393 DriverNode = CONTAINING_RECORD(NextBd,
394 BOOT_DRIVER_NODE,
395 ListEntry.Link);
396 BootDriver = &DriverNode->ListEntry;
397
398 /* Get the next list entry as we may remove the current one on failure */
399 NextBd = BootDriver->Link.Flink;
400
401 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n",
402 &BootDriver->FilePath, BootDriver->LdrEntry,
403 &BootDriver->RegistryPath);
404
405 // Paths are relative (FIXME: Are they always relative?)
406
407 /* Load it */
408 UiIndicateProgress();
409 Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
410 BootPath,
411 &BootDriver->FilePath,
412 0,
413 &BootDriver->LdrEntry);
414 if (Success)
415 {
416 /* Convert the addresses to VA since we are not going to use them anymore */
417 BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
418 BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
419 BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
420
421 if (DriverNode->Group.Buffer)
422 DriverNode->Group.Buffer = PaToVa(DriverNode->Group.Buffer);
423 DriverNode->Name.Buffer = PaToVa(DriverNode->Name.Buffer);
424 }
425 else
426 {
427 /* Loading failed: cry loudly */
428 ERR("Cannot load boot driver '%wZ'!\n", &BootDriver->FilePath);
429 UiMessageBox("Cannot load boot driver '%wZ'!", &BootDriver->FilePath);
430 ret = FALSE;
431
432 /* Remove it from the list and try to continue */
433 RemoveEntryList(&BootDriver->Link);
434 }
435 }
436
437 return ret;
438 }
439
440 PVOID
WinLdrLoadModule(PCSTR ModuleName,PULONG Size,TYPE_OF_MEMORY MemoryType)441 WinLdrLoadModule(PCSTR ModuleName,
442 PULONG Size,
443 TYPE_OF_MEMORY MemoryType)
444 {
445 ULONG FileId;
446 PVOID PhysicalBase;
447 FILEINFORMATION FileInfo;
448 ULONG FileSize;
449 ARC_STATUS Status;
450 ULONG BytesRead;
451
452 *Size = 0;
453
454 /* Open the image file */
455 NtLdrOutputLoadMsg(ModuleName, NULL);
456 Status = ArcOpen((PSTR)ModuleName, OpenReadOnly, &FileId);
457 if (Status != ESUCCESS)
458 {
459 /* In case of errors, we just return, without complaining to the user */
460 WARN("Error while opening '%s', Status: %u\n", ModuleName, Status);
461 return NULL;
462 }
463
464 /* Retrieve its size */
465 Status = ArcGetFileInformation(FileId, &FileInfo);
466 if (Status != ESUCCESS)
467 {
468 ArcClose(FileId);
469 return NULL;
470 }
471 FileSize = FileInfo.EndingAddress.LowPart;
472 *Size = FileSize;
473
474 /* Allocate memory */
475 PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
476 if (PhysicalBase == NULL)
477 {
478 ERR("Could not allocate memory for '%s'\n", ModuleName);
479 ArcClose(FileId);
480 return NULL;
481 }
482
483 /* Load the whole file */
484 Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
485 ArcClose(FileId);
486 if (Status != ESUCCESS)
487 {
488 WARN("Error while reading '%s', Status: %u\n", ModuleName, Status);
489 return NULL;
490 }
491
492 TRACE("Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
493
494 return PhysicalBase;
495 }
496
497 USHORT
WinLdrDetectVersion(VOID)498 WinLdrDetectVersion(VOID)
499 {
500 LONG rc;
501 HKEY hKey;
502
503 rc = RegOpenKey(CurrentControlSetKey, L"Control\\Terminal Server", &hKey);
504 if (rc != ERROR_SUCCESS)
505 {
506 /* Key doesn't exist; assume NT 4.0 */
507 return _WIN32_WINNT_NT4;
508 }
509 RegCloseKey(hKey);
510
511 /* We may here want to read the value of ProductVersion */
512 return _WIN32_WINNT_WS03;
513 }
514
515 static
516 PVOID
LoadModule(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,IN PCCH Path,IN PCCH File,IN PCCH ImportName,IN TYPE_OF_MEMORY MemoryType,OUT PLDR_DATA_TABLE_ENTRY * Dte,IN ULONG Percentage)517 LoadModule(
518 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
519 IN PCCH Path,
520 IN PCCH File,
521 IN PCCH ImportName, // BaseDllName
522 IN TYPE_OF_MEMORY MemoryType,
523 OUT PLDR_DATA_TABLE_ENTRY *Dte,
524 IN ULONG Percentage)
525 {
526 BOOLEAN Success;
527 CHAR FullFileName[MAX_PATH];
528 CHAR ProgressString[256];
529 PVOID BaseAddress;
530
531 RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
532 UiUpdateProgressBar(Percentage, ProgressString);
533
534 RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
535 RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
536
537 NtLdrOutputLoadMsg(FullFileName, NULL);
538 Success = PeLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
539 if (!Success)
540 {
541 ERR("PeLdrLoadImage('%s') failed\n", File);
542 return NULL;
543 }
544 TRACE("%s loaded successfully at %p\n", File, BaseAddress);
545
546 Success = PeLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
547 ImportName,
548 FullFileName,
549 PaToVa(BaseAddress),
550 Dte);
551 if (!Success)
552 {
553 /* Cleanup and bail out */
554 ERR("PeLdrAllocateDataTableEntry('%s') failed\n", FullFileName);
555 MmFreeMemory(BaseAddress);
556 return NULL;
557 }
558
559 /* Init security cookie */
560 PeLdrInitSecurityCookie(*Dte);
561
562 return BaseAddress;
563 }
564
565 #ifdef _M_IX86
566 static
567 BOOLEAN
WinLdrIsPaeSupported(_In_ USHORT OperatingSystemVersion,_In_ PLOADER_PARAMETER_BLOCK LoaderBlock,_In_ PCSTR BootOptions,_In_ PCSTR HalFileName,_Inout_updates_bytes_ (KernelFileNameSize)_Always_ (_Post_z_)PSTR KernelFileName,_In_ SIZE_T KernelFileNameSize)568 WinLdrIsPaeSupported(
569 _In_ USHORT OperatingSystemVersion,
570 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
571 _In_ PCSTR BootOptions,
572 _In_ PCSTR HalFileName,
573 _Inout_updates_bytes_(KernelFileNameSize) _Always_(_Post_z_)
574 PSTR KernelFileName,
575 _In_ SIZE_T KernelFileNameSize)
576 {
577 BOOLEAN PaeEnabled = FALSE;
578 BOOLEAN PaeDisabled = FALSE;
579 BOOLEAN Result;
580
581 if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
582 NtLdrGetOption(BootOptions, "PAE"))
583 {
584 /* We found the PAE option */
585 PaeEnabled = TRUE;
586 }
587
588 Result = PaeEnabled;
589
590 if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
591 NtLdrGetOption(BootOptions, "NOPAE"))
592 {
593 PaeDisabled = TRUE;
594 }
595
596 if (SafeBoot)
597 PaeDisabled = TRUE;
598
599 TRACE("PaeEnabled %X, PaeDisabled %X\n", PaeEnabled, PaeDisabled);
600
601 if (PaeDisabled)
602 Result = FALSE;
603
604 /* Enable PAE if DEP is enabled */
605 if (NoExecuteEnabled)
606 Result = TRUE;
607
608 // TODO: checks for CPU support, hotplug memory support ... other tests
609 // TODO: select kernel name ("ntkrnlpa.exe" or "ntoskrnl.exe"), or,
610 // if KernelFileName is a user-specified kernel file, check whether it
611 // has, if PAE needs to be enabled, the IMAGE_FILE_LARGE_ADDRESS_AWARE
612 // Characteristics bit set, and that the HAL image has a similar support.
613
614 if (Result) UNIMPLEMENTED;
615
616 return Result;
617 }
618 #endif /* _M_IX86 */
619
620 static
621 BOOLEAN
LoadWindowsCore(IN USHORT OperatingSystemVersion,IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,IN PCSTR BootOptions,IN PCSTR BootPath,IN OUT PLDR_DATA_TABLE_ENTRY * KernelDTE)622 LoadWindowsCore(IN USHORT OperatingSystemVersion,
623 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
624 IN PCSTR BootOptions,
625 IN PCSTR BootPath,
626 IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
627 {
628 BOOLEAN Success;
629 PCSTR Option;
630 ULONG OptionLength;
631 PVOID KernelBase, HalBase, KdDllBase = NULL;
632 PLDR_DATA_TABLE_ENTRY HalDTE, KdDllDTE = NULL;
633 CHAR DirPath[MAX_PATH];
634 CHAR HalFileName[MAX_PATH];
635 CHAR KernelFileName[MAX_PATH];
636 CHAR KdDllName[MAX_PATH];
637
638 if (!KernelDTE) return FALSE;
639
640 /* Initialize SystemRoot\System32 path */
641 RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath);
642 RtlStringCbCatA(DirPath, sizeof(DirPath), "system32\\");
643
644 /* Parse the boot options */
645 TRACE("LoadWindowsCore: BootOptions '%s'\n", BootOptions);
646
647 #ifdef _M_IX86
648 if (NtLdrGetOption(BootOptions, "3GB"))
649 {
650 /* We found the 3GB option. */
651 FIXME("LoadWindowsCore: 3GB - TRUE (not implemented)\n");
652 VirtualBias = TRUE;
653 }
654 // TODO: "USERVA=" for XP/2k3
655 #endif
656
657 if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
658 (NtLdrGetOption(BootOptions, "SAFEBOOT") ||
659 NtLdrGetOption(BootOptions, "SAFEBOOT:")))
660 {
661 /* We found the SAFEBOOT option. */
662 FIXME("LoadWindowsCore: SAFEBOOT - TRUE (not implemented)\n");
663 SafeBoot = TRUE;
664 }
665
666 if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
667 NtLdrGetOption(BootOptions, "BOOTLOGO"))
668 {
669 /* We found the BOOTLOGO option. */
670 FIXME("LoadWindowsCore: BOOTLOGO - TRUE (not implemented)\n");
671 BootLogo = TRUE;
672 }
673
674 /* Check the (NO)EXECUTE options */
675 if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
676 !LoaderBlock->SetupLdrBlock)
677 {
678 /* Disable NX by default on x86, otherwise enable it */
679 #ifdef _M_IX86
680 NoExecuteEnabled = FALSE;
681 #else
682 NoExecuteEnabled = TRUE;
683 #endif
684
685 #ifdef _M_IX86
686 /* Check the options in decreasing order of precedence */
687 if (NtLdrGetOption(BootOptions, "NOEXECUTE=OPTIN") ||
688 NtLdrGetOption(BootOptions, "NOEXECUTE=OPTOUT") ||
689 NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSON"))
690 {
691 NoExecuteEnabled = TRUE;
692 }
693 else if (NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSOFF"))
694 NoExecuteEnabled = FALSE;
695 else
696 #else
697 /* Only the following two options really apply for x64 and other platforms */
698 #endif
699 if (NtLdrGetOption(BootOptions, "NOEXECUTE"))
700 NoExecuteEnabled = TRUE;
701 else if (NtLdrGetOption(BootOptions, "EXECUTE"))
702 NoExecuteEnabled = FALSE;
703
704 #ifdef _M_IX86
705 /* Disable DEP in SafeBoot mode for x86 only */
706 if (SafeBoot)
707 NoExecuteEnabled = FALSE;
708 #endif
709 }
710 TRACE("NoExecuteEnabled %X\n", NoExecuteEnabled);
711
712 /*
713 * Select the HAL and KERNEL file names.
714 * Check for any "/HAL=" or "/KERNEL=" override option.
715 *
716 * See the following links to know how the file names are actually chosen:
717 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/detecthal.htm
718 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/hal.htm
719 * https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/kernel.htm
720 */
721 /* Default HAL and KERNEL file names */
722 RtlStringCbCopyA(HalFileName , sizeof(HalFileName) , "hal.dll");
723 RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
724
725 Option = NtLdrGetOptionEx(BootOptions, "HAL=", &OptionLength);
726 if (Option && (OptionLength > 4))
727 {
728 /* Retrieve the HAL file name */
729 Option += 4; OptionLength -= 4;
730 RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Option, OptionLength);
731 _strlwr(HalFileName);
732 }
733
734 Option = NtLdrGetOptionEx(BootOptions, "KERNEL=", &OptionLength);
735 if (Option && (OptionLength > 7))
736 {
737 /* Retrieve the KERNEL file name */
738 Option += 7; OptionLength -= 7;
739 RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Option, OptionLength);
740 _strlwr(KernelFileName);
741 }
742
743 #ifdef _M_IX86
744 /* Check for PAE support and select the adequate kernel image */
745 PaeModeOn = WinLdrIsPaeSupported(OperatingSystemVersion,
746 LoaderBlock,
747 BootOptions,
748 HalFileName,
749 KernelFileName,
750 sizeof(KernelFileName));
751 if (PaeModeOn) FIXME("WinLdrIsPaeSupported: PaeModeOn\n");
752 #endif
753
754 TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName, KernelFileName);
755
756 /*
757 * Load the core NT files: Kernel, HAL and KD transport DLL.
758 * Cheat about their base DLL name so as to satisfy the imports/exports,
759 * even if the corresponding underlying files do not have the same names
760 * -- this happens e.g. with UP vs. MP kernel, standard vs. ACPI hal, or
761 * different KD transport DLLs.
762 */
763
764 /* Load the Kernel */
765 KernelBase = LoadModule(LoaderBlock, DirPath, KernelFileName,
766 "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
767 if (!KernelBase)
768 {
769 ERR("LoadModule('%s') failed\n", KernelFileName);
770 UiMessageBox("Could not load %s", KernelFileName);
771 return FALSE;
772 }
773
774 /* Load the HAL */
775 HalBase = LoadModule(LoaderBlock, DirPath, HalFileName,
776 "hal.dll", LoaderHalCode, &HalDTE, 35);
777 if (!HalBase)
778 {
779 ERR("LoadModule('%s') failed\n", HalFileName);
780 UiMessageBox("Could not load %s", HalFileName);
781 PeLdrFreeDataTableEntry(*KernelDTE);
782 MmFreeMemory(KernelBase);
783 return FALSE;
784 }
785
786 /* Load the Kernel Debugger Transport DLL */
787 if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
788 {
789 /*
790 * According to http://www.nynaeve.net/?p=173 :
791 * "[...] Another enhancement that could be done Microsoft-side would be
792 * a better interface for replacing KD transport modules. Right now, due
793 * to the fact that ntoskrnl is static linked to KDCOM.DLL, the OS loader
794 * has a hardcoded hack that interprets the KD type in the OS loader options,
795 * loads one of the (hardcoded filenames) "kdcom.dll", "kd1394.dll", or
796 * "kdusb2.dll" modules, and inserts them into the loaded module list under
797 * the name "kdcom.dll". [...]"
798 */
799
800 /*
801 * A Kernel Debugger Transport DLL is always loaded for Windows XP+ :
802 * either the standard KDCOM.DLL (by default): IsCustomKdDll == FALSE
803 * or an alternative user-provided one via the /DEBUGPORT= option:
804 * IsCustomKdDll == TRUE if it does not specify the default KDCOM.
805 */
806 BOOLEAN IsCustomKdDll = FALSE;
807
808 /* Check whether there is a DEBUGPORT option */
809 Option = NtLdrGetOptionEx(BootOptions, "DEBUGPORT=", &OptionLength);
810 if (Option && (OptionLength > 10))
811 {
812 /* Move to the debug port name */
813 Option += 10; OptionLength -= 10;
814
815 /*
816 * Parse the port name.
817 * Format: /DEBUGPORT=COM[0-9]
818 * or: /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log
819 * or: /DEBUGPORT=FOO
820 * If we only have /DEBUGPORT= (i.e. without any port name),
821 * default to "COM".
822 */
823
824 /* Get the actual length of the debug port
825 * until the next whitespace or colon. */
826 OptionLength = (ULONG)strcspn(Option, " \t:");
827
828 if ((OptionLength == 0) ||
829 ( (OptionLength >= 3) && (_strnicmp(Option, "COM", 3) == 0) &&
830 ((OptionLength == 3) || ('0' <= Option[3] && Option[3] <= '9')) ))
831 {
832 /* The standard KDCOM.DLL is used */
833 }
834 else
835 {
836 /* A custom KD DLL is used */
837 IsCustomKdDll = TRUE;
838 }
839 }
840 if (!IsCustomKdDll)
841 {
842 Option = "COM"; OptionLength = 3;
843 }
844
845 RtlStringCbPrintfA(KdDllName, sizeof(KdDllName), "kd%.*s.dll",
846 OptionLength, Option);
847 _strlwr(KdDllName);
848
849 /* Load the KD DLL. Override its base DLL name to the default "KDCOM.DLL". */
850 KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
851 "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
852 if (!KdDllBase)
853 {
854 /* If we failed to load a custom KD DLL, fall back to the standard one */
855 if (IsCustomKdDll)
856 {
857 /* The custom KD DLL being optional, just ignore the failure */
858 WARN("LoadModule('%s') failed\n", KdDllName);
859
860 IsCustomKdDll = FALSE;
861 RtlStringCbCopyA(KdDllName, sizeof(KdDllName), "kdcom.dll");
862
863 KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
864 "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
865 }
866
867 if (!KdDllBase)
868 {
869 /* Ignore the failure; we will fail later when scanning the
870 * kernel import tables, if it really needs the KD DLL. */
871 ERR("LoadModule('%s') failed\n", KdDllName);
872 }
873 }
874 }
875
876 /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
877 Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
878 if (!Success)
879 {
880 UiMessageBox("Could not load %s", KernelFileName);
881 goto Quit;
882 }
883 Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
884 if (!Success)
885 {
886 UiMessageBox("Could not load %s", HalFileName);
887 goto Quit;
888 }
889 if (KdDllDTE)
890 {
891 Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdDllDTE);
892 if (!Success)
893 {
894 UiMessageBox("Could not load %s", KdDllName);
895 goto Quit;
896 }
897 }
898
899 Quit:
900 if (!Success)
901 {
902 /* Cleanup and bail out */
903 if (KdDllDTE)
904 PeLdrFreeDataTableEntry(KdDllDTE);
905 if (KdDllBase) // Optional
906 MmFreeMemory(KdDllBase);
907
908 PeLdrFreeDataTableEntry(HalDTE);
909 MmFreeMemory(HalBase);
910
911 PeLdrFreeDataTableEntry(*KernelDTE);
912 MmFreeMemory(KernelBase);
913 }
914
915 return Success;
916 }
917
918 static
919 BOOLEAN
WinLdrInitErrataInf(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,IN USHORT OperatingSystemVersion,IN PCSTR SystemRoot)920 WinLdrInitErrataInf(
921 IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
922 IN USHORT OperatingSystemVersion,
923 IN PCSTR SystemRoot)
924 {
925 LONG rc;
926 HKEY hKey;
927 ULONG BufferSize;
928 ULONG FileSize;
929 PVOID PhysicalBase;
930 WCHAR szFileName[80];
931 CHAR ErrataFilePath[MAX_PATH];
932
933 /* Open either the 'BiosInfo' (Windows <= 2003) or the 'Errata' (Vista+) key */
934 if (OperatingSystemVersion >= _WIN32_WINNT_VISTA)
935 {
936 rc = RegOpenKey(CurrentControlSetKey, L"Control\\Errata", &hKey);
937 }
938 else // (OperatingSystemVersion <= _WIN32_WINNT_WS03)
939 {
940 rc = RegOpenKey(CurrentControlSetKey, L"Control\\BiosInfo", &hKey);
941 }
942 if (rc != ERROR_SUCCESS)
943 {
944 WARN("Could not open the BiosInfo/Errata registry key (Error %u)\n", (int)rc);
945 return FALSE;
946 }
947
948 /* Retrieve the INF file name value */
949 BufferSize = sizeof(szFileName);
950 rc = RegQueryValue(hKey, L"InfName", NULL, (PUCHAR)szFileName, &BufferSize);
951 if (rc != ERROR_SUCCESS)
952 {
953 WARN("Could not retrieve the InfName value (Error %u)\n", (int)rc);
954 RegCloseKey(hKey);
955 return FALSE;
956 }
957
958 // TODO: "SystemBiosDate"
959
960 RegCloseKey(hKey);
961
962 RtlStringCbPrintfA(ErrataFilePath, sizeof(ErrataFilePath), "%s%s%S",
963 SystemRoot, "inf\\", szFileName);
964
965 /* Load the INF file */
966 PhysicalBase = WinLdrLoadModule(ErrataFilePath, &FileSize, LoaderRegistryData);
967 if (!PhysicalBase)
968 {
969 WARN("Could not load '%s'\n", ErrataFilePath);
970 return FALSE;
971 }
972
973 LoaderBlock->Extension->EmInfFileImage = PaToVa(PhysicalBase);
974 LoaderBlock->Extension->EmInfFileSize = FileSize;
975
976 return TRUE;
977 }
978
979 ARC_STATUS
LoadAndBootWindows(IN ULONG Argc,IN PCHAR Argv[],IN PCHAR Envp[])980 LoadAndBootWindows(
981 IN ULONG Argc,
982 IN PCHAR Argv[],
983 IN PCHAR Envp[])
984 {
985 ARC_STATUS Status;
986 PCSTR ArgValue;
987 PCSTR SystemPartition;
988 PCSTR FileName;
989 ULONG FileNameLength;
990 BOOLEAN Success;
991 USHORT OperatingSystemVersion;
992 PLOADER_PARAMETER_BLOCK LoaderBlock;
993 CHAR BootPath[MAX_PATH];
994 CHAR FilePath[MAX_PATH];
995 CHAR BootOptions[256];
996
997 /* Retrieve the (mandatory) boot type */
998 ArgValue = GetArgumentValue(Argc, Argv, "BootType");
999 if (!ArgValue || !*ArgValue)
1000 {
1001 ERR("No 'BootType' value, aborting!\n");
1002 return EINVAL;
1003 }
1004
1005 /* Convert it to an OS version */
1006 if (_stricmp(ArgValue, "Windows") == 0 ||
1007 _stricmp(ArgValue, "Windows2003") == 0)
1008 {
1009 OperatingSystemVersion = _WIN32_WINNT_WS03;
1010 }
1011 else if (_stricmp(ArgValue, "WindowsNT40") == 0)
1012 {
1013 OperatingSystemVersion = _WIN32_WINNT_NT4;
1014 }
1015 else if (_stricmp(ArgValue, "WindowsVista") == 0)
1016 {
1017 OperatingSystemVersion = _WIN32_WINNT_VISTA;
1018 }
1019 else
1020 {
1021 ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
1022 return EINVAL;
1023 }
1024
1025 /* Retrieve the (mandatory) system partition */
1026 SystemPartition = GetArgumentValue(Argc, Argv, "SystemPartition");
1027 if (!SystemPartition || !*SystemPartition)
1028 {
1029 ERR("No 'SystemPartition' specified, aborting!\n");
1030 return EINVAL;
1031 }
1032
1033 /* Let the user know we started loading */
1034 UiDrawBackdrop();
1035 UiDrawStatusText("Loading...");
1036 UiDrawProgressBarCenter("Loading NT...");
1037
1038 /* Retrieve the system path */
1039 *BootPath = ANSI_NULL;
1040 ArgValue = GetArgumentValue(Argc, Argv, "SystemPath");
1041 if (ArgValue)
1042 RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
1043
1044 /*
1045 * Check whether BootPath is a full path
1046 * and if not, create a full boot path.
1047 *
1048 * See FsOpenFile for the technique used.
1049 */
1050 if (strrchr(BootPath, ')') == NULL)
1051 {
1052 /* Temporarily save the boot path */
1053 RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
1054
1055 /* This is not a full path: prepend the SystemPartition */
1056 RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
1057
1058 /* Append a path separator if needed */
1059 if (*FilePath != '\\' && *FilePath != '/')
1060 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
1061
1062 /* Append the remaining path */
1063 RtlStringCbCatA(BootPath, sizeof(BootPath), FilePath);
1064 }
1065
1066 /* Append a path separator if needed */
1067 if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
1068 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
1069
1070 TRACE("BootPath: '%s'\n", BootPath);
1071
1072 /* Retrieve the boot options */
1073 *BootOptions = ANSI_NULL;
1074 ArgValue = GetArgumentValue(Argc, Argv, "Options");
1075 if (ArgValue && *ArgValue)
1076 RtlStringCbCopyA(BootOptions, sizeof(BootOptions), ArgValue);
1077
1078 /* Append boot-time options */
1079 AppendBootTimeOptions(BootOptions);
1080
1081 /*
1082 * Set the "/HAL=" and "/KERNEL=" options if needed.
1083 * If already present on the standard "Options=" option line, they take
1084 * precedence over those passed via the separate "Hal=" and "Kernel="
1085 * options.
1086 */
1087 if (!NtLdrGetOption(BootOptions, "HAL="))
1088 {
1089 /*
1090 * Not found in the options, try to retrieve the
1091 * separate value and append it to the options.
1092 */
1093 ArgValue = GetArgumentValue(Argc, Argv, "Hal");
1094 if (ArgValue && *ArgValue)
1095 {
1096 RtlStringCbCatA(BootOptions, sizeof(BootOptions), " /HAL=");
1097 RtlStringCbCatA(BootOptions, sizeof(BootOptions), ArgValue);
1098 }
1099 }
1100 if (!NtLdrGetOption(BootOptions, "KERNEL="))
1101 {
1102 /*
1103 * Not found in the options, try to retrieve the
1104 * separate value and append it to the options.
1105 */
1106 ArgValue = GetArgumentValue(Argc, Argv, "Kernel");
1107 if (ArgValue && *ArgValue)
1108 {
1109 RtlStringCbCatA(BootOptions, sizeof(BootOptions), " /KERNEL=");
1110 RtlStringCbCatA(BootOptions, sizeof(BootOptions), ArgValue);
1111 }
1112 }
1113
1114 TRACE("BootOptions: '%s'\n", BootOptions);
1115
1116 /* Check if a RAM disk file was given */
1117 FileName = NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
1118 if (FileName && (FileNameLength > 7))
1119 {
1120 /* Load the RAM disk */
1121 Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
1122 if (Status != ESUCCESS)
1123 {
1124 FileName += 7; FileNameLength -= 7;
1125 UiMessageBox("Failed to load RAM disk file '%.*s'",
1126 FileNameLength, FileName);
1127 return Status;
1128 }
1129 }
1130
1131 /* Handle the SOS option */
1132 SosEnabled = !!NtLdrGetOption(BootOptions, "SOS");
1133 if (SosEnabled)
1134 UiResetForSOS();
1135
1136 /* Allocate and minimally-initialize the Loader Parameter Block */
1137 AllocateAndInitLPB(OperatingSystemVersion, &LoaderBlock);
1138
1139 /* Load the system hive */
1140 UiUpdateProgressBar(15, "Loading system hive...");
1141 Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
1142 TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
1143 /* Bail out if failure */
1144 if (!Success)
1145 return ENOEXEC;
1146
1147 /* Fixup the version number using data from the registry */
1148 if (OperatingSystemVersion == 0)
1149 OperatingSystemVersion = WinLdrDetectVersion();
1150 LoaderBlock->Extension->MajorVersion = (OperatingSystemVersion & 0xFF00) >> 8;
1151 LoaderBlock->Extension->MinorVersion = (OperatingSystemVersion & 0xFF);
1152
1153 /* Load NLS data, OEM font, and prepare boot drivers list */
1154 Success = WinLdrScanSystemHive(LoaderBlock, BootPath);
1155 TRACE("SYSTEM hive %s\n", (Success ? "scanned" : "not scanned"));
1156 /* Bail out if failure */
1157 if (!Success)
1158 return ENOEXEC;
1159
1160 /* Load the Firmware Errata file */
1161 Success = WinLdrInitErrataInf(LoaderBlock, OperatingSystemVersion, BootPath);
1162 TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
1163 /* Not necessarily fatal if not found - carry on going */
1164
1165 /* Finish loading */
1166 return LoadAndBootWindowsCommon(OperatingSystemVersion,
1167 LoaderBlock,
1168 BootOptions,
1169 BootPath);
1170 }
1171
1172 ARC_STATUS
LoadAndBootWindowsCommon(IN USHORT OperatingSystemVersion,IN PLOADER_PARAMETER_BLOCK LoaderBlock,IN PCSTR BootOptions,IN PCSTR BootPath)1173 LoadAndBootWindowsCommon(
1174 IN USHORT OperatingSystemVersion,
1175 IN PLOADER_PARAMETER_BLOCK LoaderBlock,
1176 IN PCSTR BootOptions,
1177 IN PCSTR BootPath)
1178 {
1179 PLOADER_PARAMETER_BLOCK LoaderBlockVA;
1180 BOOLEAN Success;
1181 PLDR_DATA_TABLE_ENTRY KernelDTE;
1182 KERNEL_ENTRY_POINT KiSystemStartup;
1183 PCSTR SystemRoot;
1184
1185 TRACE("LoadAndBootWindowsCommon()\n");
1186
1187 ASSERT(OperatingSystemVersion != 0);
1188
1189 #ifdef _M_IX86
1190 /* Setup redirection support */
1191 WinLdrSetupEms(BootOptions);
1192 #endif
1193
1194 /* Convert BootPath to SystemRoot */
1195 SystemRoot = strstr(BootPath, "\\");
1196
1197 /* Detect hardware */
1198 UiUpdateProgressBar(20, "Detecting hardware...");
1199 LoaderBlock->ConfigurationRoot = MachHwDetect(BootOptions);
1200
1201 /* Initialize the PE loader import-DLL callback, so that we can obtain
1202 * feedback (for example during SOS) on the PE images that get loaded. */
1203 PeLdrImportDllLoadCallback = NtLdrImportDllLoadCallback;
1204
1205 /* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
1206 Success = LoadWindowsCore(OperatingSystemVersion,
1207 LoaderBlock,
1208 BootOptions,
1209 BootPath,
1210 &KernelDTE);
1211 if (!Success)
1212 {
1213 /* Reset the PE loader import-DLL callback */
1214 PeLdrImportDllLoadCallback = NULL;
1215
1216 UiMessageBox("Error loading NTOS core.");
1217 return ENOEXEC;
1218 }
1219
1220 /* Cleanup INI file */
1221 IniCleanup();
1222
1223 /****
1224 **** WE HAVE NOW REACHED THE POINT OF NO RETURN !!
1225 ****/
1226
1227 UiSetProgressBarSubset(40, 90); // NTOS goes from 25 to 75%
1228
1229 /* Load boot drivers */
1230 UiSetProgressBarText("Loading boot drivers...");
1231 Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
1232 TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
1233
1234 UiSetProgressBarSubset(0, 100);
1235
1236 /* Reset the PE loader import-DLL callback */
1237 PeLdrImportDllLoadCallback = NULL;
1238
1239 /* Initialize Phase 1 - no drivers loading anymore */
1240 WinLdrInitializePhase1(LoaderBlock,
1241 BootOptions,
1242 SystemRoot,
1243 BootPath,
1244 OperatingSystemVersion);
1245
1246 UiUpdateProgressBar(100, NULL);
1247
1248 /* Save entry-point pointer and Loader block VAs */
1249 KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
1250 LoaderBlockVA = PaToVa(LoaderBlock);
1251
1252 /* "Stop all motors", change videomode */
1253 MachPrepareForReactOS();
1254
1255 /* Debugging... */
1256 //DumpMemoryAllocMap();
1257
1258 /* Do the machine specific initialization */
1259 WinLdrSetupMachineDependent(LoaderBlock);
1260
1261 /* Map pages and create memory descriptors */
1262 WinLdrSetupMemoryLayout(LoaderBlock);
1263
1264 /* Set processor context */
1265 WinLdrSetProcessorContext(OperatingSystemVersion);
1266
1267 /* Save final value of LoaderPagesSpanned */
1268 LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
1269
1270 TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
1271 KiSystemStartup, LoaderBlockVA);
1272
1273 /* Zero KI_USER_SHARED_DATA page */
1274 RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, MM_PAGE_SIZE);
1275
1276 WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
1277 WinLdrpDumpBootDriver(LoaderBlockVA);
1278 #ifndef _M_AMD64
1279 WinLdrpDumpArcDisks(LoaderBlockVA);
1280 #endif
1281
1282 /* Pass control */
1283 (*KiSystemStartup)(LoaderBlockVA);
1284
1285 UNREACHABLE; // return ESUCCESS;
1286 }
1287
1288 VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)1289 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
1290 {
1291 PLIST_ENTRY NextMd;
1292 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
1293
1294 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
1295
1296 while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
1297 {
1298 MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
1299
1300 TRACE("BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
1301 MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
1302
1303 NextMd = MemoryDescriptor->ListEntry.Flink;
1304 }
1305 }
1306
1307 VOID
WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)1308 WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
1309 {
1310 PLIST_ENTRY NextBd;
1311 PBOOT_DRIVER_LIST_ENTRY BootDriver;
1312
1313 NextBd = LoaderBlock->BootDriverListHead.Flink;
1314
1315 while (NextBd != &LoaderBlock->BootDriverListHead)
1316 {
1317 BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
1318
1319 TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
1320 BootDriver->LdrEntry, &BootDriver->RegistryPath);
1321
1322 NextBd = BootDriver->Link.Flink;
1323 }
1324 }
1325
1326 VOID
WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)1327 WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
1328 {
1329 PLIST_ENTRY NextBd;
1330 PARC_DISK_SIGNATURE ArcDisk;
1331
1332 NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
1333
1334 while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
1335 {
1336 ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
1337
1338 TRACE("ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
1339 ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
1340
1341 NextBd = ArcDisk->ListEntry.Flink;
1342 }
1343 }
1344