#include <freeldr.h>
#include <ndk/ldrtypes.h>
#include "winldr.h"
+#include "ntldropts.h"
#include "registry.h"
+#include <internal/cmboot.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(WINDOWS);
extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
extern BOOLEAN WinLdrTerminalConnected;
-extern void WinLdrSetupEms(IN PCHAR BootOptions);
+extern VOID WinLdrSetupEms(IN PCSTR BootOptions);
PLOADER_SYSTEM_BLOCK WinLdrSystemBlock;
+/**/PCWSTR BootFileSystem = NULL;/**/
+
+BOOLEAN VirtualBias = FALSE;
+BOOLEAN SosEnabled = FALSE;
+BOOLEAN SafeBoot = FALSE;
+BOOLEAN BootLogo = FALSE;
+#ifdef _M_IX86
+BOOLEAN PaeModeOn = FALSE;
+#endif
+BOOLEAN NoExecuteEnabled = FALSE;
// debug stuff
VOID DumpMemoryAllocMap(VOID);
+/* PE loader import-DLL loading callback */
+static VOID
+NTAPI
+NtLdrImportDllLoadCallback(
+ _In_ PCSTR FileName)
+{
+ NtLdrOutputLoadMsg(FileName, NULL);
+}
+
+VOID
+NtLdrOutputLoadMsg(
+ _In_ PCSTR FileName,
+ _In_opt_ PCSTR Description)
+{
+ if (SosEnabled)
+ {
+ printf(" %s\n", FileName);
+ TRACE("Loading: %s\n", FileName);
+ }
+ else
+ {
+ /* Inform the user we load a file */
+ CHAR ProgressString[256];
+
+ RtlStringCbPrintfA(ProgressString, sizeof(ProgressString),
+ "Loading %s...",
+ (Description ? Description : FileName));
+ // UiSetProgressBarText(ProgressString);
+ // UiIndicateProgress();
+ UiDrawStatusText(ProgressString);
+ }
+}
+
// Init "phase 0"
VOID
-AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
+AllocateAndInitLPB(
+ IN USHORT VersionToBoot,
+ OUT PLOADER_PARAMETER_BLOCK* OutLoaderBlock)
{
PLOADER_PARAMETER_BLOCK LoaderBlock;
+ PLOADER_PARAMETER_EXTENSION Extension;
- /* Allocate and zero-init the LPB */
+ /* Allocate and zero-init the Loader Parameter Block */
WinLdrSystemBlock = MmAllocateMemoryWithType(sizeof(LOADER_SYSTEM_BLOCK),
LoaderSystemBlock);
if (WinLdrSystemBlock == NULL)
LoaderBlock = &WinLdrSystemBlock->LoaderBlock;
LoaderBlock->NlsData = &WinLdrSystemBlock->NlsDataBlock;
+ /* Initialize the Loader Block Extension */
+ Extension = &WinLdrSystemBlock->Extension;
+ LoaderBlock->Extension = Extension;
+ Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
+ Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
+ Extension->MinorVersion = (VersionToBoot & 0xFF);
+
/* Init three critical lists, used right away */
InitializeListHead(&LoaderBlock->LoadOrderListHead);
InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
// SetupBlock->ArcSetupDeviceName must be the path to the setup **SOURCE**,
// and not the setup boot path. Indeed they may differ!!
//
- /* If we have a setup block, adjust also its ARC path */
if (LoaderBlock->SetupLdrBlock)
{
PSETUP_LOADER_BLOCK SetupBlock = LoaderBlock->SetupLdrBlock;
- /* Matches ArcBoot path */
+ /* Adjust the ARC path in the setup block - Matches ArcBoot path */
SetupBlock->ArcSetupDeviceName = WinLdrSystemBlock->ArcBootDeviceName;
SetupBlock->ArcSetupDeviceName = PaToVa(SetupBlock->ArcSetupDeviceName);
- /* Note: LoaderBlock->SetupLdrBlock is PaToVa'ed at the end of this function */
+ /* Convert the setup block pointer */
+ LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
}
/* Fill ARC HalDevice, it matches ArcBoot path */
/* Allocate the ARC structure */
ArcDiskSig = FrLdrHeapAlloc(sizeof(ARC_DISK_SIGNATURE_EX), 'giSD');
+ if (!ArcDiskSig)
+ {
+ ERR("Failed to allocate ARC structure! Ignoring remaining ARC disks. (i = %lu, DiskCount = %lu)\n",
+ i, reactos_disk_count);
+ break;
+ }
/* Copy the data over */
RtlCopyMemory(ArcDiskSig, &reactos_arc_disk_info[i], sizeof(ARC_DISK_SIGNATURE_EX));
&ArcDiskSig->DiskSignature.ListEntry);
}
- /* Convert all list's to Virtual address */
+ /* Convert all lists to Virtual address */
/* Convert the ArcDisks list to virtual address */
List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
/* Convert list of boot drivers */
List_PaToVa(&LoaderBlock->BootDriverListHead);
- /* Initialize Extension now */
- Extension = &WinLdrSystemBlock->Extension;
- Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
- Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
- Extension->MinorVersion = VersionToBoot & 0xFF;
+ Extension = LoaderBlock->Extension;
+
+ /* FIXME! HACK value for docking profile */
Extension->Profile.Status = 2;
/* Check if FreeLdr detected a ACPI table */
// FIXME: Extension->AcpiTableSize;
}
+ if (VersionToBoot >= _WIN32_WINNT_VISTA)
+ {
+ Extension->BootViaWinload = 1;
+ Extension->LoaderPerformanceData = PaToVa(&WinLdrSystemBlock->LoaderPerformanceData);
+
+ InitializeListHead(&Extension->BootApplicationPersistentData);
+ List_PaToVa(&Extension->BootApplicationPersistentData);
+ }
+
#ifdef _M_IX86
/* Set headless block pointer */
if (WinLdrTerminalConnected)
&Extension->DrvDBSize,
LoaderRegistryData));
- /* Convert extension and setup block pointers */
- LoaderBlock->Extension = PaToVa(Extension);
-
- if (LoaderBlock->SetupLdrBlock)
- LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
+ /* Convert the extension block pointer */
+ LoaderBlock->Extension = PaToVa(LoaderBlock->Extension);
TRACE("WinLdrInitializePhase1() completed\n");
}
// It's not loaded, we have to load it
RtlStringCbPrintfA(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
+
+ NtLdrOutputLoadMsg(FullPath, NULL);
Success = PeLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
if (!Success)
+ {
+ ERR("PeLdrLoadImage('%s') failed\n", DllName);
return FALSE;
+ }
// Allocate a DTE for it
Success = PeLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE);
if (!Success)
{
- ERR("PeLdrAllocateDataTableEntry() failed\n");
+ /* Cleanup and bail out */
+ ERR("PeLdrAllocateDataTableEntry('%s') failed\n", DllName);
+ MmFreeMemory(DriverBase);
return FALSE;
}
+ /* Init security cookie */
+ PeLdrInitSecurityCookie(*DriverDTE);
+
// Modify any flags, if needed
(*DriverDTE)->Flags |= Flags;
Success = PeLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE);
if (!Success)
{
- ERR("PeLdrScanImportDescriptorTable() failed for %s\n", FullPath);
+ /* Cleanup and bail out */
+ ERR("PeLdrScanImportDescriptorTable('%s') failed\n", FullPath);
+ PeLdrFreeDataTableEntry(*DriverDTE);
+ MmFreeMemory(DriverBase);
return FALSE;
}
PCSTR BootPath)
{
PLIST_ENTRY NextBd;
+ PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY BootDriver;
BOOLEAN Success;
BOOLEAN ret = TRUE;
- // Walk through the boot drivers list
+ /* Walk through the boot drivers list */
NextBd = LoaderBlock->BootDriverListHead.Flink;
-
while (NextBd != &LoaderBlock->BootDriverListHead)
{
- BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
+ DriverNode = CONTAINING_RECORD(NextBd,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+ BootDriver = &DriverNode->ListEntry;
- TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
- BootDriver->LdrEntry, &BootDriver->RegistryPath);
+ /* Get the next list entry as we may remove the current one on failure */
+ NextBd = BootDriver->Link.Flink;
+
+ TRACE("BootDriver %wZ DTE %08X RegPath: %wZ\n",
+ &BootDriver->FilePath, BootDriver->LdrEntry,
+ &BootDriver->RegistryPath);
// Paths are relative (FIXME: Are they always relative?)
- // Load it
+ /* Load it */
+ UiIndicateProgress();
Success = WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
BootPath,
&BootDriver->FilePath,
0,
&BootDriver->LdrEntry);
-
if (Success)
{
- // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
+ /* Convert the addresses to VA since we are not going to use them anymore */
BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
+
+ if (DriverNode->Group.Buffer)
+ DriverNode->Group.Buffer = PaToVa(DriverNode->Group.Buffer);
+ DriverNode->Name.Buffer = PaToVa(DriverNode->Name.Buffer);
}
else
{
- // Loading failed - cry loudly
- ERR("Can't load boot driver '%wZ'!\n", &BootDriver->FilePath);
- UiMessageBox("Can't load boot driver '%wZ'!", &BootDriver->FilePath);
+ /* Loading failed: cry loudly */
+ ERR("Cannot load boot driver '%wZ'!\n", &BootDriver->FilePath);
+ UiMessageBox("Cannot load boot driver '%wZ'!", &BootDriver->FilePath);
ret = FALSE;
- // Remove it from the list and try to continue
- RemoveEntryList(NextBd);
+ /* Remove it from the list and try to continue */
+ RemoveEntryList(&BootDriver->Link);
}
-
- NextBd = BootDriver->Link.Flink;
}
return ret;
ARC_STATUS Status;
ULONG BytesRead;
- //CHAR ProgressString[256];
-
- /* Inform user we are loading files */
- //UiDrawBackdrop();
- //RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", FileName);
- //UiDrawProgressBarCenter(1, 100, ProgressString);
-
- TRACE("Loading module %s\n", ModuleName);
*Size = 0;
/* Open the image file */
+ NtLdrOutputLoadMsg(ModuleName, NULL);
Status = ArcOpen((PSTR)ModuleName, OpenReadOnly, &FileId);
if (Status != ESUCCESS)
{
return NULL;
}
- /* Get this file's size */
+ /* Retrieve its size */
Status = ArcGetFileInformation(FileId, &FileInfo);
if (Status != ESUCCESS)
{
PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
if (PhysicalBase == NULL)
{
+ ERR("Could not allocate memory for '%s'\n", ModuleName);
ArcClose(FileId);
return NULL;
}
- /* Load whole file */
+ /* Load the whole file */
Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
ArcClose(FileId);
if (Status != ESUCCESS)
LONG rc;
HKEY hKey;
- rc = RegOpenKey(NULL,
- L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
- &hKey);
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\Terminal Server", &hKey);
if (rc != ERROR_SUCCESS)
{
/* Key doesn't exist; assume NT 4.0 */
return _WIN32_WINNT_NT4;
}
+ RegCloseKey(hKey);
/* We may here want to read the value of ProductVersion */
return _WIN32_WINNT_WS03;
}
static
-BOOLEAN
+PVOID
LoadModule(
IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PCCH Path,
BOOLEAN Success;
CHAR FullFileName[MAX_PATH];
CHAR ProgressString[256];
- PVOID BaseAddress = NULL;
+ PVOID BaseAddress;
- UiDrawBackdrop();
RtlStringCbPrintfA(ProgressString, sizeof(ProgressString), "Loading %s...", File);
- UiDrawProgressBarCenter(Percentage, 100, ProgressString);
+ UiUpdateProgressBar(Percentage, ProgressString);
RtlStringCbCopyA(FullFileName, sizeof(FullFileName), Path);
RtlStringCbCatA(FullFileName, sizeof(FullFileName), File);
+ NtLdrOutputLoadMsg(FullFileName, NULL);
Success = PeLdrLoadImage(FullFileName, MemoryType, &BaseAddress);
if (!Success)
{
- TRACE("Loading %s failed\n", File);
- return FALSE;
+ ERR("PeLdrLoadImage('%s') failed\n", File);
+ return NULL;
}
TRACE("%s loaded successfully at %p\n", File, BaseAddress);
- /*
- * Cheat about the base DLL name if we are loading
- * the Kernel Debugger Transport DLL, to make the
- * PE loader happy.
- */
Success = PeLdrAllocateDataTableEntry(&LoaderBlock->LoadOrderListHead,
ImportName,
FullFileName,
BaseAddress,
Dte);
+ if (!Success)
+ {
+ /* Cleanup and bail out */
+ ERR("PeLdrAllocateDataTableEntry('%s') failed\n", FullFileName);
+ MmFreeMemory(BaseAddress);
+ return NULL;
+ }
- return Success;
+ /* Init security cookie */
+ PeLdrInitSecurityCookie(*Dte);
+
+ return BaseAddress;
+}
+
+#ifdef _M_IX86
+static
+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)
+{
+ BOOLEAN PaeEnabled = FALSE;
+ BOOLEAN PaeDisabled = FALSE;
+ BOOLEAN Result;
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
+ NtLdrGetOption(BootOptions, "PAE"))
+ {
+ /* We found the PAE option */
+ PaeEnabled = TRUE;
+ }
+
+ Result = PaeEnabled;
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ NtLdrGetOption(BootOptions, "NOPAE"))
+ {
+ PaeDisabled = TRUE;
+ }
+
+ if (SafeBoot)
+ PaeDisabled = TRUE;
+
+ TRACE("PaeEnabled %X, PaeDisabled %X\n", PaeEnabled, PaeDisabled);
+
+ if (PaeDisabled)
+ Result = FALSE;
+
+ /* Enable PAE if DEP is enabled */
+ if (NoExecuteEnabled)
+ Result = TRUE;
+
+ // TODO: checks for CPU support, hotplug memory support ... other tests
+ // TODO: select kernel name ("ntkrnlpa.exe" or "ntoskrnl.exe"), or,
+ // if KernelFileName is a user-specified kernel file, check whether it
+ // has, if PAE needs to be enabled, the IMAGE_FILE_LARGE_ADDRESS_AWARE
+ // Characteristics bit set, and that the HAL image has a similar support.
+
+ if (Result) UNIMPLEMENTED;
+
+ return Result;
}
+#endif /* _M_IX86 */
static
BOOLEAN
IN OUT PLDR_DATA_TABLE_ENTRY* KernelDTE)
{
BOOLEAN Success;
- PCSTR Options;
+ PCSTR Option;
+ ULONG OptionLength;
+ PVOID KernelBase, HalBase, KdDllBase = NULL;
+ PLDR_DATA_TABLE_ENTRY HalDTE, KdDllDTE = NULL;
CHAR DirPath[MAX_PATH];
CHAR HalFileName[MAX_PATH];
CHAR KernelFileName[MAX_PATH];
- CHAR KdTransportDllName[MAX_PATH];
- PLDR_DATA_TABLE_ENTRY HalDTE, KdComDTE = NULL;
+ CHAR KdDllName[MAX_PATH];
if (!KernelDTE) return FALSE;
RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath);
RtlStringCbCatA(DirPath, sizeof(DirPath), "system32\\");
+ /* Parse the boot options */
+ TRACE("LoadWindowsCore: BootOptions '%s'\n", BootOptions);
+
+#ifdef _M_IX86
+ if (NtLdrGetOption(BootOptions, "3GB"))
+ {
+ /* We found the 3GB option. */
+ FIXME("LoadWindowsCore: 3GB - TRUE (not implemented)\n");
+ VirtualBias = TRUE;
+ }
+ // TODO: "USERVA=" for XP/2k3
+#endif
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_NT4) &&
+ (NtLdrGetOption(BootOptions, "SAFEBOOT") ||
+ NtLdrGetOption(BootOptions, "SAFEBOOT:")))
+ {
+ /* We found the SAFEBOOT option. */
+ FIXME("LoadWindowsCore: SAFEBOOT - TRUE (not implemented)\n");
+ SafeBoot = TRUE;
+ }
+
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ NtLdrGetOption(BootOptions, "BOOTLOGO"))
+ {
+ /* We found the BOOTLOGO option. */
+ FIXME("LoadWindowsCore: BOOTLOGO - TRUE (not implemented)\n");
+ BootLogo = TRUE;
+ }
+
+ /* Check the (NO)EXECUTE options */
+ if ((OperatingSystemVersion > _WIN32_WINNT_WIN2K) &&
+ !LoaderBlock->SetupLdrBlock)
+ {
+ /* Disable NX by default on x86, otherwise enable it */
+#ifdef _M_IX86
+ NoExecuteEnabled = FALSE;
+#else
+ NoExecuteEnabled = TRUE;
+#endif
+
+#ifdef _M_IX86
+ /* Check the options in decreasing order of precedence */
+ if (NtLdrGetOption(BootOptions, "NOEXECUTE=OPTIN") ||
+ NtLdrGetOption(BootOptions, "NOEXECUTE=OPTOUT") ||
+ NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSON"))
+ {
+ NoExecuteEnabled = TRUE;
+ }
+ else if (NtLdrGetOption(BootOptions, "NOEXECUTE=ALWAYSOFF"))
+ NoExecuteEnabled = FALSE;
+ else
+#else
+ /* Only the following two options really apply for x64 and other platforms */
+#endif
+ if (NtLdrGetOption(BootOptions, "NOEXECUTE"))
+ NoExecuteEnabled = TRUE;
+ else if (NtLdrGetOption(BootOptions, "EXECUTE"))
+ NoExecuteEnabled = FALSE;
+
+#ifdef _M_IX86
+ /* Disable DEP in SafeBoot mode for x86 only */
+ if (SafeBoot)
+ NoExecuteEnabled = FALSE;
+#endif
+ }
+ TRACE("NoExecuteEnabled %X\n", NoExecuteEnabled);
+
/*
- * Default HAL and KERNEL file names.
+ * Select the HAL and KERNEL file names.
+ * Check for any "/HAL=" or "/KERNEL=" override option.
+ *
* See the following links to know how the file names are actually chosen:
* https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/detecthal.htm
* https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/hal.htm
* https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/kernel.htm
*/
+ /* Default HAL and KERNEL file names */
RtlStringCbCopyA(HalFileName , sizeof(HalFileName) , "hal.dll");
RtlStringCbCopyA(KernelFileName, sizeof(KernelFileName), "ntoskrnl.exe");
- /* Find any "/HAL=" or "/KERNEL=" switch in the boot options */
- Options = BootOptions;
- while (Options)
+ Option = NtLdrGetOptionEx(BootOptions, "HAL=", &OptionLength);
+ if (Option && (OptionLength > 4))
{
- /* Skip possible initial whitespace */
- Options += strspn(Options, " \t");
-
- /* Check whether a new option starts and it is either HAL or KERNEL */
- if (*Options != '/' || (++Options,
- !(_strnicmp(Options, "HAL=", 4) == 0 ||
- _strnicmp(Options, "KERNEL=", 7) == 0)) )
- {
- /* Search for another whitespace */
- Options = strpbrk(Options, " \t");
- continue;
- }
- else
- {
- size_t i = strcspn(Options, " \t"); /* Skip whitespace */
- if (i == 0)
- {
- /* Use the default values */
- break;
- }
+ /* Retrieve the HAL file name */
+ Option += 4; OptionLength -= 4;
+ RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Option, OptionLength);
+ _strlwr(HalFileName);
+ }
- /* We have found either HAL or KERNEL options */
- if (_strnicmp(Options, "HAL=", 4) == 0)
- {
- Options += 4; i -= 4;
- RtlStringCbCopyNA(HalFileName, sizeof(HalFileName), Options, i);
- _strupr(HalFileName);
- }
- else if (_strnicmp(Options, "KERNEL=", 7) == 0)
- {
- Options += 7; i -= 7;
- RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Options, i);
- _strupr(KernelFileName);
- }
- }
+ Option = NtLdrGetOptionEx(BootOptions, "KERNEL=", &OptionLength);
+ if (Option && (OptionLength > 7))
+ {
+ /* Retrieve the KERNEL file name */
+ Option += 7; OptionLength -= 7;
+ RtlStringCbCopyNA(KernelFileName, sizeof(KernelFileName), Option, OptionLength);
+ _strlwr(KernelFileName);
}
+#ifdef _M_IX86
+ /* Check for PAE support and select the adequate kernel image */
+ PaeModeOn = WinLdrIsPaeSupported(OperatingSystemVersion,
+ LoaderBlock,
+ BootOptions,
+ HalFileName,
+ KernelFileName,
+ sizeof(KernelFileName));
+ if (PaeModeOn) FIXME("WinLdrIsPaeSupported: PaeModeOn\n");
+#endif
+
TRACE("HAL file = '%s' ; Kernel file = '%s'\n", HalFileName, KernelFileName);
+ /*
+ * Load the core NT files: Kernel, HAL and KD transport DLL.
+ * Cheat about their base DLL name so as to satisfy the imports/exports,
+ * even if the corresponding underlying files do not have the same names
+ * -- this happens e.g. with UP vs. MP kernel, standard vs. ACPI hal, or
+ * different KD transport DLLs.
+ */
+
/* Load the Kernel */
- LoadModule(LoaderBlock, DirPath, KernelFileName, "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
+ KernelBase = LoadModule(LoaderBlock, DirPath, KernelFileName,
+ "ntoskrnl.exe", LoaderSystemCode, KernelDTE, 30);
+ if (!KernelBase)
+ {
+ ERR("LoadModule('%s') failed\n", KernelFileName);
+ UiMessageBox("Could not load %s", KernelFileName);
+ return FALSE;
+ }
/* Load the HAL */
- LoadModule(LoaderBlock, DirPath, HalFileName, "hal.dll", LoaderHalCode, &HalDTE, 45);
+ HalBase = LoadModule(LoaderBlock, DirPath, HalFileName,
+ "hal.dll", LoaderHalCode, &HalDTE, 35);
+ if (!HalBase)
+ {
+ ERR("LoadModule('%s') failed\n", HalFileName);
+ UiMessageBox("Could not load %s", HalFileName);
+ PeLdrFreeDataTableEntry(*KernelDTE);
+ MmFreeMemory(KernelBase);
+ return FALSE;
+ }
/* Load the Kernel Debugger Transport DLL */
if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
*/
/*
- * This loop replaces a dumb call to strstr(..., "DEBUGPORT=").
- * Indeed I want it to be case-insensitive to allow "debugport="
- * or "DeBuGpOrT=" or... , and I don't want it to match malformed
- * command-line options, such as:
- *
- * "...foo DEBUGPORT=xxx bar..."
- * "...foo/DEBUGPORT=xxx bar..."
- * "...foo/DEBUGPORT=bar..."
- *
- * i.e. the "DEBUGPORT=" switch must start with a slash and be separated
- * from the rest by whitespace, unless it begins the command-line, e.g.:
- *
- * "/DEBUGPORT=COM1 foo...bar..."
- * "...foo /DEBUGPORT=USB bar..."
- * or:
- * "...foo /DEBUGPORT= bar..."
- * (in that case, we default the port to COM).
+ * A Kernel Debugger Transport DLL is always loaded for Windows XP+ :
+ * either the standard KDCOM.DLL (by default): IsCustomKdDll == FALSE
+ * or an alternative user-provided one via the /DEBUGPORT= option:
+ * IsCustomKdDll == TRUE if it does not specify the default KDCOM.
*/
- Options = BootOptions;
- while (Options)
+ BOOLEAN IsCustomKdDll = FALSE;
+
+ /* Check whether there is a DEBUGPORT option */
+ Option = NtLdrGetOptionEx(BootOptions, "DEBUGPORT=", &OptionLength);
+ if (Option && (OptionLength > 10))
{
- /* Skip possible initial whitespace */
- Options += strspn(Options, " \t");
+ /* Move to the debug port name */
+ Option += 10; OptionLength -= 10;
+
+ /*
+ * Parse the port name.
+ * Format: /DEBUGPORT=COM[0-9]
+ * or: /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log
+ * or: /DEBUGPORT=FOO
+ * If we only have /DEBUGPORT= (i.e. without any port name),
+ * default to "COM".
+ */
- /* Check whether a new option starts and it is the DEBUGPORT one */
- if (*Options != '/' || _strnicmp(++Options, "DEBUGPORT=", 10) != 0)
+ /* Get the actual length of the debug port
+ * until the next whitespace or colon. */
+ OptionLength = (ULONG)strcspn(Option, " \t:");
+
+ if ((OptionLength == 0) ||
+ ( (OptionLength >= 3) && (_strnicmp(Option, "COM", 3) == 0) &&
+ ((OptionLength == 3) || ('0' <= Option[3] && Option[3] <= '9')) ))
{
- /* Search for another whitespace */
- Options = strpbrk(Options, " \t");
- continue;
+ /* The standard KDCOM.DLL is used */
}
else
{
- /* We found the DEBUGPORT option. Move to the port name. */
- Options += 10;
- break;
+ /* A custom KD DLL is used */
+ IsCustomKdDll = TRUE;
}
}
+ if (!IsCustomKdDll)
+ {
+ Option = "COM"; OptionLength = 3;
+ }
+
+ RtlStringCbPrintfA(KdDllName, sizeof(KdDllName), "kd%.*s.dll",
+ OptionLength, Option);
+ _strlwr(KdDllName);
- if (Options)
+ /* Load the KD DLL. Override its base DLL name to the default "KDCOM.DLL". */
+ KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
+ "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
+ if (!KdDllBase)
{
- /*
- * We have found the DEBUGPORT option. Parse the port name.
- * Format: /DEBUGPORT=COM1 or /DEBUGPORT=FILE:\Device\HarddiskX\PartitionY\debug.log or /DEBUGPORT=FOO
- * If we only have /DEBUGPORT= (i.e. without any port name), defaults it to "COM".
- */
- RtlStringCbCopyA(KdTransportDllName, sizeof(KdTransportDllName), "KD");
- if (_strnicmp(Options, "COM", 3) == 0 && '0' <= Options[3] && Options[3] <= '9')
+ /* If we failed to load a custom KD DLL, fall back to the standard one */
+ if (IsCustomKdDll)
{
- RtlStringCbCatNA(KdTransportDllName, sizeof(KdTransportDllName), Options, 3);
+ /* The custom KD DLL being optional, just ignore the failure */
+ WARN("LoadModule('%s') failed\n", KdDllName);
+
+ IsCustomKdDll = FALSE;
+ RtlStringCbCopyA(KdDllName, sizeof(KdDllName), "kdcom.dll");
+
+ KdDllBase = LoadModule(LoaderBlock, DirPath, KdDllName,
+ "kdcom.dll", LoaderSystemCode, &KdDllDTE, 40);
}
- else
+
+ if (!KdDllBase)
{
- size_t i = strcspn(Options, " \t:"); /* Skip valid separators: whitespace or colon */
- if (i == 0)
- RtlStringCbCatA(KdTransportDllName, sizeof(KdTransportDllName), "COM");
- else
- RtlStringCbCatNA(KdTransportDllName, sizeof(KdTransportDllName), Options, i);
+ /* Ignore the failure; we will fail later when scanning the
+ * kernel import tables, if it really needs the KD DLL. */
+ ERR("LoadModule('%s') failed\n", KdDllName);
}
- RtlStringCbCatA(KdTransportDllName, sizeof(KdTransportDllName), ".DLL");
- _strupr(KdTransportDllName);
-
- /*
- * Load the transport DLL. Override the base DLL name of the
- * loaded transport DLL to the default "KDCOM.DLL" name.
- */
- LoadModule(LoaderBlock, DirPath, KdTransportDllName, "kdcom.dll", LoaderSystemCode, &KdComDTE, 60);
}
}
/* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */
- Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
- Success &= PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
- if (KdComDTE)
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE);
+ if (!Success)
{
- Success &= PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdComDTE);
+ UiMessageBox("Could not load %s", KernelFileName);
+ goto Quit;
+ }
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE);
+ if (!Success)
+ {
+ UiMessageBox("Could not load %s", HalFileName);
+ goto Quit;
+ }
+ if (KdDllDTE)
+ {
+ Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdDllDTE);
+ if (!Success)
+ {
+ UiMessageBox("Could not load %s", KdDllName);
+ goto Quit;
+ }
+ }
+
+Quit:
+ if (!Success)
+ {
+ /* Cleanup and bail out */
+ if (KdDllDTE)
+ PeLdrFreeDataTableEntry(KdDllDTE);
+ if (KdDllBase) // Optional
+ MmFreeMemory(KdDllBase);
+
+ PeLdrFreeDataTableEntry(HalDTE);
+ MmFreeMemory(HalBase);
+
+ PeLdrFreeDataTableEntry(*KernelDTE);
+ MmFreeMemory(KernelBase);
}
return Success;
}
+static
+BOOLEAN
+WinLdrInitErrataInf(
+ IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN USHORT OperatingSystemVersion,
+ IN PCSTR SystemRoot)
+{
+ LONG rc;
+ HKEY hKey;
+ ULONG BufferSize;
+ ULONG FileSize;
+ PVOID PhysicalBase;
+ WCHAR szFileName[80];
+ CHAR ErrataFilePath[MAX_PATH];
+
+ /* Open either the 'BiosInfo' (Windows <= 2003) or the 'Errata' (Vista+) key */
+ if (OperatingSystemVersion >= _WIN32_WINNT_VISTA)
+ {
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\Errata", &hKey);
+ }
+ else // (OperatingSystemVersion <= _WIN32_WINNT_WS03)
+ {
+ rc = RegOpenKey(CurrentControlSetKey, L"Control\\BiosInfo", &hKey);
+ }
+ if (rc != ERROR_SUCCESS)
+ {
+ WARN("Could not open the BiosInfo/Errata registry key (Error %u)\n", (int)rc);
+ return FALSE;
+ }
+
+ /* Retrieve the INF file name value */
+ BufferSize = sizeof(szFileName);
+ rc = RegQueryValue(hKey, L"InfName", NULL, (PUCHAR)szFileName, &BufferSize);
+ if (rc != ERROR_SUCCESS)
+ {
+ WARN("Could not retrieve the InfName value (Error %u)\n", (int)rc);
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+
+ // TODO: "SystemBiosDate"
+
+ RegCloseKey(hKey);
+
+ RtlStringCbPrintfA(ErrataFilePath, sizeof(ErrataFilePath), "%s%s%S",
+ SystemRoot, "inf\\", szFileName);
+
+ /* Load the INF file */
+ PhysicalBase = WinLdrLoadModule(ErrataFilePath, &FileSize, LoaderRegistryData);
+ if (!PhysicalBase)
+ {
+ WARN("Could not load '%s'\n", ErrataFilePath);
+ return FALSE;
+ }
+
+ LoaderBlock->Extension->EmInfFileImage = PaToVa(PhysicalBase);
+ LoaderBlock->Extension->EmInfFileSize = FileSize;
+
+ return TRUE;
+}
+
ARC_STATUS
LoadAndBootWindows(
IN ULONG Argc,
ARC_STATUS Status;
PCSTR ArgValue;
PCSTR SystemPartition;
- PCHAR File;
+ PCSTR FileName;
+ ULONG FileNameLength;
BOOLEAN Success;
USHORT OperatingSystemVersion;
PLOADER_PARAMETER_BLOCK LoaderBlock;
- CHAR BootPath[MAX_PATH];
- CHAR FileName[MAX_PATH];
- CHAR BootOptions[256];
+ CHAR BootPath[MAX_PATH];
+ CHAR FilePath[MAX_PATH];
+ CHAR BootOptions[256];
/* Retrieve the (mandatory) boot type */
ArgValue = GetArgumentValue(Argc, Argv, "BootType");
{
OperatingSystemVersion = _WIN32_WINNT_NT4;
}
+ else if (_stricmp(ArgValue, "WindowsVista") == 0)
+ {
+ OperatingSystemVersion = _WIN32_WINNT_VISTA;
+ }
else
{
ERR("Unknown 'BootType' value '%s', aborting!\n", ArgValue);
return EINVAL;
}
+ /* Let the user know we started loading */
UiDrawBackdrop();
- UiDrawProgressBarCenter(1, 100, "Loading NT...");
+ UiDrawStatusText("Loading...");
+ UiDrawProgressBarCenter("Loading NT...");
/* Retrieve the system path */
*BootPath = ANSI_NULL;
if (strrchr(BootPath, ')') == NULL)
{
/* Temporarily save the boot path */
- RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
+ RtlStringCbCopyA(FilePath, sizeof(FilePath), BootPath);
/* This is not a full path: prepend the SystemPartition */
RtlStringCbCopyA(BootPath, sizeof(BootPath), SystemPartition);
/* Append a path separator if needed */
- if (*FileName != '\\' && *FileName != '/')
+ if (*FilePath != '\\' && *FilePath != '/')
RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
/* Append the remaining path */
- RtlStringCbCatA(BootPath, sizeof(BootPath), FileName);
+ RtlStringCbCatA(BootPath, sizeof(BootPath), FilePath);
}
/* Append a path separator if needed */
AppendBootTimeOptions(BootOptions);
/*
- * Set "/HAL=" and "/KERNEL=" options if needed.
+ * Set the "/HAL=" and "/KERNEL=" options if needed.
* If already present on the standard "Options=" option line, they take
* precedence over those passed via the separate "Hal=" and "Kernel="
* options.
*/
- if (strstr(BootOptions, "/HAL=") != 0)
+ if (!NtLdrGetOption(BootOptions, "HAL="))
{
/*
* Not found in the options, try to retrieve the
RtlStringCbCatA(BootOptions, sizeof(BootOptions), ArgValue);
}
}
- if (strstr(BootOptions, "/KERNEL=") != 0)
+ if (!NtLdrGetOption(BootOptions, "KERNEL="))
{
/*
* Not found in the options, try to retrieve the
TRACE("BootOptions: '%s'\n", BootOptions);
- /* Check if a ramdisk file was given */
- File = strstr(BootOptions, "/RDPATH=");
- if (File)
+ /* Check if a RAM disk file was given */
+ FileName = NtLdrGetOptionEx(BootOptions, "RDPATH=", &FileNameLength);
+ if (FileName && (FileNameLength > 7))
{
- /* Copy the file name and everything else after it */
- RtlStringCbCopyA(FileName, sizeof(FileName), File + 8);
-
- /* Null-terminate */
- *strstr(FileName, " ") = ANSI_NULL;
-
- /* Load the ramdisk */
- Status = RamDiskLoadVirtualFile(FileName, SystemPartition);
+ /* Load the RAM disk */
+ Status = RamDiskInitialize(FALSE, BootOptions, SystemPartition);
if (Status != ESUCCESS)
{
- UiMessageBox("Failed to load RAM disk file %s", FileName);
+ FileName += 7; FileNameLength -= 7;
+ UiMessageBox("Failed to load RAM disk file '%.*s'",
+ FileNameLength, FileName);
return Status;
}
}
- /* Let user know we started loading */
- //UiDrawStatusText("Loading...");
+ /* Handle the SOS option */
+ SosEnabled = !!NtLdrGetOption(BootOptions, "SOS");
+ if (SosEnabled)
+ UiResetForSOS();
- /* Allocate and minimalist-initialize LPB */
- AllocateAndInitLPB(&LoaderBlock);
+ /* Allocate and minimally-initialize the Loader Parameter Block */
+ AllocateAndInitLPB(OperatingSystemVersion, &LoaderBlock);
/* Load the system hive */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(15, 100, "Loading system hive...");
+ UiUpdateProgressBar(15, "Loading system hive...");
Success = WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
TRACE("SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
/* Bail out if failure */
if (!Success)
return ENOEXEC;
+ /* Fixup the version number using data from the registry */
+ if (OperatingSystemVersion == 0)
+ OperatingSystemVersion = WinLdrDetectVersion();
+ LoaderBlock->Extension->MajorVersion = (OperatingSystemVersion & 0xFF00) >> 8;
+ LoaderBlock->Extension->MinorVersion = (OperatingSystemVersion & 0xFF);
+
/* Load NLS data, OEM font, and prepare boot drivers list */
Success = WinLdrScanSystemHive(LoaderBlock, BootPath);
TRACE("SYSTEM hive %s\n", (Success ? "scanned" : "not scanned"));
if (!Success)
return ENOEXEC;
+ /* Load the Firmware Errata file */
+ Success = WinLdrInitErrataInf(LoaderBlock, OperatingSystemVersion, BootPath);
+ TRACE("Firmware Errata file %s\n", (Success ? "loaded" : "not loaded"));
+ /* Not necessarily fatal if not found - carry on going */
+
/* Finish loading */
return LoadAndBootWindowsCommon(OperatingSystemVersion,
LoaderBlock,
BootOptions,
- BootPath,
- FALSE);
+ BootPath);
}
ARC_STATUS
LoadAndBootWindowsCommon(
- USHORT OperatingSystemVersion,
- PLOADER_PARAMETER_BLOCK LoaderBlock,
- PCSTR BootOptions,
- PCSTR BootPath,
- BOOLEAN Setup)
+ IN USHORT OperatingSystemVersion,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN PCSTR BootOptions,
+ IN PCSTR BootPath)
{
PLOADER_PARAMETER_BLOCK LoaderBlockVA;
BOOLEAN Success;
TRACE("LoadAndBootWindowsCommon()\n");
+ ASSERT(OperatingSystemVersion != 0);
+
#ifdef _M_IX86
/* Setup redirection support */
- WinLdrSetupEms((PCHAR)BootOptions);
+ WinLdrSetupEms(BootOptions);
#endif
/* Convert BootPath to SystemRoot */
SystemRoot = strstr(BootPath, "\\");
/* Detect hardware */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(20, 100, "Detecting hardware...");
- LoaderBlock->ConfigurationRoot = MachHwDetect();
+ UiUpdateProgressBar(20, "Detecting hardware...");
+ LoaderBlock->ConfigurationRoot = MachHwDetect(BootOptions);
- if (OperatingSystemVersion == 0)
- OperatingSystemVersion = WinLdrDetectVersion();
+ /* Initialize the PE loader import-DLL callback, so that we can obtain
+ * feedback (for example during SOS) on the PE images that get loaded. */
+ PeLdrImportDllLoadCallback = NtLdrImportDllLoadCallback;
/* Load the operating system core: the Kernel, the HAL and the Kernel Debugger Transport DLL */
Success = LoadWindowsCore(OperatingSystemVersion,
&KernelDTE);
if (!Success)
{
+ /* Reset the PE loader import-DLL callback */
+ PeLdrImportDllLoadCallback = NULL;
+
UiMessageBox("Error loading NTOS core.");
return ENOEXEC;
}
+ /* Cleanup INI file */
+ IniCleanup();
+
+/****
+ **** WE HAVE NOW REACHED THE POINT OF NO RETURN !!
+ ****/
+
+ UiSetProgressBarSubset(40, 90); // NTOS goes from 25 to 75%
+
/* Load boot drivers */
- UiDrawBackdrop();
- UiDrawProgressBarCenter(100, 100, "Loading boot drivers...");
+ UiSetProgressBarText("Loading boot drivers...");
Success = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
TRACE("Boot drivers loading %s\n", Success ? "successful" : "failed");
- /* Cleanup ini file */
- IniCleanup();
+ UiSetProgressBarSubset(0, 100);
+
+ /* Reset the PE loader import-DLL callback */
+ PeLdrImportDllLoadCallback = NULL;
/* Initialize Phase 1 - no drivers loading anymore */
WinLdrInitializePhase1(LoaderBlock,
BootPath,
OperatingSystemVersion);
+ UiUpdateProgressBar(100, NULL);
+
/* Save entry-point pointer and Loader block VAs */
KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
LoaderBlockVA = PaToVa(LoaderBlock);
WinLdrSetupMemoryLayout(LoaderBlock);
/* Set processor context */
- WinLdrSetProcessorContext();
+ WinLdrSetProcessorContext(OperatingSystemVersion);
/* Save final value of LoaderPagesSpanned */
LoaderBlock->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
/* Pass control */
(*KiSystemStartup)(LoaderBlockVA);
- return ESUCCESS;
+
+ UNREACHABLE; // return ESUCCESS;
}
VOID