diff --git a/boot/freeldr/freeldr/ntldr/winldr.c b/boot/freeldr/freeldr/ntldr/winldr.c index abd1e34d87e..37154af4ce4 100644 --- a/boot/freeldr/freeldr/ntldr/winldr.c +++ b/boot/freeldr/freeldr/ntldr/winldr.c @@ -6,12 +6,15 @@ */ #include +#include // For KeFindConfiguration*Entry() #include #include "winldr.h" #include "ntldropts.h" #include "registry.h" #include +#include // For CM_FRAMEBUF_DEVICE_DATA + #include DBG_DEFAULT_CHANNEL(WINDOWS); @@ -616,6 +619,112 @@ WinLdrIsPaeSupported( } #endif /* _M_IX86 */ +static VOID +NtLdrDetectBootVid( + _In_ PCONFIGURATION_COMPONENT_DATA ConfigTree, + _Out_writes_bytes_(BootVidNameSize) _Always_(_Post_z_) + PSTR BootVidName, + _In_ SIZE_T BootVidNameSize) +{ + /* NOTE: The following array should instead be read from txtsetup.sif */ + static const struct + { + PCSTR SystemSubId; + PCSTR ModuleName; + } BootVidNames[] = + { +#if defined(_M_IX86) && !defined(UEFIBOOT) + {"PC-98", "pc98bvid.dll"}, + {"Xbox", "xboxbvid.dll"}, +#endif + {"EFI", "lfbbvid.dll"}, + }; + + /* Default BootVid file name */ + RtlStringCbCopyA(BootVidName, BootVidNameSize, "bootvid.dll"); + + /* Attempt auto-detection by System ID */ + PCONFIGURATION_COMPONENT_DATA Entry; + Entry = KeFindConfigurationEntry(ConfigTree, + SystemClass, + ArcSystem, + NULL); + if (!Entry) + { + /* No SystemClass ArcSystem entry, retry with hack */ + Entry = KeFindConfigurationEntry(ConfigTree, + SystemClass, + MaximumType, // HACK for non-ARC machines + NULL); + } + if (Entry) + { + // Entry->ComponentEntry.IdentifierLength; + TRACE("ARC System ID: '%s'\n", Entry->ComponentEntry.Identifier); + + /* Look up the name */ + for (ULONG i = 0; i < RTL_NUMBER_OF(BootVidNames); ++i) + { + if (strstr(Entry->ComponentEntry.Identifier, BootVidNames[i].SystemSubId)) + { + RtlStringCbCopyA(BootVidName, BootVidNameSize, BootVidNames[i].ModuleName); + break; + } + } + } + /* Special-case detection if the display controller contains + * a DeviceSpecific CM_FRAMEBUF_DEVICE_DATA resource */ + Entry = KeFindConfigurationEntry(ConfigTree, + ControllerClass, + DisplayController, + NULL); + if (Entry) + { + /* Cast to PCM_PARTIAL_RESOURCE_LIST to access + * the common Version and Revision fields */ + PCM_PARTIAL_RESOURCE_LIST ResourceList = + (PCM_PARTIAL_RESOURCE_LIST)Entry->ConfigurationData; + ULONG ConfigurationDataLength = + Entry->ComponentEntry.ConfigurationDataLength; + + // Entry->ComponentEntry.IdentifierLength; + TRACE("Display: '%s'\n", Entry->ComponentEntry.Identifier); + + /* The configuration data length must be valid. + * The Version/Revision must be greater than or equal to 1.2 + * in order to describe a valid new configuration data. */ + if (Entry->ConfigurationData && + (ConfigurationDataLength >= sizeof(CM_PARTIAL_RESOURCE_LIST)) && + ( (ResourceList->Version > 1) || + ((ResourceList->Version == 1) && (ResourceList->Revision > 1)) )) + { + /* Try to find the DeviceSpecific resource */ + PCM_PARTIAL_RESOURCE_DESCRIPTOR DeviceSpecific = NULL; + for (ULONG i = 0; i < ResourceList->Count; ++i) + { + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = + &ResourceList->PartialDescriptors[i]; + if (Descriptor->Type == CmResourceTypeDeviceSpecific) + { + /* NOTE: This descriptor *MUST* be the last one. + * The actual device data follows the descriptor. */ + ASSERT(i == ResourceList->Count - 1); + DeviceSpecific = Descriptor; + break; + } + } + + /* Check whether the resource describes framebuffer information */ + if (DeviceSpecific && + (DeviceSpecific->u.DeviceSpecificData.DataSize >= sizeof(CM_FRAMEBUF_DEVICE_DATA))) + { + /* It does, use the Linear FrameBuffer Boot Video Driver instead */ + RtlStringCbCopyA(BootVidName, BootVidNameSize, "lfbbvid.dll"); + } + } + } +} + static BOOLEAN LoadWindowsCore(IN USHORT OperatingSystemVersion, @@ -627,14 +736,14 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion, BOOLEAN Success; PCSTR Option; ULONG OptionLength; - PVOID KernelBase, HalBase, KdDllBase = NULL; - PLDR_DATA_TABLE_ENTRY HalDTE, KdDllDTE = NULL; + PVOID KernelBase, HalBase, KdDllBase = NULL, BootVidBase = NULL; + PLDR_DATA_TABLE_ENTRY HalDTE, KdDllDTE = NULL, BootVidDTE = NULL; + PCSTR ModuleName; CHAR DirPath[MAX_PATH]; CHAR HalFileName[MAX_PATH]; CHAR KernelFileName[MAX_PATH]; CHAR KdDllName[MAX_PATH]; - - if (!KernelDTE) return FALSE; + CHAR BootVidName[MAX_PATH]; /* Initialize SystemRoot\System32 path */ RtlStringCbCopyA(DirPath, sizeof(DirPath), BootPath); @@ -880,33 +989,76 @@ LoadWindowsCore(IN USHORT OperatingSystemVersion, } } - /* Load all referenced DLLs for Kernel, HAL and Kernel Debugger Transport DLL */ + /* Load the correct Boot Video Driver */ + if (OperatingSystemVersion >= _WIN32_WINNT_WIN2K) + { + /* Check whether there is a BOOTVID option */ + Option = NtLdrGetOptionEx(BootOptions, "BOOTVID=", &OptionLength); + if (Option && (OptionLength > 8)) + { + /* Retrieve the BootVid file name */ + Option += 8; OptionLength -= 8; + RtlStringCbCopyNA(BootVidName, sizeof(BootVidName), Option, OptionLength); + _strlwr(BootVidName); + TRACE("User-specified BootVid file: '%s'\n", BootVidName); + } + else + { + /* No option given, attempt auto-detection */ + NtLdrDetectBootVid(LoaderBlock->ConfigurationRoot, + BootVidName, sizeof(BootVidName)); + TRACE("Auto-detected BootVid file: '%s'\n", BootVidName); + } + + /* Load the BootVid */ + BootVidBase = LoadModule(&LoaderBlock->LoadOrderListHead, + DirPath, BootVidName, + "bootvid.dll", LoaderSystemCode, + &BootVidDTE, 45); + if (!BootVidBase) + { + /* Ignore the failure; we will fail later when scanning the + * kernel import tables, if it really needs the BootVid. */ + ERR("LoadModule('%s') failed\n", BootVidName); + } + } + + /* Load all referenced DLLs for Kernel, HAL, Kernel Debugger Transport and BootVid */ + ModuleName = KernelFileName; Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, *KernelDTE); if (!Success) - { - UiMessageBox("Could not load %s", KernelFileName); goto Quit; - } + ModuleName = HalFileName; Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, HalDTE); if (!Success) - { - UiMessageBox("Could not load %s", HalFileName); goto Quit; - } if (KdDllDTE) { + ModuleName = KdDllName; Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, KdDllDTE); if (!Success) - { - UiMessageBox("Could not load %s", KdDllName); goto Quit; - } + } + if (BootVidDTE) + { + ModuleName = BootVidName; + Success = PeLdrScanImportDescriptorTable(&LoaderBlock->LoadOrderListHead, DirPath, BootVidDTE); + if (!Success) + goto Quit; } Quit: if (!Success) { + ERR("PeLdrScanImportDescriptorTable('%s') failed\n", ModuleName); + UiMessageBox("Could not load %s", ModuleName); + /* Cleanup and bail out */ + if (BootVidDTE) + PeLdrFreeDataTableEntry(BootVidDTE); + if (BootVidBase) // Optional + MmFreeMemory(BootVidBase); + if (KdDllDTE) PeLdrFreeDataTableEntry(KdDllDTE); if (KdDllBase) // Optional diff --git a/boot/freeldr/freeldr/rosload.cmake b/boot/freeldr/freeldr/rosload.cmake index 3494a652459..75eede17b1f 100644 --- a/boot/freeldr/freeldr/rosload.cmake +++ b/boot/freeldr/freeldr/rosload.cmake @@ -17,6 +17,7 @@ list(APPEND ROSLOAD_SOURCE oslist.c lib/rtl/libsupp.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmboot.c + ${REACTOS_SOURCE_DIR}/ntoskrnl/ke/config.c ntldr/conversion.c ntldr/headless.c ntldr/inffile.c diff --git a/boot/freeldr/freeldr/uefi.cmake b/boot/freeldr/freeldr/uefi.cmake index 1d74f2c690a..8ca6a6f83f2 100644 --- a/boot/freeldr/freeldr/uefi.cmake +++ b/boot/freeldr/freeldr/uefi.cmake @@ -55,6 +55,7 @@ add_asm_files(uefifreeldr_common_asm ${FREELDR_COMMON_ASM_SOURCE} ${UEFILDR_COMM list(APPEND FREELDR_NTLDR_SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmboot.c + ${REACTOS_SOURCE_DIR}/ntoskrnl/ke/config.c ntldr/conversion.c ntldr/headless.c ntldr/inffile.c diff --git a/ntoskrnl/ke/config.c b/ntoskrnl/ke/config.c index fd406888077..5b0b3c99441 100644 --- a/ntoskrnl/ke/config.c +++ b/ntoskrnl/ke/config.c @@ -3,6 +3,8 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Configuration Tree Routines * COPYRIGHT: Copyright 2005-2006 Alex Ionescu + * + * NOTE: This module is shared by both the kernel and the bootloader. */ /* INCLUDES ******************************************************************/