diff --git a/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c b/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c index 59beccfb4fe..8bea135ec0e 100644 --- a/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c +++ b/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c @@ -18,14 +18,18 @@ #include #include +#include "../../vidfb.h" #include DBG_DEFAULT_CHANNEL(HWDETECT); #define MAX_XBOX_COM_PORTS 2 +/* From xboxvideo.c */ +extern ULONG NvBase; extern ULONG_PTR FrameBuffer; extern ULONG FrameBufferSize; +extern PCM_FRAMEBUF_DEVICE_DATA FrameBufferData; BOOLEAN XboxFindPciBios(PPCI_REGISTRY_INFO BusData) @@ -148,17 +152,19 @@ XboxGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize) } static VOID -DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey) +DetectDisplayController( + _In_ PCONFIGURATION_COMPONENT_DATA BusKey) { PCONFIGURATION_COMPONENT_DATA ControllerKey; PCM_PARTIAL_RESOURCE_LIST PartialResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; + PCM_FRAMEBUF_DEVICE_DATA FramebufData; ULONG Size; - if (FrameBufferSize == 0) + if (!FrameBuffer || (FrameBufferSize == 0) || !FrameBufferData) return; - Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors[1]); + Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors[3]) + sizeof(*FramebufData); PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST); if (PartialResourceList == NULL) { @@ -169,17 +175,40 @@ DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey) /* Initialize resource descriptor */ RtlZeroMemory(PartialResourceList, Size); PartialResourceList->Version = 1; - PartialResourceList->Revision = 1; - PartialResourceList->Count = 1; + PartialResourceList->Revision = 2; + PartialResourceList->Count = 3; + + /* Set IO Control Port */ + PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; + PartialDescriptor->Type = CmResourceTypePort; + PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + PartialDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; + PartialDescriptor->u.Port.Start.LowPart = NvBase; + PartialDescriptor->u.Port.Start.HighPart = 0; + PartialDescriptor->u.Port.Length = (16 * 1024 * 1024); /* Set Memory */ - PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; + PartialDescriptor = &PartialResourceList->PartialDescriptors[1]; PartialDescriptor->Type = CmResourceTypeMemory; PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; PartialDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; PartialDescriptor->u.Memory.Start.LowPart = (FrameBuffer & 0x0FFFFFFF); PartialDescriptor->u.Memory.Length = FrameBufferSize; + /* Set framebuffer-specific data */ + PartialDescriptor = &PartialResourceList->PartialDescriptors[2]; + PartialDescriptor->Type = CmResourceTypeDeviceSpecific; + PartialDescriptor->ShareDisposition = CmResourceShareUndetermined; + PartialDescriptor->Flags = 0; + PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(*FramebufData); + + /* Get pointer to framebuffer-specific data */ + FramebufData = (PCM_FRAMEBUF_DEVICE_DATA)(PartialDescriptor + 1); + RtlCopyMemory(FramebufData, FrameBufferData, sizeof(*FrameBufferData)); + FramebufData->Version = 1; + FramebufData->Revision = 3; + FramebufData->VideoClock = 0; + FldrCreateComponentKey(BusKey, ControllerClass, DisplayController, @@ -190,6 +219,8 @@ DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey) PartialResourceList, Size, &ControllerKey); + + // NOTE: Don't add a MonitorPeripheral for now. } static @@ -236,7 +267,6 @@ DetectIsaBios( /* Detect ISA/BIOS devices */ DetectBiosDisks(SystemKey, BusKey); DetectSerialPorts(Options, BusKey, XboxGetSerialPort, MAX_XBOX_COM_PORTS); - DetectDisplayController(BusKey); /* FIXME: Detect more ISA devices */ } @@ -272,10 +302,45 @@ XboxHwDetect( GetHarddiskConfigurationData = XboxGetHarddiskConfigurationData; FindPciBios = XboxFindPciBios; - /* TODO: Build actual xbox's hardware configuration tree */ + /* TODO: Build actual Xbox's hardware configuration tree */ DetectPciBios(SystemKey, &BusNumber); DetectIsaBios(Options, SystemKey, &BusNumber); + /* On XBOX, the display controller is on PCI bus #1 */ + { + PCONFIGURATION_COMPONENT_DATA BusKey; + ULONG NumPciBus = 0; + ULONG PciBusToFind = 1; + + /* PCI buses are under the System Key (i.e. siblings) */ + for (BusKey = SystemKey->Child; BusKey; BusKey = BusKey->Sibling) + { + ERR("** XBOX: Current bus '%s' **\n", BusKey->ComponentEntry.Identifier); + + /* Try to get a match */ + if ((BusKey->ComponentEntry.Class == AdapterClass) && + (BusKey->ComponentEntry.Type == MultiFunctionAdapter) && + /* Verify it's a PCI key */ + (BusKey->ComponentEntry.Identifier && + !_stricmp(BusKey->ComponentEntry.Identifier, "PCI"))) + { + /* Got a PCI bus, check whether it's the one to find */ + if (NumPciBus == PciBusToFind) + { + ERR("** XBOX: PCI bus #%lu found!\n **\n", PciBusToFind); + break; + } + /* Nope, continue */ + ++NumPciBus; + } + } + if (BusKey) + { + ERR("** XBOX: Adding Display Controller on PCI #1 **\n"); + DetectDisplayController(BusKey); + } + } + TRACE("DetectHardware() Done\n"); return SystemKey; } diff --git a/boot/freeldr/freeldr/arch/i386/xbox/xboxvideo.c b/boot/freeldr/freeldr/arch/i386/xbox/xboxvideo.c index 6c325fa52e6..d47b0fffce9 100644 --- a/boot/freeldr/freeldr/arch/i386/xbox/xboxvideo.c +++ b/boot/freeldr/freeldr/arch/i386/xbox/xboxvideo.c @@ -28,8 +28,8 @@ DBG_DEFAULT_CHANNEL(UI); ULONG NvBase = 0xFD000000; ULONG_PTR FrameBuffer; ULONG FrameBufferSize; +PCM_FRAMEBUF_DEVICE_DATA FrameBufferData = NULL; extern multiboot_info_t * MultibootInfoPtr; -#define FB_SIZE_MB 4 #define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) | (((Green) & 0xff) << 8) | ((Blue) & 0xff)) @@ -99,16 +99,17 @@ XboxVideoInit(VOID) ULONG ScreenHeight; ULONG BytesPerPixel; - /* Reuse framebuffer that was set up by firmware */ + /* Reuse the framebuffer that was set up by firmware */ FrameBuffer = (ULONG_PTR)READ_REGISTER_ULONG(NvBase + NV2A_CRTC_FRAMEBUFFER_START); - /* Verify that framebuffer address is page-aligned */ + TRACE("XBOX framebuffer at 0x%p\n", FrameBuffer); + /* Verify that the framebuffer address is page-aligned */ ASSERT(FrameBuffer % PAGE_SIZE == 0); - /* Obtain framebuffer memory size from multiboot memory map */ + /* Obtain framebuffer memory size from the multiboot memory map */ if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0) { /* Fallback to Cromwell standard which reserves high 4 MB of RAM */ - FrameBufferSize = 4 * 1024 * 1024; + FrameBufferSize = 4 * 1024 * 1024; // See FB_SIZE WARN("Could not detect framebuffer memory size, fallback to 4 MB\n"); } @@ -129,13 +130,18 @@ XboxVideoInit(VOID) /* Verify that screen fits framebuffer size */ ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize); - VidFbInitializeVideo(FrameBuffer, - FrameBufferSize, - ScreenWidth, - ScreenHeight, - ScreenWidth, // PixelsPerScanLine - BytesPerPixel * 8, - NULL); + if (!VidFbInitializeVideo(&FrameBufferData, + FrameBuffer, + FrameBufferSize, + ScreenWidth, + ScreenHeight, + ScreenWidth, + BytesPerPixel * 8, + NULL)) + { + ERR("Couldn't initialize video framebuffer\n"); + return; + } VidFbClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE); } diff --git a/boot/freeldr/freeldr/arch/uefi/uefihw.c b/boot/freeldr/freeldr/arch/uefi/uefihw.c index 9a6d293ef10..584c2a43d7b 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefihw.c +++ b/boot/freeldr/freeldr/arch/uefi/uefihw.c @@ -8,6 +8,7 @@ /* INCLUDES ******************************************************************/ #include +#include "../vidfb.h" #include DBG_DEFAULT_CHANNEL(WARNING); @@ -20,6 +21,11 @@ extern UCHAR PcBiosDiskCount; extern EFI_MEMORY_DESCRIPTOR* EfiMemoryMap; extern UINT32 FreeldrDescCount; +/* From uefivid.c */ +extern ULONG_PTR VramAddress; +extern ULONG VramSize; +extern PCM_FRAMEBUF_DEVICE_DATA FrameBufferData; + BOOLEAN AcpiPresent = FALSE; /* FUNCTIONS *****************************************************************/ @@ -127,6 +133,114 @@ DetectAcpiBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber) } } +static VOID +DetectDisplayController( + _In_ PCONFIGURATION_COMPONENT_DATA BusKey) +{ + PCONFIGURATION_COMPONENT_DATA ControllerKey; + PCM_PARTIAL_RESOURCE_LIST PartialResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; + PCM_FRAMEBUF_DEVICE_DATA FramebufData; + ULONG Size; + + if (!VramAddress || (VramSize == 0) || !FrameBufferData) + return; + + Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors[2]) + sizeof(*FramebufData); + PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST); + if (PartialResourceList == NULL) + { + ERR("Failed to allocate resource descriptor\n"); + return; + } + + /* Initialize resource descriptor */ + RtlZeroMemory(PartialResourceList, Size); + PartialResourceList->Version = 1; + PartialResourceList->Revision = 2; + PartialResourceList->Count = 2; + + /* Set Memory */ + PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; + PartialDescriptor->Type = CmResourceTypeMemory; + PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + PartialDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + PartialDescriptor->u.Memory.Start.QuadPart = VramAddress; + PartialDescriptor->u.Memory.Length = VramSize; + + /* Set framebuffer-specific data */ + PartialDescriptor = &PartialResourceList->PartialDescriptors[1]; + PartialDescriptor->Type = CmResourceTypeDeviceSpecific; + PartialDescriptor->ShareDisposition = CmResourceShareUndetermined; + PartialDescriptor->Flags = 0; + PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(*FramebufData); + + /* Get pointer to framebuffer-specific data */ + FramebufData = (PCM_FRAMEBUF_DEVICE_DATA)(PartialDescriptor + 1); + RtlCopyMemory(FramebufData, FrameBufferData, sizeof(*FrameBufferData)); + FramebufData->Version = 1; + FramebufData->Revision = 3; + FramebufData->VideoClock = 0; // FIXME: Use EDID + + FldrCreateComponentKey(BusKey, + ControllerClass, + DisplayController, + Output | ConsoleOut, + 0, + 0xFFFFFFFF, + "UEFI GOP Framebuffer", + PartialResourceList, + Size, + &ControllerKey); + + // NOTE: Don't add a MonitorPeripheral for now. + // We should use EDID data for it. +} + +static +VOID +DetectInternal(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber) +{ + PCM_PARTIAL_RESOURCE_LIST PartialResourceList; + PCONFIGURATION_COMPONENT_DATA BusKey; + ULONG Size; + + /* Set 'Configuration Data' value */ + Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); + PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST); + if (PartialResourceList == NULL) + { + ERR("Failed to allocate resource descriptor\n"); + return; + } + + /* Initialize resource descriptor */ + RtlZeroMemory(PartialResourceList, Size); + PartialResourceList->Version = 1; + PartialResourceList->Revision = 1; + PartialResourceList->Count = 0; + + /* Create new bus key */ + FldrCreateComponentKey(SystemKey, + AdapterClass, + MultiFunctionAdapter, + 0, + 0, + 0xFFFFFFFF, + "UEFI Internal", + PartialResourceList, + Size, + &BusKey); + + /* Increment bus number */ + (*BusNumber)++; + + /* Detect devices that do not belong to "standard" buses */ + DetectDisplayController(BusKey); + + /* FIXME: Detect more devices */ +} + PCONFIGURATION_COMPONENT_DATA UefiHwDetect( _In_opt_ PCSTR Options) @@ -147,7 +261,9 @@ UefiHwDetect( #error Please define a system key for your architecture #endif - /* Detect ACPI */ + /* Detect buses */ + DetectInternal(SystemKey, &BusNumber); + // TODO: DetectPciBios DetectAcpiBios(SystemKey, &BusNumber); TRACE("DetectHardware() Done\n"); diff --git a/boot/freeldr/freeldr/arch/uefi/uefivid.c b/boot/freeldr/freeldr/arch/uefi/uefivid.c index e00c9e875ef..464b2ab5536 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefivid.c +++ b/boot/freeldr/freeldr/arch/uefi/uefivid.c @@ -17,6 +17,10 @@ extern EFI_SYSTEM_TABLE* GlobalSystemTable; extern EFI_HANDLE GlobalImageHandle; EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +ULONG_PTR VramAddress; +ULONG VramSize; +PCM_FRAMEBUF_DEVICE_DATA FrameBufferData = NULL; + #define LOWEST_SUPPORTED_RES 1 /* FUNCTIONS ******************************************************************/ @@ -51,13 +55,13 @@ static EFI_PIXEL_BITMASK EfiPixelMasks[] = EFI_STATUS UefiInitializeVideo(VOID) { + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL* gop = NULL; + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; EFI_PIXEL_BITMASK* pPixelBitmask; ULONG BitsPerPixel; - EFI_STATUS Status; - EFI_GRAPHICS_OUTPUT_PROTOCOL* gop = NULL; - Status = GlobalSystemTable->BootServices->LocateProtocol(&EfiGraphicsOutputProtocol, 0, (void**)&gop); if (Status != EFI_SUCCESS) { @@ -100,20 +104,27 @@ UefiInitializeVideo(VOID) case PixelBltOnly: default: { - ERR("Unsupported UFEI GOP format %lu\n", PixelFormat); + ERR("Unsupported UEFI GOP format %lu\n", PixelFormat); pPixelBitmask = NULL; BitsPerPixel = 0; break; } } - VidFbInitializeVideo((ULONG_PTR)gop->Mode->FrameBufferBase, - gop->Mode->FrameBufferSize, - gop->Mode->Info->HorizontalResolution, - gop->Mode->Info->VerticalResolution, - gop->Mode->Info->PixelsPerScanLine, - BitsPerPixel, - (PPIXEL_BITMASK)pPixelBitmask); + VramAddress = (ULONG_PTR)gop->Mode->FrameBufferBase; + VramSize = gop->Mode->FrameBufferSize; + if (!VidFbInitializeVideo(&FrameBufferData, + VramAddress, + VramSize, + gop->Mode->Info->HorizontalResolution, + gop->Mode->Info->VerticalResolution, + gop->Mode->Info->PixelsPerScanLine, + BitsPerPixel, + (PPIXEL_BITMASK)pPixelBitmask)) + { + ERR("Couldn't initialize video framebuffer\n"); + Status = EFI_UNSUPPORTED; + } return Status; } diff --git a/boot/freeldr/freeldr/arch/vidfb.c b/boot/freeldr/freeldr/arch/vidfb.c index 8bc616970c9..f8640824f09 100644 --- a/boot/freeldr/freeldr/arch/vidfb.c +++ b/boot/freeldr/freeldr/arch/vidfb.c @@ -3,7 +3,7 @@ * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Video support for linear framebuffers * COPYRIGHT: Authors of uefivid.c and xboxvideo.c - * Copyright 2025 Hermès Bélusca-Maïto + * Copyright 2025-2026 Hermès Bélusca-Maïto */ #include @@ -28,6 +28,7 @@ typedef struct _FRAMEBUFFER_INFO ULONG ScreenWidth; ULONG ScreenHeight; + /* Number of pixel elements per video memory line */ ULONG PixelsPerScanLine; // aka. "Pitch" or "ScreenStride", but Stride is in bytes or bits... ULONG BitsPerPixel; // aka. "PixelStride". @@ -40,7 +41,8 @@ typedef struct _FRAMEBUFFER_INFO ULONG Delta; // aka. "Pitch": actual size in bytes of a scanline. } FRAMEBUFFER_INFO, *PFRAMEBUFFER_INFO; -FRAMEBUFFER_INFO framebufInfo; +static FRAMEBUFFER_INFO framebufInfo = {0}; +static CM_FRAMEBUF_DEVICE_DATA FrameBufferData = {0}; /* FUNCTIONS ******************************************************************/ @@ -95,6 +97,7 @@ VidFbPrintFramebufferInfo(VOID) **/ BOOLEAN VidFbInitializeVideo( + _Out_opt_ PCM_FRAMEBUF_DEVICE_DATA* pFbData, _In_ ULONG_PTR BaseAddress, _In_ ULONG BufferSize, _In_ UINT32 ScreenWidth, @@ -105,8 +108,18 @@ VidFbInitializeVideo( { PPIXEL_BITMASK BitMasks = &framebufInfo.PixelMasks; + if (pFbData) + *pFbData = NULL; + RtlZeroMemory(&framebufInfo, sizeof(framebufInfo)); + /* Verify framebuffer dimensions */ + if ((ScreenWidth < 1) || (ScreenHeight < 1)) + { + ERR("Invalid framebuffer dimensions\n"); + return FALSE; + } + framebufInfo.BaseAddress = BaseAddress; framebufInfo.BufferSize = BufferSize; framebufInfo.ScreenWidth = ScreenWidth; @@ -114,9 +127,17 @@ VidFbInitializeVideo( framebufInfo.PixelsPerScanLine = PixelsPerScanLine; framebufInfo.BitsPerPixel = BitsPerPixel; - framebufInfo.BytesPerPixel = ((BitsPerPixel + 7) & ~7) / 8; // Round up to nearest byte. + framebufInfo.BytesPerPixel = (BitsPerPixel + 7) / 8; // Round up to nearest byte. framebufInfo.Delta = (PixelsPerScanLine * framebufInfo.BytesPerPixel + 3) & ~3; + /* Verify that the framebuffer fits inside the video RAM */ + if (!(ScreenHeight * framebufInfo.Delta <= BufferSize)) + { + ERR("Framebuffer doesn't fit inside the video RAM (FB size: %lu, VRAM size: %lu)\n", + ScreenHeight * framebufInfo.Delta, BufferSize); + return FALSE; + } + /* We currently only support 32bpp */ if (BitsPerPixel != 32) { @@ -187,6 +208,21 @@ VidFbInitializeVideo( } #endif + /* Initialize the hardware device configuration data if specified */ + if (pFbData) + { + FrameBufferData.FrameBufferOffset = 0; + FrameBufferData.ScreenWidth = framebufInfo.ScreenWidth; + FrameBufferData.ScreenHeight = framebufInfo.ScreenHeight; + FrameBufferData.PixelsPerScanLine = framebufInfo.PixelsPerScanLine; + FrameBufferData.BitsPerPixel = framebufInfo.BitsPerPixel; + + RtlCopyMemory(&FrameBufferData.PixelMasks, + &framebufInfo.PixelMasks, sizeof(framebufInfo.PixelMasks)); + + *pFbData = &FrameBufferData; + } + return TRUE; } @@ -336,7 +372,7 @@ VidFbGetPaletteColor( * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * or MIT (https://spdx.org/licenses/MIT) * PURPOSE: Linear framebuffer based console support - * COPYRIGHT: Copyright 2025 Hermès Bélusca-Maïto + * COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto */ #define VGA_CHAR_SIZE 2 diff --git a/boot/freeldr/freeldr/arch/vidfb.h b/boot/freeldr/freeldr/arch/vidfb.h index 1540713b7a8..d90ac88e56d 100644 --- a/boot/freeldr/freeldr/arch/vidfb.h +++ b/boot/freeldr/freeldr/arch/vidfb.h @@ -2,7 +2,7 @@ * PROJECT: FreeLoader * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Video support for linear framebuffers - * COPYRIGHT: Copyright 2025 Hermès Bélusca-Maïto + * COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto */ #pragma once @@ -50,8 +50,10 @@ PixelBitmasksToBpp( return CountNumberOfBits(CompoundMask); // FindHighestSetBit(CompoundMask); } +#include BOOLEAN VidFbInitializeVideo( + _Out_opt_ PCM_FRAMEBUF_DEVICE_DATA* pFbData, _In_ ULONG_PTR BaseAddress, _In_ ULONG BufferSize, _In_ UINT32 ScreenWidth, @@ -115,7 +117,7 @@ VidFbGetPaletteColor( * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * or MIT (https://spdx.org/licenses/MIT) * PURPOSE: Linear framebuffer based console support - * COPYRIGHT: Copyright 2025 Hermès Bélusca-Maïto + * COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto */ #pragma once