[FREELDR:XBOX/UEFI] Enumerate video framebuffer information in the Hardware Configuration Tree (#8617)

- UEFI: Report GOP framebuffer information.
- UEFI: Update ARC versioning for configuration data.
- XBOX: Enumerate video display controller under the correct PCI bus.
- XBOX: Update ARC versioning for display controller configuration data.
This commit is contained in:
Hermès Bélusca-Maïto
2023-06-05 13:33:58 +02:00
parent f21d692342
commit 00bbac600e
6 changed files with 274 additions and 38 deletions

View File

@@ -18,14 +18,18 @@
#include <freeldr.h>
#include <drivers/xbox/superio.h>
#include "../../vidfb.h"
#include <debug.h>
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;
}

View File

@@ -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);
}

View File

@@ -8,6 +8,7 @@
/* INCLUDES ******************************************************************/
#include <uefildr.h>
#include "../vidfb.h"
#include <debug.h>
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");

View File

@@ -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;
}

View File

@@ -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 <hermes.belusca-maito@reactos.org>
* Copyright 2025-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#include <freeldr.h>
@@ -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 <hermes.belusca-maito@reactos.org>
* COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#define VGA_CHAR_SIZE 2

View File

@@ -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 <hermes.belusca-maito@reactos.org>
* COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#pragma once
@@ -50,8 +50,10 @@ PixelBitmasksToBpp(
return CountNumberOfBits(CompoundMask); // FindHighestSetBit(CompoundMask);
}
#include <drivers/bootvid/framebuf.h>
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 <hermes.belusca-maito@reactos.org>
* COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#pragma once