[FREELDR:XBOX/UEFI] Unify the XBOX and UEFI linear framebuffer support together (#8509)

CORE-11954, CORE-16216

Here only moving and adjusting existing code has been done.
In the future, this code will be expanded to support other bits-per-pixel
formats and pixel bitmasks, available in UEFI platforms, and be used to
handle bios-based PC VESA framebuffer.
This commit is contained in:
Hermès Bélusca-Maïto
2025-12-19 13:21:23 +01:00
parent 9e64fa837d
commit d1445c8e69
9 changed files with 486 additions and 294 deletions
@@ -24,14 +24,13 @@ DBG_DEFAULT_CHANNEL(HWDETECT);
#define MAX_XBOX_COM_PORTS 2
extern PVOID FrameBuffer;
extern ULONG_PTR FrameBuffer;
extern ULONG FrameBufferSize;
BOOLEAN
XboxFindPciBios(PPCI_REGISTRY_INFO BusData)
{
/* We emulate PCI BIOS here, there are 2 known working PCI buses on an original Xbox */
BusData->NoBuses = 2;
BusData->MajorRevision = 1;
BusData->MinorRevision = 0;
@@ -181,7 +180,7 @@ DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
PartialDescriptor->Type = CmResourceTypeMemory;
PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
PartialDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
PartialDescriptor->u.Memory.Start.LowPart = (ULONG_PTR)FrameBuffer & 0x0FFFFFFF;
PartialDescriptor->u.Memory.Start.LowPart = (FrameBuffer & 0x0FFFFFFF);
PartialDescriptor->u.Memory.Length = FrameBufferSize;
FldrCreateComponentKey(BusKey,
@@ -20,15 +20,15 @@
*/
#include <freeldr.h>
#include <debug.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(MEMORY);
static ULONG InstalledMemoryMb = 0;
static ULONG AvailableMemoryMb = 0;
extern multiboot_info_t * MultibootInfoPtr;
extern ULONG NvBase;
extern PVOID FrameBuffer;
extern ULONG_PTR FrameBuffer;
extern ULONG FrameBufferSize;
#define TEST_SIZE 0x200
@@ -267,7 +267,7 @@ XboxMemGetMemoryMap(ULONG *MemoryMapSize)
{
/* Video memory */
ReserveMemory(XboxMemoryMap,
(ULONG_PTR)FrameBuffer,
FrameBuffer,
FrameBufferSize,
LoaderFirmwarePermanent,
"Video memory");
+60 -155
View File
@@ -20,148 +20,58 @@
*/
#include <freeldr.h>
#include "../../vgafont.h"
#include "../../vidfb.h"
#include <debug.h>
DBG_DEFAULT_CHANNEL(UI);
ULONG NvBase = 0xFD000000;
PVOID FrameBuffer;
ULONG_PTR FrameBuffer;
ULONG FrameBufferSize;
static ULONG ScreenWidth;
static ULONG ScreenHeight;
static ULONG BytesPerPixel;
static ULONG Delta;
extern multiboot_info_t * MultibootInfoPtr;
#define FB_SIZE_MB 4
UCHAR MachDefaultTextColor = COLOR_GRAY;
#define TOP_BOTTOM_LINES 0
#define FB_SIZE_MB 4
#define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) | (((Green) & 0xff) << 8) | ((Blue) & 0xff))
static VOID
XboxVideoOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
{
const UCHAR* FontPtr;
PULONG Pixel;
UCHAR Mask;
unsigned Line;
unsigned Col;
FontPtr = BitmapFont8x16 + Char * CHAR_HEIGHT;
Pixel = (PULONG) ((char *) FrameBuffer + (Y * CHAR_HEIGHT + TOP_BOTTOM_LINES) * Delta
+ X * CHAR_WIDTH * BytesPerPixel);
for (Line = 0; Line < CHAR_HEIGHT; Line++)
{
Mask = 0x80;
for (Col = 0; Col < CHAR_WIDTH; Col++)
{
Pixel[Col] = (0 != (FontPtr[Line] & Mask) ? FgColor : BgColor);
Mask = Mask >> 1;
}
Pixel = (PULONG) ((char *) Pixel + Delta);
}
}
static ULONG
XboxVideoAttrToSingleColor(UCHAR Attr)
{
UCHAR Intensity;
Intensity = (0 == (Attr & 0x08) ? 127 : 255);
return 0xff000000 |
(0 == (Attr & 0x04) ? 0 : (Intensity << 16)) |
(0 == (Attr & 0x02) ? 0 : (Intensity << 8)) |
(0 == (Attr & 0x01) ? 0 : Intensity);
}
static VOID
XboxVideoAttrToColors(UCHAR Attr, ULONG *FgColor, ULONG *BgColor)
{
*FgColor = XboxVideoAttrToSingleColor(Attr & 0xf);
*BgColor = XboxVideoAttrToSingleColor((Attr >> 4) & 0xf);
}
static VOID
XboxVideoClearScreenColor(ULONG Color, BOOLEAN FullScreen)
{
ULONG Line, Col;
PULONG p;
for (Line = 0; Line < ScreenHeight - (FullScreen ? 0 : 2 * TOP_BOTTOM_LINES); Line++)
{
p = (PULONG) ((char *) FrameBuffer + (Line + (FullScreen ? 0 : TOP_BOTTOM_LINES)) * Delta);
for (Col = 0; Col < ScreenWidth; Col++)
{
*p++ = Color;
}
}
}
VOID
XboxVideoScrollUp(VOID)
{
ULONG BgColor, Dummy;
ULONG PixelCount = ScreenWidth * CHAR_HEIGHT *
(((ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT) - 1);
PULONG Src = (PULONG)((PUCHAR)FrameBuffer + (CHAR_HEIGHT + TOP_BOTTOM_LINES) * Delta);
PULONG Dst = (PULONG)((PUCHAR)FrameBuffer + TOP_BOTTOM_LINES * Delta);
XboxVideoAttrToColors(ATTR(COLOR_WHITE, COLOR_BLACK), &Dummy, &BgColor);
while (PixelCount--)
*Dst++ = *Src++;
for (PixelCount = 0; PixelCount < ScreenWidth * CHAR_HEIGHT; PixelCount++)
*Dst++ = BgColor;
VidFbScrollUp();
}
VOID
XboxVideoClearScreen(UCHAR Attr)
{
ULONG FgColor, BgColor;
XboxVideoAttrToColors(Attr, &FgColor, &BgColor);
XboxVideoClearScreenColor(BgColor, FALSE);
VidFbClearScreen(Attr);
}
VOID
XboxVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
{
ULONG FgColor, BgColor;
XboxVideoAttrToColors(Attr, &FgColor, &BgColor);
XboxVideoOutputChar(Ch, X, Y, FgColor, BgColor);
VidFbPutChar(Ch, Attr, X, Y);
}
UCHAR
static UCHAR
NvGetCrtc(UCHAR Index)
{
WRITE_REGISTER_UCHAR(NvBase + NV2A_CRTC_REGISTER_INDEX, Index);
return READ_REGISTER_UCHAR(NvBase + NV2A_CRTC_REGISTER_VALUE);
}
ULONG
XboxGetFramebufferSize(PVOID Offset)
static ULONG
XboxGetFramebufferSize(
_In_ ULONG_PTR Offset)
{
memory_map_t * MemoryMap;
INT Count, i;
if (!MultibootInfoPtr)
{
return 0;
}
if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
{
return 0;
}
MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
@@ -180,7 +90,7 @@ XboxGetFramebufferSize(PVOID Offset)
/* Framebuffer address offset value is coming from the GPU within
* memory mapped I/O address space, so we're comparing only low
* 28 bits of the address within actual RAM address space */
if (MemoryMap->base_addr_low == ((ULONG)Offset & 0x0FFFFFFF) && MemoryMap->base_addr_high == 0)
if (MemoryMap->base_addr_low == (Offset & 0x0FFFFFFF) && MemoryMap->base_addr_high == 0)
{
TRACE("Video memory found\n");
return MemoryMap->length_low;
@@ -193,62 +103,67 @@ XboxGetFramebufferSize(PVOID Offset)
VOID
XboxVideoInit(VOID)
{
/* Reuse framebuffer that was set up by firmware */
FrameBuffer = (PVOID)READ_REGISTER_ULONG(NvBase + NV2A_CRTC_FRAMEBUFFER_START);
/* Verify that framebuffer address is page-aligned */
ASSERT((ULONG_PTR)FrameBuffer % PAGE_SIZE == 0);
ULONG ScreenWidth;
ULONG ScreenHeight;
ULONG BytesPerPixel;
/* Obtain framebuffer memory size from multiboot memory map */
if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0)
{
/* Fallback to Cromwell standard which reserves high 4 MB of RAM */
FrameBufferSize = 4 * 1024 * 1024;
WARN("Could not detect framebuffer memory size, fallback to 4 MB\n");
}
/* Reuse 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 */
ASSERT(FrameBuffer % PAGE_SIZE == 0);
ScreenWidth = READ_REGISTER_ULONG(NvBase + NV2A_RAMDAC_FP_HVALID_END) + 1;
ScreenHeight = READ_REGISTER_ULONG(NvBase + NV2A_RAMDAC_FP_VVALID_END) + 1;
/* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
BytesPerPixel = 8 * (((NvGetCrtc(0x19) & 0xE0) << 3) | (NvGetCrtc(0x13) & 0xFF)) / ScreenWidth;
if (BytesPerPixel == 4)
{
ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel - 1);
}
else
{
ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel);
}
Delta = (ScreenWidth * BytesPerPixel + 3) & ~ 0x3;
/* Obtain framebuffer memory size from multiboot memory map */
if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0)
{
/* Fallback to Cromwell standard which reserves high 4 MB of RAM */
FrameBufferSize = 4 * 1024 * 1024;
WARN("Could not detect framebuffer memory size, fallback to 4 MB\n");
}
/* Verify screen resolution */
ASSERT(ScreenWidth > 1);
ASSERT(ScreenHeight > 1);
ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
/* Verify that screen fits framebuffer size */
ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize);
ScreenWidth = READ_REGISTER_ULONG(NvBase + NV2A_RAMDAC_FP_HVALID_END) + 1;
ScreenHeight = READ_REGISTER_ULONG(NvBase + NV2A_RAMDAC_FP_VVALID_END) + 1;
XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
/* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
BytesPerPixel = 8 * (((NvGetCrtc(0x19) & 0xE0) << 3) | (NvGetCrtc(0x13) & 0xFF)) / ScreenWidth;
if (BytesPerPixel == 4)
ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel - 1);
else
ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel);
/* Verify screen resolution */
ASSERT(ScreenWidth > 1);
ASSERT(ScreenHeight > 1);
ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
/* Verify that screen fits framebuffer size */
ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize);
VidFbInitializeVideo(FrameBuffer,
FrameBufferSize,
ScreenWidth,
ScreenHeight,
ScreenWidth, // PixelsPerScanLine
BytesPerPixel * 8);
VidFbClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
}
VIDEODISPLAYMODE
XboxVideoSetDisplayMode(PCSTR DisplayMode, BOOLEAN Init)
{
/* We only have one mode, semi-text */
return VideoTextMode;
/* We only have one mode, semi-text */
return VideoTextMode;
}
VOID
XboxVideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth)
{
*Width = ScreenWidth / CHAR_WIDTH;
*Height = (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT;
*Depth = 0;
VidFbGetDisplaySize(Width, Height, Depth);
}
ULONG
XboxVideoGetBufferSize(VOID)
{
return (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT * (ScreenWidth / CHAR_WIDTH) * 2;
return VidFbGetBufferSize();
}
VOID
@@ -260,47 +175,37 @@ XboxVideoGetFontsFromFirmware(PULONG RomFontPointers)
VOID
XboxVideoSetTextCursorPosition(UCHAR X, UCHAR Y)
{
/* We don't have a cursor yet */
/* We don't have a cursor yet */
}
VOID
XboxVideoHideShowTextCursor(BOOLEAN Show)
{
/* We don't have a cursor yet */
/* We don't have a cursor yet */
}
VOID
XboxVideoCopyOffScreenBufferToVRAM(PVOID Buffer)
{
PUCHAR OffScreenBuffer = (PUCHAR) Buffer;
ULONG Col, Line;
for (Line = 0; Line < (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT; Line++)
{
for (Col = 0; Col < ScreenWidth / CHAR_WIDTH; Col++)
{
XboxVideoPutChar(OffScreenBuffer[0], OffScreenBuffer[1], Col, Line);
OffScreenBuffer += 2;
}
}
VidFbCopyOffScreenBufferToVRAM(Buffer);
}
BOOLEAN
XboxVideoIsPaletteFixed(VOID)
{
return FALSE;
return FALSE;
}
VOID
XboxVideoSetPaletteColor(UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue)
{
/* Not supported */
/* Not supported */
}
VOID
XboxVideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue)
{
/* Not supported */
/* Not supported */
}
VOID
@@ -312,7 +217,7 @@ XboxVideoSync(VOID)
VOID
XboxVideoPrepareForReactOS(VOID)
{
XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
VidFbClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
XboxVideoHideShowTextCursor(FALSE);
}
+37 -127
View File
@@ -6,13 +6,10 @@
*/
#include <uefildr.h>
#include "../vgafont.h"
#include "../vidfb.h"
#include <debug.h>
DBG_DEFAULT_CHANNEL(WARNING);
#define TOP_BOTTOM_LINES 0
#define LOWEST_SUPPORTED_RES 1
DBG_DEFAULT_CHANNEL(UI);
/* GLOBALS ********************************************************************/
@@ -20,18 +17,21 @@ extern EFI_SYSTEM_TABLE* GlobalSystemTable;
extern EFI_HANDLE GlobalImageHandle;
UCHAR MachDefaultTextColor = COLOR_GRAY;
REACTOS_INTERNAL_BGCONTEXT framebufferData;
EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
#define LOWEST_SUPPORTED_RES 1
/* FUNCTIONS ******************************************************************/
EFI_STATUS
UefiInitializeVideo(VOID)
{
EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
ULONG BitsPerPixel;
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop = NULL;
RtlZeroMemory(&framebufferData, sizeof(framebufferData));
Status = GlobalSystemTable->BootServices->LocateProtocol(&EfiGraphicsOutputProtocol, 0, (void**)&gop);
if (Status != EFI_SUCCESS)
{
@@ -42,118 +42,52 @@ UefiInitializeVideo(VOID)
/* We don't need high resolutions for freeldr */
gop->SetMode(gop, LOWEST_SUPPORTED_RES);
framebufferData.BaseAddress = (ULONG_PTR)gop->Mode->FrameBufferBase;
framebufferData.BufferSize = gop->Mode->FrameBufferSize;
framebufferData.ScreenWidth = gop->Mode->Info->HorizontalResolution;
framebufferData.ScreenHeight = gop->Mode->Info->VerticalResolution;
framebufferData.PixelsPerScanLine = gop->Mode->Info->PixelsPerScanLine;
framebufferData.PixelFormat = gop->Mode->Info->PixelFormat;
return Status;
}
VOID
UefiPrintFramebufferData(VOID)
{
TRACE("Framebuffer BaseAddress : %X\n", framebufferData.BaseAddress);
TRACE("Framebuffer BufferSize : %X\n", framebufferData.BufferSize);
TRACE("Framebuffer ScreenWidth : %d\n", framebufferData.ScreenWidth);
TRACE("Framebuffer ScreenHeight : %d\n", framebufferData.ScreenHeight);
TRACE("Framebuffer PixelsPerScanLine : %d\n", framebufferData.PixelsPerScanLine);
TRACE("Framebuffer PixelFormat : %d\n", framebufferData.PixelFormat);
}
static ULONG
UefiVideoAttrToSingleColor(UCHAR Attr)
{
UCHAR Intensity;
Intensity = (0 == (Attr & 0x08) ? 127 : 255);
return 0xff000000 |
(0 == (Attr & 0x04) ? 0 : (Intensity << 16)) |
(0 == (Attr & 0x02) ? 0 : (Intensity << 8)) |
(0 == (Attr & 0x01) ? 0 : Intensity);
}
static VOID
UefiVideoAttrToColors(UCHAR Attr, ULONG *FgColor, ULONG *BgColor)
{
*FgColor = UefiVideoAttrToSingleColor(Attr & 0xf);
*BgColor = UefiVideoAttrToSingleColor((Attr >> 4) & 0xf);
}
static VOID
UefiVideoClearScreenColor(ULONG Color, BOOLEAN FullScreen)
{
ULONG Delta;
ULONG Line, Col;
PULONG p;
Delta = (framebufferData.PixelsPerScanLine * 4 + 3) & ~ 0x3;
for (Line = 0; Line < framebufferData.ScreenHeight - (FullScreen ? 0 : 2 * TOP_BOTTOM_LINES); Line++)
/* Physical format of the pixel */
PixelFormat = gop->Mode->Info->PixelFormat;
switch (PixelFormat)
{
p = (PULONG) ((char *) framebufferData.BaseAddress + (Line + (FullScreen ? 0 : TOP_BOTTOM_LINES)) * Delta);
for (Col = 0; Col < framebufferData.ScreenWidth; Col++)
case PixelRedGreenBlueReserved8BitPerColor:
case PixelBlueGreenRedReserved8BitPerColor:
{
*p++ = Color;
BitsPerPixel = RTL_BITS_OF(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
break;
}
case PixelBitMask:
case PixelBltOnly:
default:
{
ERR("Unsupported UFEI GOP format %lu\n", PixelFormat);
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);
return Status;
}
VOID
UefiVideoClearScreen(UCHAR Attr)
{
ULONG FgColor, BgColor;
UefiVideoAttrToColors(Attr, &FgColor, &BgColor);
UefiVideoClearScreenColor(BgColor, FALSE);
}
VOID
UefiVideoOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
{
const UCHAR* FontPtr;
PULONG Pixel;
UCHAR Mask;
unsigned Line;
unsigned Col;
ULONG Delta;
Delta = (framebufferData.PixelsPerScanLine * 4 + 3) & ~ 0x3;
FontPtr = BitmapFont8x16 + Char * CHAR_HEIGHT;
Pixel = (PULONG) ((char *) framebufferData.BaseAddress +
(Y * CHAR_HEIGHT + TOP_BOTTOM_LINES) * Delta + X * CHAR_WIDTH * 4);
for (Line = 0; Line < CHAR_HEIGHT; Line++)
{
Mask = 0x80;
for (Col = 0; Col < CHAR_WIDTH; Col++)
{
Pixel[Col] = (0 != (FontPtr[Line] & Mask) ? FgColor : BgColor);
Mask = Mask >> 1;
}
Pixel = (PULONG) ((char *) Pixel + Delta);
}
VidFbClearScreen(Attr);
}
VOID
UefiVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
{
ULONG FgColor = 0;
ULONG BgColor = 0;
if (Ch != 0)
{
UefiVideoAttrToColors(Attr, &FgColor, &BgColor);
UefiVideoOutputChar(Ch, X, Y, FgColor, BgColor);
}
VidFbPutChar(Ch, Attr, X, Y);
}
VOID
UefiVideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth)
{
*Width = framebufferData.ScreenWidth / CHAR_WIDTH;
*Height = (framebufferData.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT;
*Depth = 0;
VidFbGetDisplaySize(Width, Height, Depth);
}
VIDEODISPLAYMODE
@@ -166,43 +100,19 @@ UefiVideoSetDisplayMode(PCSTR DisplayMode, BOOLEAN Init)
ULONG
UefiVideoGetBufferSize(VOID)
{
return ((framebufferData.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT * (framebufferData.ScreenWidth / CHAR_WIDTH) * 2);
return VidFbGetBufferSize();
}
VOID
UefiVideoCopyOffScreenBufferToVRAM(PVOID Buffer)
{
PUCHAR OffScreenBuffer = (PUCHAR)Buffer;
ULONG Col, Line;
for (Line = 0; Line < (framebufferData.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT; Line++)
{
for (Col = 0; Col < framebufferData.ScreenWidth / CHAR_WIDTH; Col++)
{
UefiVideoPutChar(OffScreenBuffer[0], OffScreenBuffer[1], Col, Line);
OffScreenBuffer += 2;
}
}
VidFbCopyOffScreenBufferToVRAM(Buffer);
}
VOID
UefiVideoScrollUp(VOID)
{
ULONG BgColor, Dummy;
ULONG Delta;
Delta = (framebufferData.PixelsPerScanLine * 4 + 3) & ~ 0x3;
ULONG PixelCount = framebufferData.ScreenWidth * CHAR_HEIGHT *
(((framebufferData.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT) - 1);
PULONG Src = (PULONG)((PUCHAR)framebufferData.BaseAddress + (CHAR_HEIGHT + TOP_BOTTOM_LINES) * Delta);
PULONG Dst = (PULONG)((PUCHAR)framebufferData.BaseAddress + TOP_BOTTOM_LINES * Delta);
UefiVideoAttrToColors(ATTR(COLOR_WHITE, COLOR_BLACK), &Dummy, &BgColor);
while (PixelCount--)
*Dst++ = *Src++;
for (PixelCount = 0; PixelCount < framebufferData.ScreenWidth * CHAR_HEIGHT; PixelCount++)
*Dst++ = BgColor;
VidFbScrollUp();
}
VOID
+301
View File
@@ -0,0 +1,301 @@
/*
* PROJECT: FreeLoader
* 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 <[email protected]>
*/
#include <freeldr.h>
#include "vidfb.h"
#include "vgafont.h"
#include <debug.h>
DBG_DEFAULT_CHANNEL(UI);
#define VGA_CHAR_SIZE 2
/* This is used to introduce artificial symmetric borders at the top and bottom */
#define TOP_BOTTOM_LINES 0
/* GLOBALS ********************************************************************/
typedef struct _FRAMEBUFFER_INFO
{
ULONG_PTR BaseAddress;
ULONG BufferSize;
/* Horizontal and Vertical resolution in pixels */
ULONG ScreenWidth;
ULONG ScreenHeight;
ULONG PixelsPerScanLine; // aka. "Pitch" or "ScreenStride", but Stride is in bytes or bits...
ULONG BitsPerPixel; // aka. "PixelStride".
/** Calculated values */
ULONG BytesPerPixel;
ULONG Delta; // aka. "Pitch": actual size in bytes of a scanline.
} FRAMEBUFFER_INFO, *PFRAMEBUFFER_INFO;
FRAMEBUFFER_INFO framebufInfo;
/* FUNCTIONS ******************************************************************/
#if DBG
static VOID
VidFbPrintFramebufferInfo(VOID)
{
TRACE("Framebuffer format:\n");
TRACE(" BaseAddress : 0x%X\n", framebufInfo.BaseAddress);
TRACE(" BufferSize : %lu\n", framebufInfo.BufferSize);
TRACE(" ScreenWidth : %lu\n", framebufInfo.ScreenWidth);
TRACE(" ScreenHeight : %lu\n", framebufInfo.ScreenHeight);
TRACE(" PixelsPerScanLine : %lu\n", framebufInfo.PixelsPerScanLine);
TRACE(" BitsPerPixel : %lu\n", framebufInfo.BitsPerPixel);
TRACE(" BytesPerPixel : %lu\n", framebufInfo.BytesPerPixel);
TRACE(" Delta : %lu\n", framebufInfo.Delta);
}
#endif
/**
* @brief
* Initializes internal framebuffer data based on the given parameters.
*
* @param[in] BaseAddress
* The framebuffer physical base address.
*
* @param[in] BufferSize
* The framebuffer size, in bytes.
*
* @param[in] ScreenWidth
* @param[in] ScreenHeight
* The width and height of the visible framebuffer area, in pixels.
*
* @param[in] PixelsPerScanLine
* The size in number of pixels of a whole horizontal video memory scanline.
*
* @param[in] BitsPerPixel
* The number of usable bits (not counting the reserved ones) per pixel.
*
* @return
* TRUE if initialization is successful; FALSE if not.
**/
BOOLEAN
VidFbInitializeVideo(
_In_ ULONG_PTR BaseAddress,
_In_ ULONG BufferSize,
_In_ UINT32 ScreenWidth,
_In_ UINT32 ScreenHeight,
_In_ UINT32 PixelsPerScanLine,
_In_ UINT32 BitsPerPixel)
{
RtlZeroMemory(&framebufInfo, sizeof(framebufInfo));
framebufInfo.BaseAddress = BaseAddress;
framebufInfo.BufferSize = BufferSize;
framebufInfo.ScreenWidth = ScreenWidth;
framebufInfo.ScreenHeight = ScreenHeight;
framebufInfo.PixelsPerScanLine = PixelsPerScanLine;
framebufInfo.BitsPerPixel = BitsPerPixel;
framebufInfo.BytesPerPixel = ((BitsPerPixel + 7) & ~7) / 8; // Round up to nearest byte.
framebufInfo.Delta = (PixelsPerScanLine * framebufInfo.BytesPerPixel + 3) & ~3;
/* We currently only support 32bpp */
if (BitsPerPixel != 32)
{
/* Unsupported BPP */
ERR("Unsupported %lu bits per pixel format\n", BitsPerPixel);
return FALSE;
}
#if DBG
VidFbPrintFramebufferInfo();
#endif
return TRUE;
}
static inline
UINT32
VidFbAttrToSingleColor(
_In_ UCHAR Attr)
{
UCHAR Intensity;
Intensity = (0 == (Attr & 0x08) ? 127 : 255);
return 0xff000000 |
(0 == (Attr & 0x04) ? 0 : (Intensity << 16)) |
(0 == (Attr & 0x02) ? 0 : (Intensity << 8)) |
(0 == (Attr & 0x01) ? 0 : Intensity);
}
static VOID
VidFbAttrToColors(
_In_ UCHAR Attr,
_Out_ PUINT32 FgColor,
_Out_ PUINT32 BgColor)
{
*FgColor = VidFbAttrToSingleColor(Attr & 0x0F);
*BgColor = VidFbAttrToSingleColor((Attr >> 4) & 0x0F);
}
VOID
VidFbClearScreenColor(
_In_ UINT32 Color,
_In_ BOOLEAN FullScreen)
{
ULONG Line, Col;
PUINT32 p;
for (Line = 0; Line < framebufInfo.ScreenHeight - (FullScreen ? 0 : 2 * TOP_BOTTOM_LINES); Line++)
{
p = (PUINT32)((PUCHAR)framebufInfo.BaseAddress + (Line + (FullScreen ? 0 : TOP_BOTTOM_LINES)) * framebufInfo.Delta);
for (Col = 0; Col < framebufInfo.ScreenWidth; Col++)
{
*p++ = Color;
}
}
}
VOID
VidFbClearScreen(
_In_ UCHAR Attr)
{
UINT32 FgColor, BgColor;
VidFbAttrToColors(Attr, &FgColor, &BgColor);
VidFbClearScreenColor(BgColor, FALSE);
}
VOID
VidFbOutputChar(
_In_ UCHAR Char,
_In_ ULONG X,
_In_ ULONG Y,
_In_ UINT32 FgColor,
_In_ UINT32 BgColor)
{
const UCHAR* FontPtr;
PUINT32 Pixel;
UCHAR Mask;
ULONG Line, Col;
FontPtr = BitmapFont8x16 + Char * CHAR_HEIGHT;
Pixel = (PUINT32)((PUCHAR)framebufInfo.BaseAddress +
(Y * CHAR_HEIGHT + TOP_BOTTOM_LINES) * framebufInfo.Delta + X * CHAR_WIDTH * 4);
for (Line = 0; Line < CHAR_HEIGHT; Line++)
{
Mask = 0x80;
for (Col = 0; Col < CHAR_WIDTH; Col++)
{
Pixel[Col] = (0 != (FontPtr[Line] & Mask) ? FgColor : BgColor);
Mask = Mask >> 1;
}
Pixel = (PUINT32)((PUCHAR)Pixel + framebufInfo.Delta);
}
}
VOID
VidFbPutChar(
_In_ UCHAR Char,
_In_ UCHAR Attr,
_In_ ULONG X,
_In_ ULONG Y)
{
UINT32 FgColor, BgColor;
VidFbAttrToColors(Attr, &FgColor, &BgColor);
VidFbOutputChar(Char, X, Y, FgColor, BgColor);
}
VOID
VidFbGetDisplaySize(
_Out_ PULONG Width,
_Out_ PULONG Height,
_Out_ PULONG Depth)
{
*Width = framebufInfo.ScreenWidth / CHAR_WIDTH;
*Height = (framebufInfo.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT;
*Depth = framebufInfo.BitsPerPixel;
}
ULONG
VidFbGetBufferSize(VOID)
{
return ((framebufInfo.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT *
(framebufInfo.ScreenWidth / CHAR_WIDTH) * VGA_CHAR_SIZE);
}
VOID
VidFbCopyOffScreenBufferToVRAM(
_In_ PVOID Buffer)
{
PUCHAR OffScreenBuffer = (PUCHAR)Buffer;
ULONG Line, Col;
for (Line = 0; Line < (framebufInfo.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT; Line++)
{
for (Col = 0; Col < framebufInfo.ScreenWidth / CHAR_WIDTH; Col++)
{
VidFbPutChar(OffScreenBuffer[0], OffScreenBuffer[1], Col, Line);
OffScreenBuffer += VGA_CHAR_SIZE;
}
}
}
VOID
VidFbScrollUp(VOID)
{
UINT32 BgColor, Dummy;
ULONG PixelCount = framebufInfo.ScreenWidth * CHAR_HEIGHT *
(((framebufInfo.ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT) - 1);
PUINT32 Src = (PUINT32)((PUCHAR)framebufInfo.BaseAddress + (CHAR_HEIGHT + TOP_BOTTOM_LINES) * framebufInfo.Delta);
PUINT32 Dst = (PUINT32)((PUCHAR)framebufInfo.BaseAddress + TOP_BOTTOM_LINES * framebufInfo.Delta);
VidFbAttrToColors(ATTR(COLOR_WHITE, COLOR_BLACK), &Dummy, &BgColor);
while (PixelCount--)
*Dst++ = *Src++;
for (PixelCount = 0; PixelCount < framebufInfo.ScreenWidth * CHAR_HEIGHT; PixelCount++)
*Dst++ = BgColor;
}
#if 0
VOID
VidFbSetTextCursorPosition(UCHAR X, UCHAR Y)
{
/* We don't have a cursor yet */
}
VOID
VidFbHideShowTextCursor(BOOLEAN Show)
{
/* We don't have a cursor yet */
}
BOOLEAN
VidFbIsPaletteFixed(VOID)
{
return FALSE;
}
VOID
VidFbSetPaletteColor(
_In_ UCHAR Color,
_In_ UCHAR Red, _In_ UCHAR Green, _In_ UCHAR Blue)
{
/* Not supported */
}
VOID
VidFbGetPaletteColor(
_In_ UCHAR Color,
_Out_ PUCHAR Red, _Out_ PUCHAR Green, _Out_ PUCHAR Blue)
{
/* Not supported */
}
#endif
+78
View File
@@ -0,0 +1,78 @@
/*
* 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 <[email protected]>
*/
#pragma once
BOOLEAN
VidFbInitializeVideo(
_In_ ULONG_PTR BaseAddress,
_In_ ULONG BufferSize,
_In_ UINT32 ScreenWidth,
_In_ UINT32 ScreenHeight,
_In_ UINT32 PixelsPerScanLine,
_In_ UINT32 BitsPerPixel);
VOID
VidFbClearScreenColor(
_In_ UINT32 Color,
_In_ BOOLEAN FullScreen);
VOID
VidFbClearScreen(
_In_ UCHAR Attr);
VOID
VidFbOutputChar(
_In_ UCHAR Char,
_In_ ULONG X,
_In_ ULONG Y,
_In_ UINT32 FgColor,
_In_ UINT32 BgColor);
VOID
VidFbPutChar(
_In_ UCHAR Char,
_In_ UCHAR Attr,
_In_ ULONG X,
_In_ ULONG Y);
VOID
VidFbGetDisplaySize(
_Out_ PULONG Width,
_Out_ PULONG Height,
_Out_ PULONG Depth);
ULONG
VidFbGetBufferSize(VOID);
VOID
VidFbCopyOffScreenBufferToVRAM(
_In_ PVOID Buffer);
VOID
VidFbScrollUp(VOID);
#if 0
VOID
VidFbSetTextCursorPosition(UCHAR X, UCHAR Y);
VOID
VidFbHideShowTextCursor(BOOLEAN Show);
BOOLEAN
VidFbIsPaletteFixed(VOID);
VOID
VidFbSetPaletteColor(
_In_ UCHAR Color,
_In_ UCHAR Red, _In_ UCHAR Green, _In_ UCHAR Blue);
VOID
VidFbGetPaletteColor(
_In_ UCHAR Color,
_Out_ PUCHAR Red, _Out_ PUCHAR Green, _Out_ PUCHAR Blue);
#endif
+4
View File
@@ -58,6 +58,10 @@ if(ARCH STREQUAL "i386")
# arch/i386/i386bug.c
arch/i386/i386idt.c)
if(SARCH STREQUAL "xbox")
list(APPEND PCATLDR_ARC_SOURCE
arch/vidfb.c)
endif()
if(SARCH STREQUAL "pc98" OR SARCH STREQUAL "xbox")
# These machine types require built-in bitmap font
list(APPEND PCATLDR_ARC_SOURCE
-6
View File
@@ -35,12 +35,6 @@ if(ARCH STREQUAL "i386")
ntldr/arch/i386/winldr.c
ntldr/headless.c)
if(SARCH STREQUAL "pc98" OR SARCH STREQUAL "xbox")
# These machine types require built-in bitmap font
list(APPEND ROSLOAD_SOURCE
arch/vgafont.c)
endif()
list(APPEND ROSLOAD_ASM_SOURCE
arch/i386/drvmap.S
arch/i386/linux.S)
+1
View File
@@ -21,6 +21,7 @@ list(APPEND UEFILDR_ARC_SOURCE
arch/uefi/uefisetup.c
arch/uefi/uefiutil.c
arch/uefi/uefivid.c
arch/vidfb.c
arch/vgafont.c)
if(ARCH STREQUAL "i386")