/*++
CsmVideo.efi -- UEFI CSM Compatibility Video Driver
Source: AmiModulePkg/CSM/CsmVideo/
UefiBiosVideo.c -- Main driver: VESA VBE BIOS emulation, GOP, EDID
VgaClass.c -- VGA text mode class (INT10 BIOS text services)
Driver entry:
_ModuleEntryPoint (0x390) -> sub_3F64 (Get HOB list) -> CsmVideoDriverEntry (0x44C)
Installs Legacy8259, LegacyBiosService, UGA protocols on ImageHandle
Installs EDID_ACTIVE on child Handle
Connects LegacyBiosPlatform protocol
Device lifecycle:
CsmVideoChildInit (0x7A0) -> CsmVideoInstanceCreate (0xCE0):
Alloc CSM_VIDEO_INSTANCE (264 bytes, sig 0x705A6642 "BfZp")
Detect VGA vs VESA
If VESA: VesaEnumerateModes -> VesaGetControllerCapabilities -> EdidParseAndMerge -> AllocateVideoBuffers
If legacy text: VgaClassConstructor -> install LegacyBios protocol
GOP callbacks:
QueryMode -> sub_21AC
SetMode -> sub_24AC
VGA class vtable (144 bytes, sig 0x434A5678 "VgJC"):
Init(0x10), StringOutput(0x18), TestString(0x20), Clear(0x28),
SetAttr(0x30), SetCursor(0x38), EnableCursor(0x40), QueryMode(0x48), SetMode(0x50)
--*/
#include "CsmVideo.h"
//
// Forward declarations from CsmVideo.h / library code
//
EFI_BOOT_SERVICES *gBS;
EFI_SYSTEM_TABLE *gST;
EFI_RUNTIME_SERVICES *gRT;
EFI_HANDLE gImageHandle;
// ========================================================================
// _ModuleEntryPoint @ 0x390
// ========================================================================
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
HobGetHobList ();
return CsmVideoDriverEntry (ImageHandle, SystemTable);
}
// ========================================================================
// CsmVideoDriverEntry @ 0x44C
// ========================================================================
EFI_STATUS
CsmVideoDriverEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_HANDLE ChildHandle = NULL;
EFI_STATUS Status;
//
// Install protocols on ImageHandle:
// - Legacy8259 protocol
// - LegacyBiosService protocol
// - UGA Legacy protocol
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiLegacy8259ProtocolGuid,
&gLegacyBiosServiceData,
&gEfiUgaLegacyProtocolGuid,
&gUgaLegacyData,
&gEfiLegacyBiosServiceProtocolGuid,
NULL
);
//
// Install EDID_ACTIVE protocol on a child handle
//
ChildHandle = NULL;
gEDIDActiveHandle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiEdidActiveProtocolGuid,
&gEdidActiveData,
NULL
);
//
// Connect the LegacyBiosPlatform protocol
//
Status = gBS->ConnectController (
ImageHandle,
&gEfiLegacyBiosPlatformProtocolGuid,
&gLegacyBiosPlatformData,
FALSE
);
return Status;
}
// ========================================================================
// sub_7A0 -- CsmVideoChildInit: initialize a VGA/display child
// ========================================================================
EFI_STATUS
CsmVideoChildInit (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle,
IN VOID *Context
)
{
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo;
EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 Supported;
UINT64 Attributes;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
CSM_VIDEO_INSTANCE *CsmVideo;
EFI_STATUS Status;
//
// Get PCI Root Bridge IO protocol on the child
//
Status = gBS->HandleProtocol (
ChildHandle,
&gEfiPciRootBridgeIoProtocolGuid,
(VOID **)&RootBridgeIo
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Locate Legacy BIOS Platform protocol
//
Status = gBS->LocateProtocol (
&gEfiLegacyBiosPlatformProtocolGuid,
NULL,
(VOID **)&LegacyBiosPlatform
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open PCI IO protocol with VGA attribute
//
Attributes = *(UINT64 *)((UINT8 *)Instance + 40); // Instance->Attributes
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get current mode / attributes
//
Status = PciIo->GetAttributes (PciIo, NULL, &Supported, NULL, NULL);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Enable VGA decode, IO, and memory access
//
Status = PciIo->SetAttributes (
PciIo,
EfiPciIoAttributeOperationEnable,
Attributes,
NULL
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Check if this is a VGA-compatible device via LegacyBIOS platform
//
Status = LegacyBiosPlatform->GetVgaCompatible (
LegacyBiosPlatform,
ChildHandle,
&CsmVideo
);
//
// Allocate resources descriptor for VGA legacy IO range
//
if (CsmVideo != NULL) {
Resources = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR));
if (Resources != NULL) {
Resources->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
Resources->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
Resources->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
Resources->AddrRangeMin = 0x3B0;
Resources->AddrRangeMax = 0x3DF;
Resources->AddrLen = 0x30;
Status = PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSet, 0x700 | 0x18, NULL);
// ...
}
}
//
// Check if already VGA enabled - skip if so
//
if (IsVgaEnableCheck (ChildHandle)) {
return EFI_SUCCESS;
}
//
// Create the CsmVideo instance
//
Status = CsmVideoInstanceCreate (
Instance,
ChildHandle,
PciIo,
RootBridgeIo,
LegacyBiosPlatform,
Context,
SavedAttributes
);
Done:
gBS->CloseProtocol (
ChildHandle,
&gEfiPciIoProtocolGuid,
Instance->ImageHandle,
ChildHandle
);
return Status;
}
// ========================================================================
// sub_9EC -- CsmVideoModeSet: set display mode
// ========================================================================
EFI_STATUS
CsmVideoModeSet (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle,
IN UINTN ModeCount,
IN UINTN *ModeArray
)
{
EFI_STATUS Status;
CSM_VIDEO_INSTANCE *CsmVideo;
UINTN Index;
//
// If no modes requested, try EDID_OVERRIDE first, then EDID_ACTIVE
//
if (ModeCount == 0) {
//
// Try to open EDID_OVERRIDE protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidOverrideProtocolGuid,
NULL,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (!EFI_ERROR (Status)) {
return CsmVideoChildAddProtocol (Instance, ChildHandle, ChildHandle);
}
//
// Otherwise open EDID_ACTIVE and configure display
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&CsmVideo,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CSM Video device detection error: %r\n", Status));
return EFI_UNSUPPORTED;
}
// Detect VGA child info
CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)CsmVideo - 32);
if (CsmVideo->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
}
IsVesaModeEnabled = CsmVideo->VesaModeEnabled;
//
// For each requested mode, try to add it
//
for (Index = 0; Index < ModeCount; Index++) {
if (EFI_ERROR (CsmVideoChildAddProtocol (Instance, ChildHandle, ModeArray[Index]))) {
IsVesaModeEnabled = FALSE;
}
}
//
// Restore previous VGA mode if needed
//
if (!IsVgaEnableCheck (ChildHandle) && IsVesaModeEnabled) {
Status = gBS->HandleProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&CsmVideo
);
if (!EFI_ERROR (Status)) {
CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)CsmVideo - 32);
if (CsmVideo->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
}
PciIo->SetAttributes (PciIo, EfiPciIoAttributeOperationEnable, SavedAttributes);
}
}
return EFI_SUCCESS;
}
//
// Detect the video device
//
Status = CsmVideoDetectDevice (Instance, ModeArray[0], &CsmVideo);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CSM Video device detection error: %r\n", Status));
return EFI_UNSUPPORTED;
}
IsVesaModeEnabled = CsmVideo->VesaModeEnabled;
SavedAttributes = CsmVideo->SavedPciAttributes;
//
// Add each requested mode
//
for (Index = 0; Index < ModeCount; Index++) {
if (EFI_ERROR (CsmVideoChildAddProtocol (Instance, ChildHandle, ModeArray[Index]))) {
IsVesaModeEnabled = FALSE;
}
}
//
// Restore VGA mode if necessary
//
if (!IsVgaEnableCheck (ChildHandle) && IsVesaModeEnabled) {
CsmVideo = CsmVideoFromHandle (ChildHandle);
if (CsmVideo != NULL) {
PciIo->SetAttributes (PciIo, EfiPciIoAttributeOperationEnable, SavedAttributes);
}
}
return IsVesaModeEnabled ? EFI_SUCCESS : EFI_UNSUPPORTED;
}
// ========================================================================
// sub_CE0 -- CsmVideoInstanceCreate: create and initialize video instance
// ========================================================================
EFI_STATUS
CsmVideoInstanceCreate (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle,
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo,
IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform,
IN EFI_HANDLE LegacyBiosHandle,
IN UINT64 SavedPciAttributes
)
{
CSM_VIDEO_INSTANCE *CsmVideo;
EFI_STATUS Status;
UINT8 Class[3];
UINT8 SubClass;
UINT8 HeaderType;
BOOLEAN IsVesaMode;
//
// Allocate 264-byte instance
//
Status = gBS->AllocatePool (EfiBootServicesData, sizeof (CSM_VIDEO_INSTANCE), (VOID **)&CsmVideo);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->SetMem (CsmVideo, sizeof (CSM_VIDEO_INSTANCE), 0);
//
// Query the VGA PCI config space for class code
//
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
PCI_CLASSCODE_OFFSET,
3,
Class
);
if (EFI_ERROR (Status)) {
goto Error;
}
CsmVideo->bEdidOverrideActive = 0;
//
// Detect device type: VGA compatible (class 3) or not
//
if (!(Class[2] == 3 || (Class[2] == 0 && Class[1] == 3 && !Class[0]))) {
// Not VGA-compatible; check for other video class
if (Class[0] != 3 || Class[1] != 0 || Class[2] != 0) {
// Not VGA, not a display controller
CsmVideo->bChildInVgaMode = 1;
} else {
CsmVideo->bChildInVgaMode = 0;
}
} else {
// Is VGA compatible - check for VESA mode
if (Class[0] != 1) {
// Not already in VGA mode, but VGA compatible
CsmVideo->bChildInVgaMode = 1;
}
}
//
// Initialize instance fields
//
CsmVideo->Signature = CSM_VIDEO_INSTANCE_SIGNATURE;
CsmVideo->PciIo = PciIo;
CsmVideo->PciRootBridgeIo = RootBridgeIo;
CsmVideo->VesaModeEnabled = 0;
CsmVideo->UsesLegacyVga = 1; // Default to legacy VGA
CsmVideo->SavedPciAttributes = SavedPciAttributes;
CsmVideo->VesaModeEnabled = 1; // Assume VESA-capable
DEBUG ((DEBUG_INFO, "CSM VGA PCI attributes saved: %lx\n", SavedPciAttributes));
//
// If no Legacy BIOS platform, go straight to legacy VGA
//
if (!gLegacyBiosPlatformAvailable) {
//
// Create end of device path for VGA IO range claim
//
if (LegacyBiosHandle == NULL) {
// Create ACPI device path for VGA IO range
// ...
}
//
// Apppend device path for the VGA rom
//
CsmVideo->EdidOverrideBuffer = AppendDevicePath (LegacyBiosHandle, NULL);
//
// Install protocol interfaces for the VESA/child
//
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmVideo->Handle,
&gEfiEdidDiscoveredProtocolGuid,
&CsmVideo->EdidDiscovered,
&gEfiEdidActiveProtocolGuid,
&CsmVideo->EdidActive,
&gEfiUgaDrawProtocolGuid,
&CsmVideo->UgaDraw,
NULL
);
if (EFI_ERROR (Status)) {
goto Error;
}
//
// Enumerate VESA modes
//
Status = VesaEnumerateModes (CsmVideo);
if (!EFI_ERROR (Status)) {
// VESA succeeded
} else {
// Fall back to legacy VGA
CsmVideo->VesaModeEnabled = 0;
CsmVideo->UsesLegacyVga = 1;
}
} else {
//
// Legacy BIOS platform path -- install EDID protocol only
//
CsmVideo->VesaModeEnabled = 0;
CsmVideo->UsesLegacyVga = 1;
}
if (CsmVideo->VesaModeEnabled) {
//
// Install full set of protocols for VESA/child
//
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmVideo->Handle,
&gEfiEdidDiscoveredProtocolGuid,
&CsmVideo->EdidDiscovered,
&gEfiEdidActiveProtocolGuid,
&CsmVideo->EdidActive,
&gEfiUgaDrawProtocolGuid,
&CsmVideo->UgaDraw,
NULL
);
//
// Install GOP protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&CsmVideo->EdidActive,
Instance->ImageHandle,
CsmVideo->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
//
// Legacy VGA mode: populate VGA text mode parameters
//
CsmVideo->PciIoLegacyVga = &gLegacyVgaCallbacks;
CsmVideo->FrameBufferBase = 0xB8000;
CsmVideo->FrameBufferSize = 0x8000;
// Legacy VGA CRTC parameters
CsmVideo->Crtc[0] = 0x3D4; // CRTC index
CsmVideo->Crtc[1] = 0x3D5; // CRTC data
CsmVideo->Crtc[2] = 0x3B4; // Mono CRTC index
CsmVideo->Crtc[3] = 0x3B5; // Mono CRTC data
CsmVideo->Crtc[4] = 0x3C0; // Attribute Controller
CsmVideo->Crtc[5] = 0x3CE; // Graphics Controller
CsmVideo->Crtc[6] = 0x3C4; // Sequencer
CsmVideo->InputRanges = 0xFF;
CsmVideo->OutputRanges = 0xFF;
CsmVideo->ColorDepth = 2; // 4-bit color
CsmVideo->Handle = ChildHandle;
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmVideo->Handle,
&gEfiEdidOverrideProtocolGuid,
&CsmVideo->EdidOverride,
NULL
);
}
gLastCsmVideoHandle = ChildHandle;
gIsLegacyVgaMode = !CsmVideo->VesaModeEnabled;
return EFI_SUCCESS;
Error:
CsmVideoFreeBuffers (CsmVideo);
return Status;
}
// ========================================================================
// sub_1080 -- CsmVideoDetectDevice: detect video controller and return instance
// ========================================================================
EFI_STATUS
CsmVideoDetectDevice (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle,
OUT CSM_VIDEO_INSTANCE **CsmVideo
)
{
CSM_VIDEO_INSTANCE *DetectedInstance;
EFI_STATUS Status;
//
// First, try to open EDID_ACTIVE protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&DetectedInstance, // Returns ptr to EdidActive field
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
//
// Adjust from field offset back to instance start
// EdidActive is at offset 32 in CsmVideoInstance
//
*CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)DetectedInstance - 32);
if ((*CsmVideo)->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
*CsmVideo = (CSM_VIDEO_INSTANCE *)DetectedInstance;
}
goto Found;
}
//
// Fall back to EDID_OVERRIDE protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidOverrideProtocolGuid,
(VOID **)&DetectedInstance,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
//
// EdidOverride is at offset 0x60 (96) in the instance
//
*CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)DetectedInstance - 96);
if ((*CsmVideo)->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
*CsmVideo = (CSM_VIDEO_INSTANCE *)DetectedInstance;
}
goto Found;
}
return Status;
Found:
return EFI_SUCCESS;
}
// ========================================================================
// sub_1178 -- CsmVideoChildAddProtocol: install protocols on video child
// ========================================================================
EFI_STATUS
CsmVideoChildAddProtocol (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle,
IN EFI_HANDLE ParentHandle
)
{
CSM_VIDEO_INSTANCE *CsmVideo;
EFI_STATUS Status;
//
// Detect the video device
//
Status = CsmVideoDetectDevice (Instance, ParentHandle, &CsmVideo);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Close any existing EDID_ACTIVE protocol on the target handle
//
gBS->CloseProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
Instance->ImageHandle,
ParentHandle
);
if (CsmVideo->VesaModeEnabled) {
//
// Install the full protocol set on this child (VESA mode)
//
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmVideo->Handle,
&gEfiEdidDiscoveredProtocolGuid,
&CsmVideo->EdidDiscovered,
&gEfiEdidActiveProtocolGuid,
&CsmVideo->EdidActive,
&gEfiUgaDrawProtocolGuid,
&CsmVideo->UgaDraw,
NULL
);
} else {
//
// Install EDID_OVERRIDE (legacy VGA mode)
//
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmVideo->Handle,
&gEfiEdidOverrideProtocolGuid,
&CsmVideo->EdidOverride,
NULL
);
}
if (EFI_ERROR (Status)) {
//
// If install failed, re-open EDID_ACTIVE to restore state
//
gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
NULL,
Instance->ImageHandle,
ParentHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
return Status;
}
//
// Initialize cursor to 80x25 text mode
//
{
UINT16 CursorInfo[2];
CursorInfo[0] = 3; // 80x25 color text mode
gBS->SetMem (&CursorInfo[1], sizeof (UINT16), 0);
// VGA INT10 AH=00h: set video mode 3 (80x25 color text)
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
(UINT8)CursorInfo[0],
CursorInfo
);
// VGA INT10 AH=01h: set cursor shape (no cursor)
CursorInfo[0] = 0x1114; // Function 01h, CH=11h, CL=14h
CursorInfo[1] = 0x00;
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
(UINT8)CursorInfo[0],
CursorInfo
);
}
//
// Initialize VESA controller
//
VesaGetControllerCapabilities (CsmVideo);
//
// Mark the global child handle
//
gLastCsmVideoChildHandle = NULL;
return EFI_SUCCESS;
}
// ========================================================================
// sub_1300 -- CsmVideoFreeBuffers: free all resources
// ========================================================================
VOID
CsmVideoFreeBuffers (
IN CSM_VIDEO_INSTANCE *CsmVideo
)
{
if (CsmVideo == NULL) {
return;
}
// Free frame buffer 3
if (CsmVideo->FrameBuffer3 != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer3);
CsmVideo->FrameBuffer3 = NULL;
}
// Free frame buffer 2
if (CsmVideo->FrameBuffer2 != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer2);
CsmVideo->FrameBuffer2 = NULL;
}
// Free frame buffer
if (CsmVideo->FrameBuffer != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer);
CsmVideo->FrameBuffer = NULL;
}
// Free scan line buffer
if (CsmVideo->ScanLineBuffer != NULL) {
gBS->FreePool (CsmVideo->ScanLineBuffer);
CsmVideo->ScanLineBuffer = NULL;
}
// Free text buffer + its memory descriptor
if (CsmVideo->TextBuffer != NULL) {
gBS->FreePages (CsmVideo->TextBufferPhysical, CsmVideo->TextBufferPages);
CsmVideo->TextBuffer = NULL;
}
// Free EDID override buffer
if (CsmVideo->EdidOverrideBuffer != NULL) {
gBS->FreePool (CsmVideo->EdidOverrideBuffer);
CsmVideo->EdidOverrideBuffer = NULL;
}
// Free the instance itself
if (CsmVideo->Buffer1 != NULL) {
gBS->FreePool (CsmVideo->Buffer1);
CsmVideo->Buffer1 = NULL;
}
if (CsmVideo->Reserved40 != 0) {
gBS->FreePool ((VOID *)(UINTN)CsmVideo->Reserved40);
CsmVideo->Reserved40 = 0;
}
if (CsmVideo->ScanLineBuffer != NULL) {
gBS->FreePool (CsmVideo->ScanLineBuffer);
CsmVideo->ScanLineBuffer = NULL;
}
if (CsmVideo->TextBuffer != NULL) {
gBS->FreePool (CsmVideo->TextBuffer);
CsmVideo->TextBuffer = NULL;
}
if (CsmVideo->FrameBuffer != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer);
CsmVideo->FrameBuffer = NULL;
}
if (CsmVideo->FrameBuffer2 != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer2);
CsmVideo->FrameBuffer2 = NULL;
}
if (CsmVideo->FrameBuffer3 != NULL) {
gBS->FreePool (CsmVideo->FrameBuffer3);
CsmVideo->FrameBuffer3 = NULL;
}
gBS->FreePool (CsmVideo);
}
// ========================================================================
// sub_145C -- EdidParseAndMerge: parse EDID block, extract timings
// ========================================================================
VOID
EdidParseAndMerge (
IN EDID_BLOCK *Edid
)
{
UINTN Index;
UINT16 DetailedTimingIndex;
UINT8 *TimingDescriptor;
UINT16 HorizontalPixels;
UINT16 VerticalLines;
UINT8 AspectRatio;
UINT16 EstablishedTimings;
//
// Validate EDID checksum
//
{
UINT8 Checksum = 0;
UINT8 *Bytes = (UINT8 *)Edid;
UINTN ByteIndex;
for (ByteIndex = 0; ByteIndex < sizeof (EDID_BLOCK); ByteIndex++) {
Checksum = (UINT8)(Checksum + Bytes[ByteIndex]);
}
if (Checksum != 0) {
DEBUG ((DEBUG_ERROR, "EDID checksum is invalid, EDID will be ignored.\n"));
return;
}
}
//
// Parse established timings from EDID byte 0x23
//
EstablishedTimings = Edid->EstablishedTimings[0] |
(Edid->EstablishedTimings[1] << 8) |
((Edid->EstablishedTimings[2] & 0x80) << 9);
Index = 0;
//
// Map known established timing resolutions
//
{
typedef struct {
UINT16 TimingFlag;
UINT16 XRes;
UINT16 YRes;
} ESTABLISHED_TIMING;
ESTABLISHED_TIMING EstablishedTimingMap[17];
UINTN TimingIndex;
//
// Established timings from EDID spec
//
EstablishedTimingMap[0].TimingFlag = 0x0001; // 720x400 @ 70Hz
EstablishedTimingMap[0].XRes = 720;
EstablishedTimingMap[0].YRes = 400;
// ... (full table continues)
//
// Check each flag bit
//
for (TimingIndex = 0; TimingIndex < 17; TimingIndex++) {
if (EstablishedTimings & EstablishedTimingMap[TimingIndex].TimingFlag) {
gEdidResolutionTable[Index++] =
EDID_DETAILED_TIMING_RESOLUTION (
EstablishedTimingMap[TimingIndex].XRes,
EstablishedTimingMap[TimingIndex].YRes
);
}
}
}
//
// Parse detailed timing descriptors (EDID bytes 0x36-0x6F, 18 bytes each)
//
for (DetailedTimingIndex = 0; DetailedTimingIndex < 4; DetailedTimingIndex++) {
TimingDescriptor = &Edid->DetailedTimingDescriptors[DetailedTimingIndex * 18];
//
// Check if this is a timing descriptor (byte 0 = tag, byte 1 != 1 = pixel clock)
//
if (TimingDescriptor[0] != 0x01 && TimingDescriptor[1] != 0x01) {
//
// Extract Horizontal pixels from bytes 0x02-0x04 (packed)
//
HorizontalPixels = (UINT16)(TimingDescriptor[2] + ((TimingDescriptor[4] & 0xF0) << 4));
HorizontalPixels = (UINT16)(8 * (HorizontalPixels + 31));
//
// Aspect ratio / Vertical lines extraction
//
AspectRatio = TimingDescriptor[3] >> 6;
switch (AspectRatio) {
case 0: // Ratio 16:10
VerticalLines = (UINT16)(10 * (HorizontalPixels >> 4));
break;
case 1: // Ratio 4:3
VerticalLines = (UINT16)(4 * (HorizontalPixels / 5));
break;
case 2: // Ratio 5:4
VerticalLines = (UINT16)(5 * (HorizontalPixels / 6));
break;
case 3: // Ratio 16:9
VerticalLines = (UINT16)(9 * (HorizontalPixels / 16));
break;
default:
continue;
}
gEdidResolutionTable[Index++] =
EDID_DETAILED_TIMING_RESOLUTION (HorizontalPixels, VerticalLines);
DEBUG ((
DEBUG_INFO,
"EDID Detailed timing[%d]: inserted resolution 0x%x (%dx%d)\n",
(UINTN)DetailedTimingIndex,
EDID_DETAILED_TIMING_RESOLUTION (HorizontalPixels, VerticalLines),
HorizontalPixels,
VerticalLines
));
}
}
}
// ========================================================================
// sub_16A0 -- VesaGetControllerCapabilities: query VESA VBE BIOS
// ========================================================================
EFI_STATUS
VesaGetControllerCapabilities (
IN CSM_VIDEO_INSTANCE *CsmVideo
)
{
UINT16 VbeControllerInfo[24]; // 48 bytes
UINT16 GraphicsPortCount;
UINT16 PortIndex;
UINT16 ReturnedStatus;
//
// Issue VBE controller capabilities call
//
gBS->SetMem (VbeControllerInfo, sizeof (VbeControllerInfo), 0);
VbeControllerInfo[0] = VESA_CAPABILITIES_FN; // 0x4F15
VbeControllerInfo[1] = 0x10; // Function = Get Capabilities
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
0x10,
VbeControllerInfo
);
if (VbeControllerInfo[0] == 0x004F) {
GraphicsPortCount = VbeControllerInfo[3]; // Number of graphics ports
if (GraphicsPortCount == 0) {
DEBUG ((DEBUG_WARN,
"VESA VBE/SCI Capabilities call returns 0 graphics ports - forced to 1.\n"));
GraphicsPortCount = 1;
}
} else {
GraphicsPortCount = 1; // Default to 1
}
//
// Enumerate each graphics port to find a connected display
//
for (PortIndex = 0; PortIndex < GraphicsPortCount; PortIndex++) {
gBS->SetMem (VbeControllerInfo, sizeof (VbeControllerInfo), 0);
VbeControllerInfo[0] = VESA_CAPABILITIES_FN;
VbeControllerInfo[1] = 1; // Function = Get Port
VbeControllerInfo[14] = (UINT16)((CsmVideo->Crtc[2] >> 4) & 0xF000);
VbeControllerInfo[10] = CsmVideo->Crtc[2]; // Port index
VbeControllerInfo[3] = 0;
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
0x10,
VbeControllerInfo
);
if (VbeControllerInfo[0] == 0x004F) {
break; // Found a connected port
}
}
if (PortIndex == GraphicsPortCount) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_17D8 -- VesaEnumerateModes: enumerate all VESA VBE modes
// ========================================================================
EFI_STATUS
VesaEnumerateModes (
IN OUT CSM_VIDEO_INSTANCE *CsmVideo
)
{
EFI_STATUS Status;
UINT16 VbeModeInfo[64]; // 256 byte VBE mode info block
UINT16 VbeModeNumber;
UINT16 *ModeListPtr;
UINT16 ControllerInformation[128]; // 256 byte VBE controller info
VESA_MODE_INFO *VesaModelist;
UINT16 TotalModes;
UINT16 UsableModes;
UINT16 *ModeBuffer;
UINTN Index;
UINTN EdidOverrideProtocolSize;
UINT8 EdidOverrideProtocolData;
BOOLEAN EdidMatchFound;
BOOLEAN ModeMatchFound;
UINTN HorizontalRes;
UINTN VerticalRes;
//
// Get VBE controller info
//
Status = VesaGetControllerCapabilities (CsmVideo);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_INFO,
"VESA: fetching the list of VESA modes supported by the controller from %x\n",
CsmVideo->EdidDiscovered));
//
// Get EDID override data if present
//
EdidOverrideProtocolSize = 0;
Status = gBS->LocateProtocol (
&gEfiEdidOverrideProtocolGuid,
NULL,
(VOID **)&EdidOverrideProtocolData
);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO,
"EDID override protocol found: data size %x, attribute %x\n",
0, 0));
}
//
// Allocate space for mode list (up to ~256 VBE modes)
//
ModeBuffer = AllocateZeroPool (256 * sizeof (UINT16));
if (ModeBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UsableModes = 0;
TotalModes = 0;
//
// Loop through VESA/VBE modes
//
for (Index = 0; ; Index++) {
//
// Get VBE mode info for this mode number
// VBE function 0x4F01: Get Mode Info
//
gBS->SetMem (VbeModeInfo, sizeof (VbeModeInfo), 0);
VbeModeInfo[0] = 0x4F01; // VBE function
VbeModeInfo[2] = ModeBuffer[Index]; // Mode number
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
0x10,
VbeModeInfo
);
if (VbeModeInfo[0] != 0x004F) {
// No more modes or error
break;
}
VbeModeNumber = (UINT16)VbeModeInfo[2];
TotalModes++;
DEBUG ((DEBUG_INFO, "VESA mode %x ", VbeModeNumber));
//
// Validate mode number
//
if (VbeModeNumber < 0x100) {
DEBUG ((DEBUG_INFO, ".. skipping as it is not a proper VESA mode number\n"));
continue;
}
//
// Check mode attributes bit 7 (linear FB supported) and bit 0 (mode supported)
//
if (!(VbeModeInfo[0] & 0x80) || !(VbeModeInfo[0] & 0x01)) {
DEBUG ((DEBUG_INFO, ".. skipping as the mode is not supported in hardware...\n"));
continue;
}
//
// Check mode type (must be invalid type to be graphical)
//
if ((VbeModeInfo & 0x08) == 0) {
DEBUG ((DEBUG_INFO, ".. skipping as the mode is not graphical...\n"));
continue;
}
//
// Check for linear frame buffer
//
if (!(VbeModeInfo[0] & VESA_MODE_LINEAR_FB_BIT)) {
DEBUG ((DEBUG_INFO, ".. skipping as the mode has not linear frame buffer...\n"));
continue;
}
//
// Check bits per pixel: must be 24-32, and modulo 8 == 0
//
{
UINT8 BitsPerPixel = (UINT8)(VbeModeInfo[0x12]);
if (BitsPerPixel < 24) {
DEBUG ((DEBUG_INFO, ".. skipping as BPP (%d) is less than 24...\n", BitsPerPixel));
continue;
}
if (BitsPerPixel > 32) {
DEBUG ((DEBUG_INFO, ".. skipping as BPP (%d) is more than 32...\n", BitsPerPixel));
continue;
}
if ((BitsPerPixel % 8) != 0) {
DEBUG ((DEBUG_INFO, ".. skipping as BPP (%d) modulo 8 is non-zero...\n", BitsPerPixel));
continue;
}
}
//
// Check PhysBasePtr is non-zero
//
{
UINT64 PhysBasePtr = *(UINT64 *)&VbeModeInfo[0x28];
if (PhysBasePtr == 0) {
DEBUG ((DEBUG_INFO, ".. skipping as PhysBasePtr is zero...\n"));
continue;
}
}
//
// Check resolution against EDID table
//
HorizontalRes = *(UINT32 *)&VbeModeInfo[0x12]; // XResolution
VerticalRes = *(UINT32 *)&VbeModeInfo[0x16]; // YResolution
EdidMatchFound = FALSE;
ModeMatchFound = FALSE;
for (Index = 0; Index < EDID_MAX_DETAILED_TIMING; Index++) {
UINTN TableEntry = gEdidResolutionTable[Index];
UINTN TableX = TableEntry >> 16;
UINTN TableY = TableEntry & 0xFFFF;
if (TableX == HorizontalRes && TableY == VerticalRes) {
//
// Check for duplicate
//
for (Index = 0; Index < UsableModes; Index++) {
VESA_MODE_INFO *ExistingMode = &CsmVideo->VesaModeInfo[Index];
if (ExistingMode->HorizontalResolution == HorizontalRes &&
ExistingMode->VerticalResolution == VerticalRes) {
DEBUG ((DEBUG_INFO,
".. skipping as the same resolution (%dx%d) is already available\n",
HorizontalRes, VerticalRes));
goto NextMode;
}
}
//
// Mode is usable -- add to our mode table
//
CsmVideo->VesaModeInfo[UsableModes].VbeModeNumber = VbeModeNumber;
CsmVideo->VesaModeInfo[UsableModes].HorizontalResolution = (UINT32)HorizontalRes;
CsmVideo->VesaModeInfo[UsableModes].VerticalResolution = (UINT32)VerticalRes;
CsmVideo->VesaModeInfo[UsableModes].BytesPerScanLine = VbeModeInfo[0x10];
CsmVideo->VesaModeInfo[UsableModes].LinearFrameBufferBase = PhysBasePtr;
CsmVideo->VesaModeInfo[UsableModes].BitsPerPixel = VbeModeInfo[0x12] & 0xFF;
ModeMatchFound = TRUE;
UsableModes++;
break;
}
}
if (EdidMatchFound) {
DEBUG ((DEBUG_INFO, "EDID match found.\n"));
} else if (ModeMatchFound) {
DEBUG ((DEBUG_INFO, "MODE match found (%d).\n", (UINTN)UsableModes));
} else {
DEBUG ((DEBUG_INFO, "neither EDID nor MODE match is found.\n"));
}
}
// (end for loop)
//
// Update mode count
//
*(UINT32 *)((UINT8 *)CsmVideo + 0x50) = UsableModes;
CsmVideo->MaxMode = UsableModes;
DEBUG ((DEBUG_INFO, "Total number of GOP modes: %d\n", (UINTN)UsableModes));
//
// Allocate video buffers for this instance
//
Status = AllocateVideoBuffers (CsmVideo);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_21AC -- GraphicsOutputQueryMode: GOP QueryMode
// ========================================================================
EFI_STATUS
EFIAPI
GraphicsOutputQueryMode (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN UINT32 ModeNumber,
OUT UINTN *SizeOfInfo,
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
)
{
CSM_VIDEO_INSTANCE *CsmVideo;
VESA_MODE_INFO *ModeInfoEntry;
//
// Get instance from CR (This is at offset 32 from instance)
//
CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)This - 32);
if (CsmVideo->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
CsmVideo = (CSM_VIDEO_INSTANCE *)This;
}
//
// Check if initialized
//
if (CsmVideo->bEdidOverrideActive) {
return EFI_DEVICE_ERROR;
}
//
// Validate parameters
//
if (ModeNumber >= CsmVideo->MaxMode || SizeOfInfo == NULL || Info == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Allocate output buffer (36 bytes as observed)
//
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
Status = gBS->AllocatePool (EfiBootServicesData, *SizeOfInfo, (VOID **)Info);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Populate mode info from VESA mode table (72 bytes per entry)
//
ModeInfoEntry = &CsmVideo->VesaModeInfo[ModeNumber];
(*Info)->Version = 0;
(*Info)->HorizontalResolution = ModeInfoEntry->HorizontalResolution;
(*Info)->VerticalResolution = ModeInfoEntry->VerticalResolution;
(*Info)->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
(*Info)->PixelsPerScanLine = ModeInfoEntry->HorizontalResolution;
//
// Calculate pixel information
//
(*Info)->PixelInformation.RedMask = ModeInfoEntry->RedMask;
(*Info)->PixelInformation.GreenMask = ModeInfoEntry->GreenMask;
(*Info)->PixelInformation.BlueMask = ModeInfoEntry->BlueMask;
(*Info)->PixelInformation.ReservedMask = 0;
//
// PixelsPerScanLine = 8 * BytesPerScanLine / BitsPerPixel
//
(*Info)->PixelsPerScanLine = 8 * ModeInfoEntry->BytesPerScanLine / ModeInfoEntry->BitsPerPixel;
return EFI_SUCCESS;
}
// ========================================================================
// sub_22D4 -- AllocateVideoBuffers: allocate scan line, text, and frame buffers
// ========================================================================
EFI_STATUS
AllocateVideoBuffers (
IN OUT CSM_VIDEO_INSTANCE *CsmVideo
)
{
UINT16 MaxBytesPerScanLine;
UINT32 MaxVerticalResolution;
UINT32 ModeCount;
UINTN Index;
EFI_STATUS Status;
//
// Compute worst-case dimensions from all modes
//
MaxBytesPerScanLine = 0;
MaxVerticalResolution = 0;
ModeCount = CsmVideo->MaxMode;
DEBUG ((DEBUG_INFO, "UefiBiosVideo AllocateTheBuffers()\n"));
//
// Scan all modes to find the largest
//
for (Index = 0; Index < ModeCount; Index++) {
VESA_MODE_INFO *Mode = &CsmVideo->VesaModeInfo[Index];
DEBUG ((DEBUG_INFO, "VbeModeNumber: 0x%x\n", Mode->VbeModeNumber));
DEBUG ((DEBUG_INFO, "BytesPerScanLine: 0x%x\n", Mode->BytesPerScanLine));
DEBUG ((DEBUG_INFO, "HorizontalResolution: 0x%x\n", Mode->HorizontalResolution));
DEBUG ((DEBUG_INFO, "VerticalResolution: 0x%x\n", Mode->VerticalResolution));
if (Mode->BytesPerScanLine > MaxBytesPerScanLine) {
MaxBytesPerScanLine = Mode->BytesPerScanLine;
}
if (Mode->VerticalResolution > MaxVerticalResolution) {
MaxVerticalResolution = Mode->VerticalResolution;
}
}
DEBUG ((DEBUG_INFO, "MaxBytesPerScanLine: 0x%x\n", MaxBytesPerScanLine));
DEBUG ((DEBUG_INFO, "MaxVerticalResolution: 0x%x\n", MaxVerticalResolution));
//
// Allocate scan line buffer
//
Status = gBS->AllocatePool (
EfiBootServicesData,
MaxBytesPerScanLine,
&CsmVideo->ScanLineBuffer
);
if (EFI_ERROR (Status)) {
CsmVideo->ScanLineBuffer = NULL;
return Status;
}
gBS->SetMem (CsmVideo->ScanLineBuffer, MaxBytesPerScanLine, 0);
//
// Allocate text buffer (153600 bytes = 80*25*2*24 -- VGA text mode save area)
//
Status = gBS->AllocatePool (
EfiBootServicesData,
153600,
&CsmVideo->TextBuffer
);
if (EFI_ERROR (Status)) {
gBS->FreePool (CsmVideo->ScanLineBuffer);
CsmVideo->ScanLineBuffer = NULL;
return Status;
}
gBS->SetMem (CsmVideo->TextBuffer, 153600, 0);
//
// Allocate frame buffer
//
{
UINTN FrameBufferSize = MaxVerticalResolution * MaxBytesPerScanLine;
Status = gBS->AllocatePool (
EfiBootServicesData,
FrameBufferSize,
&CsmVideo->FrameBuffer
);
if (EFI_ERROR (Status)) {
gBS->FreePool (CsmVideo->ScanLineBuffer);
gBS->FreePool (CsmVideo->TextBuffer);
CsmVideo->ScanLineBuffer = NULL;
CsmVideo->TextBuffer = NULL;
return Status;
}
gBS->SetMem (CsmVideo->FrameBuffer, FrameBufferSize, 0);
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_24AC -- GraphicsOutputSetMode: GOP SetMode
// ========================================================================
EFI_STATUS
EFIAPI
GraphicsOutputSetMode (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN UINT32 ModeNumber
)
{
CSM_VIDEO_INSTANCE *CsmVideo;
VESA_MODE_INFO *ModeInfo;
EFI_STATUS Status;
UINT16 VbeCallBuffer[28]; // 48 bytes buffer for INT10
//
// Find instance via CR (This at offset 32)
//
CsmVideo = (CSM_VIDEO_INSTANCE *)((UINT8 *)This - 32);
if (CsmVideo->Signature != CSM_VIDEO_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
CsmVideo = (CSM_VIDEO_INSTANCE *)This;
}
//
// Validate mode number
//
if (ModeNumber >= CsmVideo->MaxMode) {
return EFI_INVALID_PARAMETER;
}
ModeInfo = &CsmVideo->VesaModeInfo[ModeNumber];
//
// Prepare VBE call buffer
//
gBS->SetMem (VbeCallBuffer, sizeof (VbeCallBuffer), 0);
//
// If mode number < 0x100, use standard VGA mode set
//
if (ModeInfo->VbeModeNumber < 0x100) {
//
// VGA mode set via INT10 AH=00h, AL=mode
//
VbeCallBuffer[0] = ModeInfo->VbeModeNumber;
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
0x00,
VbeCallBuffer
);
} else {
//
// VESA/VBE mode set: INT10 AX=4F02h, BX=mode
//
VbeCallBuffer[0] = 0x4F02; // VBE Set Mode
VbeCallBuffer[2] = ModeInfo->VbeModeNumber | VESA_MODE_LINEAR_FB_BIT;
CsmVideo->PciIo->Int10 (
CsmVideo->PciIo,
0x10,
VbeCallBuffer
);
if (VbeCallBuffer[0] != 0x004F) {
return EFI_UNSUPPORTED;
}
}
//
// Update current mode info
//
CsmVideo->CurrentMode = ModeNumber;
CsmVideo->ModeInfo->HorizontalResolution = ModeInfo->HorizontalResolution;
CsmVideo->ModeInfo->VerticalResolution = ModeInfo->VerticalResolution;
CsmVideo->ModeInfo->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
CsmVideo->ModeInfo->PixelsPerScanLine = 8 * ModeInfo->BytesPerScanLine / ModeInfo->BitsPerPixel;
CsmVideo->ModeInfoSize = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
CsmVideo->FrameBufferBase = ModeInfo->LinearFrameBufferBase;
//
// Calculate frame buffer size
//
CsmVideo->FrameBufferSize = ModeInfo->BytesPerScanLine * ModeInfo->VerticalResolution;
//
// Clear the frame buffer (fill with zeros)
//
{
UINTN ClearSize = ModeInfo->VerticalResolution * ModeInfo->BytesPerScanLine;
VOID *FrameBufferPtr = (VOID *)(UINTN)ModeInfo->LinearFrameBufferBase;
gBS->SetMem (FrameBufferPtr, ClearSize, 0);
}
//
// Copy current frame buffer from VESA linear FB to our shadow buffer
//
gBS->CopyMem (
CsmVideo->FrameBuffer,
(VOID *)(UINTN)ModeInfo->LinearFrameBufferBase,
ModeInfo->BytesPerScanLine * ModeInfo->VerticalResolution
);
CsmVideo->bEdidOverrideActive = 0;
return EFI_SUCCESS;
}
// ========================================================================
// sub_26DC -- GraphicsOutputSetModeWrapper: 10-param wrapper for GOP SetMode
// ========================================================================
EFI_STATUS
GraphicsOutputSetModeWrapper (
IN OUT CSM_VIDEO_INSTANCE *CsmVideo,
IN UINT8 *ModeData,
IN UINT32 ModeNumber,
IN UINT64 Param4,
IN UINT64 HorizontalRes,
IN UINT64 VerticalRes,
IN UINT64 Param7,
IN UINT64 Param8,
IN UINT64 BytesPerScanLine,
IN UINT64 Param10
)
{
EFI_STATUS Status;
UINT64 FrameBufferBase;
BOOLEAN EdidOverrideActive;
//
// Get current EDID override info from instance
//
CsmVideo = CR_FROM_EDID_ACTIVE (CsmVideo);
if (CsmVideo == NULL) {
return EFI_INVALID_PARAMETER;
}
EdidOverrideActive = CsmVideo->bEdidOverrideActive;
//
// If currently in EDID override mode, handle state transition
//
if (EdidOverrideActive) {
//
// Close EDID_ACTIVE protocol (open from child controller)
//
Status = gBS->CloseProtocol (
CsmVideo->ParentHandle,
&gEfiEdidActiveProtocolGuid,
CsmVideo->ImageHandle,
CsmVideo->Handle
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Set the VGA mode
//
Status = GraphicsOutputSetMode (&CsmVideo->GraphicsOutput, ModeNumber);
if (EFI_ERROR (Status)) {
//
// Re-open EDID_ACTIVE on failure
//
gBS->OpenProtocol (
CsmVideo->ParentHandle,
&gEfiEdidActiveProtocolGuid,
NULL,
CsmVideo->ImageHandle,
CsmVideo->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
return Status;
}
//
// Open EDID_ACTIVE with BY_CHILD_CONTROLLER after mode set
//
Status = gBS->OpenProtocol (
CsmVideo->ParentHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&CsmVideo->EdidActive,
CsmVideo->ImageHandle,
CsmVideo->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Re-install the Full protocol set (EDID_DISCOVERED, EDID_ACTIVE, UGA_DRAW)
//
// ...
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_2D84 -- VgaTextSetCursorPosition: set cursor via INT10 AH=02h
// ========================================================================
EFI_STATUS
VgaTextSetCursorPosition (
IN VOID *This,
IN UINTN CursorMode
)
{
UINT16 CursorInfo[2];
VGA_CLASS_INSTANCE *Instance;
Instance = (VGA_CLASS_INSTANCE *)((UINT8 *)This - 96);
if (Instance->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
//
// Validate cursor mode
//
if (CursorMode > Instance->ModeTableSize) {
return EFI_UNSUPPORTED;
}
//
// Perform INT10 call
//
gBS->SetMem (CursorInfo, sizeof (CursorInfo), 0);
if (CursorMode == 0) {
CursorInfo[0] = 0x0002; // AH=02h, BH=00h
CursorInfo[1] = 0x0000; // DX = 0 (row=0, col=0)
} else {
// Set cursor to end of screen for mode 1
CursorInfo[0] = 0x0002;
CursorInfo[1] = 0x0000;
}
//
// Call INT10 to set cursor position
//
Instance->Init (This, 0);
return EFI_SUCCESS;
}
// ========================================================================
// sub_2E58 -- EdidOverrideUninstall: remove EDID override protocols
// ========================================================================
EFI_STATUS
EdidOverrideUninstall (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
//
// Open EDID_OVERRIDE protocol on child
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidOverrideProtocolGuid,
NULL,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close and uninstall EDID_ACTIVE protocol
//
Status = gBS->CloseProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
NULL,
Instance->ImageHandle,
ChildHandle
);
return Status;
}
// ========================================================================
// sub_2ED0 -- VgaClassConstructor: create VGA text class
// ========================================================================
EFI_STATUS
VgaClassConstructor (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
VGA_CLASS_INSTANCE *VgaClass;
EFI_PCI_IO_PROTOCOL *PciIo;
VOID *RootBridgeIo;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
UINTN ModeCount;
//
// Get PCI Root Bridge IO protocol
//
Status = gBS->HandleProtocol (
ChildHandle,
&gEfiPciRootBridgeIoProtocolGuid,
&RootBridgeIo
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open PCI IO protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&PciIo,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open EDID_OVERRIDE protocol
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidOverrideProtocolGuid,
(VOID **)&PciIo,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Allocate VGA Class Instance (144 bytes)
//
Status = gBS->AllocatePool (EfiBootServicesData, sizeof (VGA_CLASS_INSTANCE), (VOID **)&VgaClass);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
gBS->SetMem (VgaClass, sizeof (VGA_CLASS_INSTANCE), 0);
//
// Set signature
//
VgaClass->Signature = VGA_CLASS_INSTANCE_SIGNATURE;
VgaClass->ParentHandle = ChildHandle;
//
// Fill vtable
//
VgaClass->Init = (EFI_STATUS (*)(VOID *))sub_322C;
VgaClass->StringOutput = (EFI_STATUS (*)(VOID *, CHAR16 *))sub_3280;
VgaClass->TestString = (EFI_STATUS (*)(VOID *, CHAR16 *))sub_34BC;
VgaClass->ClearScreen = (EFI_STATUS (*)(VOID *))sub_3550;
VgaClass->SetAttribute = (EFI_STATUS (*)(VOID *, VOID *))sub_3610;
VgaClass->SetCursor = (EFI_STATUS (*)(VOID *, UINTN, UINTN))sub_362C;
VgaClass->EnableCursor = (EFI_STATUS (*)(VOID *, BOOLEAN))sub_36D0;
VgaClass->QueryMode = (EFI_STATUS (*)(VOID *, UINTN *, UINTN *))sub_3770;
VgaClass->SetMode = (EFI_STATUS (*)(VOID *, UINTN))sub_3810;
VgaClass->Unused58 = NULL;
//
*((UINT32 *)&VgaClass->ModeTableSize) = ((UINT8 *)PciIo)[35]; // Max mode count
VgaClass->TextModeData = (VOID *)PciIo;
VgaClass->FrameBufferAccess = (VOID *)RootBridgeIo;
//
// Initialize the VGA class instance:
// init -> set mode (15) -> set cursor -> enable cursor
//
Status = VgaClass->SetMode (&VgaClass->ModeTableSize, 15);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = VgaClass->Init (&VgaClass->ModeTableSize, 0);
if (EFI_ERROR (Status)) {
goto Error;
}
Status = VgaClass->EnableCursor (&VgaClass->ModeTableSize, 1);
if (EFI_ERROR (Status)) {
goto Error;
}
//
// Install Legacy BIOS protocol on the child
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ChildHandle,
&gEfiLegacyBiosProtocolGuid,
VgaClass,
NULL
);
return Status;
Error:
gBS->CloseProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
Instance->ImageHandle,
ChildHandle
);
gBS->FreePool (VgaClass);
return Status;
}
// ========================================================================
// sub_3138 -- VgaClassDestructor: destroy VGA class instance
// ========================================================================
EFI_STATUS
VgaClassDestructor (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle
)
{
VGA_CLASS_INSTANCE *VgaClass;
EFI_STATUS Status;
//
// Open Legacy BIOS protocol
//
Status = gBS->HandleProtocol (
ChildHandle,
&gEfiLegacyBiosProtocolGuid,
(VOID **)&VgaClass
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Adjust from LegacyBios protocol interface back to instance
//
VgaClass = (VGA_CLASS_INSTANCE *)((UINT8 *)VgaClass - 16);
if (VgaClass->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
}
//
// Uninstall Legacy BIOS protocol
//
Status = gBS->ReinstallProtocolInterface (
ChildHandle,
&gEfiLegacyBiosProtocolGuid,
&VgaClass->Signature,
VgaClass
);
//
// Uninstall EDID_ACTIVE protocol
//
Status = gBS->CloseProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
Instance->ImageHandle,
ChildHandle
);
//
// Uninstall EDID_OVERRIDE protocol
//
Status = gBS->CloseProtocol (
ChildHandle,
&gEfiEdidOverrideProtocolGuid,
Instance->ImageHandle,
ChildHandle
);
//
// Free the instance
//
gBS->FreePool (VgaClass);
return Status;
}
// ========================================================================
// sub_322C -- VgaTextInit: initialize VGA text mode
// ========================================================================
EFI_STATUS
VgaTextInit (
IN VGA_CLASS_INSTANCE *This,
IN UINTN Mode
)
{
//
// Set palette registers (INT10 AH=0Bh/BH=01h)
//
This->SetAttribute (This, (VOID *)(UINTN)(This->ModeTableSize & 0xF));
//
// Set cursor type (start, end)
//
return This->SetCursor (This, 0);
}
// ========================================================================
// sub_3280 -- VgaTextStringOutput: output string to VGA text screen
// ========================================================================
EFI_STATUS
VgaTextStringOutput (
IN VGA_CLASS_INSTANCE *This,
IN CHAR16 *String
)
{
EFI_STATUS Status;
UINT16 CursorData[2];
UINT64 FrameBufferOffset;
UINT16 Attribute;
UINTN CursorX;
UINTN CursorY;
UINTN ScreenWidth;
UINTN ScreenHeight;
UINT64 FrameBufferBase;
UINT16 CharacterAttribute;
CHAR16 CurrentChar;
CHAR8 GlyphData;
UINTN Stride;
//
// Validate This signature
//
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
//
// Get current mode dimensions
//
Status = This->QueryMode (This, &ScreenWidth, &ScreenHeight);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get text cursor position from attribute fields
//
CursorX = This->CursorX;
CursorY = This->CursorY;
//
// Get current attribute
//
Attribute = This->Attribute;
//
// Get frame buffer stride (bytes per scan line)
//
Stride = This->FrameBufferStride;
//
// Process each character in the string
//
for (; *String != 0; String++) {
CurrentChar = *String;
switch (CurrentChar) {
case 0x08: // Backspace
if (CursorX > 0) {
CursorX--;
}
break;
case 0x0A: // Line feed
if (CursorY < (ScreenHeight - 1)) {
//
// Scroll the screen up by one line
//
if (CursorY == (ScreenHeight - 1)) {
// Scroll
CursorData[0] = ((Attribute << 8) | 0x20);
This->SetCursor (This, CursorY, CursorX);
CursorY++;
}
}
CursorY++;
break;
case 0x0D: // Carriage return
CursorX = 0;
break;
default:
//
// Convert OEM characters to VGA glyphs
//
if (VgaOemCharTranslate (CurrentChar, &GlyphData)) {
CharacterAttribute = GlyphData | (Attribute << 8);
} else {
CharacterAttribute = ((CHAR8)CurrentChar) | (Attribute << 8);
}
//
// Write character to frame buffer at current cursor position
//
FrameBufferOffset = CursorY * Stride + CursorX * 2;
FrameBufferBase = This->FrameBufferAddress;
// Write character + attribute to VGA text buffer (B8000 or shadow)
*(UINT16 *)(UINTN)(FrameBufferBase + FrameBufferOffset) = CharacterAttribute;
if (CursorX < (ScreenWidth - 1)) {
CursorX++;
} else {
//
// Advance to next line
//
This->StringOutput (This, L"\r\n");
}
break;
}
}
//
// Update cursor position
//
This->CursorX = CursorX;
This->CursorY = CursorY;
VgaCursorSetPosition (This, CursorX, CursorY, ScreenWidth);
return EFI_SUCCESS;
}
// ========================================================================
// sub_34BC -- VgaTextTestStringValid: validate Unicode string for VGA
// ========================================================================
EFI_STATUS
VgaTextTestStringValid (
IN VGA_CLASS_INSTANCE *This,
IN CHAR16 *String
)
{
CHAR16 CurrentChar;
for (; *String != 0; String++) {
CurrentChar = *String;
//
// ASCII printable range (0x20-0x7F)
//
if ((CurrentChar - 0x20) > 0x5F) {
//
// Check for control characters (0x00-0x0D with supported set)
//
if (CurrentChar > 0x0D ||
CurrentChar < 0x08) {
//
// Check for OEM character range
//
if (((CurrentChar & 0xFF00) - 0x2100) & 0xFBFF) {
return EFI_UNSUPPORTED;
}
//
// Look up in OEM-to-VGA translation table
//
if (!VgaOemCharTranslate (CurrentChar, NULL)) {
return EFI_UNSUPPORTED;
}
}
}
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_3550 -- VgaTextClearScreen: fill VGA text screen with spaces
// ========================================================================
EFI_STATUS
VgaTextClearScreen (
IN VGA_CLASS_INSTANCE *This
)
{
EFI_STATUS Status;
UINTN ScreenWidth;
UINTN ScreenHeight;
UINTN CursorX;
UINTN CursorY;
UINTN Stride;
UINT16 ClearData;
//
// Validate
//
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
//
// Get dimensions
//
Status = This->QueryMode (This, &ScreenWidth, &ScreenHeight);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Clear the entire screen buffer
//
Stride = ScreenWidth * 2; // Two bytes per character (char + attr)
ClearData = (This->Attribute << 8) | 0x20; // Space with current attribute
//
// Fill the VGA text region
//
for (CursorY = 0; CursorY < ScreenHeight; CursorY++) {
for (CursorX = 0; CursorX < ScreenWidth; CursorX++) {
*(UINT16 *)(UINTN)(This->FrameBufferAddress + CursorY * Stride + CursorX * 2) = ClearData;
}
}
//
// Set cursor to home (0,0)
//
This->SetCursor (This, 0, 0);
return EFI_SUCCESS;
}
// ========================================================================
// sub_362C -- VgaTextSetCursorPosition: set text cursor with bounds check
// ========================================================================
EFI_STATUS
VgaTextSetCursorPosition (
IN VGA_CLASS_INSTANCE *This,
IN UINTN Column,
IN UINTN Row
)
{
UINTN MaxCol;
UINTN MaxRow;
EFI_STATUS Status;
//
// Validate
//
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
//
// Get current mode dimensions
//
Status = This->QueryMode (This, &MaxCol, &MaxRow);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Bounds check
//
if (Column >= MaxCol || Row >= MaxRow) {
return EFI_UNSUPPORTED;
}
//
// Set cursor position via CRT controller registers
//
VgaCursorSetPosition (This, Column, Row, MaxCol);
//
// Update internal state
//
This->CursorX = Column;
This->CursorY = Row;
return EFI_SUCCESS;
}
// ========================================================================
// sub_36D0 -- VgaTextEnableCursor: enable/disable cursor
// ========================================================================
EFI_STATUS
VgaTextEnableCursor (
IN VGA_CLASS_INSTANCE *This,
IN BOOLEAN Enable
)
{
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
//
// Enable cursor via INT10: AH=01h, CH=cursor start, CL=cursor end
//
if (Enable) {
if (This->ModeTableSize == 1) {
// 80x25: cursor start=6, end=7
VgaWriteCrtRegister (This, CRTC_CURSOR_START, 6);
VgaWriteCrtRegister (This, CRTC_CURSOR_END, 7);
} else {
// 80x50: cursor start=14, end=15
VgaWriteCrtRegister (This, CRTC_CURSOR_START, 14);
VgaWriteCrtRegister (This, CRTC_CURSOR_END, 15);
}
} else {
//
// Disable cursor by moving it off screen
//
VgaWriteCrtRegister (This, CRTC_CURSOR_START, 0x20);
}
This->CursorEnabled = Enable;
return EFI_SUCCESS;
}
// ========================================================================
// sub_3770 -- VgaTextQueryModeInfo: return cols/rows for VGA text mode
// ========================================================================
EFI_STATUS
VgaTextQueryModeInfo (
IN VGA_CLASS_INSTANCE *This,
IN UINTN ModeIndex,
OUT UINTN *Columns,
OUT UINTN *Rows
)
{
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
}
//
// Validate mode index
//
if (ModeIndex >= This->ModeTableSize) {
if (Columns) *Columns = 0;
if (Rows) *Rows = 0;
return EFI_UNSUPPORTED;
}
//
// Mode 0 = 80x25, Mode 1 = 80x50
//
if (ModeIndex == 0) {
if (Columns) *Columns = VGA_TEXT_MODE_0_COLS;
if (Rows) *Rows = VGA_TEXT_MODE_0_ROWS;
} else {
if (Columns) *Columns = VGA_TEXT_MODE_1_COLS;
if (Rows) *Rows = VGA_TEXT_MODE_1_ROWS;
}
return EFI_SUCCESS;
}
// ========================================================================
// sub_3810 -- VgaTextSetMode: select VGA text mode
// ========================================================================
EFI_STATUS
VgaTextSetMode (
IN VGA_CLASS_INSTANCE *This,
IN UINTN ModeIndex
)
{
if (This->Signature != VGA_CLASS_INSTANCE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "CR has Bad Signature\n"));
return EFI_INVALID_PARAMETER;
}
if (ModeIndex >= This->ModeTableSize) {
return EFI_UNSUPPORTED;
}
//
// Clear the current screen
//
This->ClearScreen (This);
//
// Store current mode index
//
This->CurrentMode = (UINT32)ModeIndex;
//
// Program the frame buffer mode
//
return This->FrameBufferModeSet (This->FrameBufferAccess, ModeIndex);
}
// ========================================================================
// sub_388C -- VgaCursorSetPosition: program cursor via CRT registers
// ========================================================================
EFI_STATUS
VgaCursorSetPosition (
IN VGA_CLASS_INSTANCE *This,
IN UINTN X,
IN UINTN Y,
IN UINTN ScreenWidth
)
{
UINTN CursorOffset;
//
// Calculate linear cursor offset
//
CursorOffset = X + ScreenWidth * Y;
//
// Write cursor location high byte to CRTC register 0x0E
//
VgaWriteCrtRegister (This, CRTC_CURSOR_LOC_HIGH, (CursorOffset >> 8));
//
// Write cursor location low byte to CRTC register 0x0F
//
VgaWriteCrtRegister (This, CRTC_CURSOR_LOC_LOW, (CursorOffset & 0xFF));
return EFI_SUCCESS;
}
// ========================================================================
// sub_38F4 -- VgaWriteCrtRegister: write CRTC register
// ========================================================================
EFI_STATUS
VgaWriteCrtRegister (
IN VGA_CLASS_INSTANCE *This,
IN UINT8 RegisterIndex,
IN UINT8 Value
)
{
//
// VGA: write index to 0x3D4 (CRTC index register), data to 0x3D5 (CRTC data register)
//
__outbyte (CRTC_INDEX_PORT, RegisterIndex);
__outbyte (CRTC_DATA_PORT, Value);
return EFI_SUCCESS;
}
// ========================================================================
// sub_396C -- VgaOemCharTranslate: convert OEM/Unicode to VGA glyph
// ========================================================================
BOOLEAN
VgaOemCharTranslate (
IN CHAR16 UnicodeChar,
OUT CHAR8 *Glyph
)
{
//
// OEM character range: Unicode code page 437 / OEM
// Ranges: 0x2100-0x21FF / 0x2500-0x257F for box drawing, etc.
//
if (((UnicodeChar & 0xFF00) - 0x2100) & 0xFBFF) {
return FALSE;
}
//
// Look up the character in the translation table (a global static list)
// The table maps pairs of (Unicode, VGA_Index)
//
{
extern CHAR16 gOemCharTable[];
CHAR16 *Entry = gOemCharTable;
while (*Entry != 0) {
if (*Entry == UnicodeChar) {
if (Glyph != NULL) {
*Glyph = (CHAR8)*(Entry + 1);
}
return TRUE;
}
Entry += 2;
}
}
return FALSE;
}
// ========================================================================
// sub_568 -- IsVgaEnableCheck: check if any child has VGA enable
// ========================================================================
BOOLEAN
IsVgaEnableCheck (
IN EFI_HANDLE ChildHandle
)
{
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
UINTN OpenInfoCount;
EFI_STATUS Status;
UINTN Index;
BOOLEAN VgaEnabled;
VgaEnabled = FALSE;
//
// Open protocol info for EDID_ACTIVE on this handle
//
Status = gBS->OpenProtocolInformation (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
&OpenInfoBuffer,
&OpenInfoCount
);
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// Check each open protocol entry for BIT3 (VGA enable flag)
//
for (Index = 0; Index < OpenInfoCount; Index++) {
if (OpenInfoBuffer[Index].Attributes & 0x08) {
VgaEnabled = TRUE;
break;
}
}
gBS->FreePool (OpenInfoBuffer);
return VgaEnabled;
}
// ========================================================================
// sub_5E0 -- LegacyBiosPlatformSetVideoController: set/clear video owner
// ========================================================================
EFI_STATUS
LegacyBiosPlatformSetVideoController (
IN CSM_VIDEO_INSTANCE *Instance,
IN BOOLEAN SetAsActive,
IN BOOLEAN Force
)
{
EFI_STATUS Status;
EFI_HANDLE BiosPlatformHandle;
BiosPlatformHandle = gLegacyBiosPlatformHandle;
//
// If no platform handle or already in the desired state, skip
//
if (BiosPlatformHandle == NULL) {
return EFI_SUCCESS;
}
//
// Check if the current state matches the request (byte_5770 optimization)
//
if (gIsLegacyVgaMode == SetAsActive && !Force) {
return EFI_SUCCESS;
}
//
// Set or clear VGA controller ownership on the legacy BIOS platform
//
if (SetAsActive) {
Status = gBS->SignalEvent (BiosPlatformHandle);
} else {
Status = gBS->CheckEvent (BiosPlatformHandle);
}
if (EFI_ERROR (Status)) {
gIsLegacyVgaMode = !SetAsActive;
return Status;
}
return Status < 0 ? Status : (SetAsActive != gIsLegacyVgaMode ?
EFI_UNSUPPORTED : EFI_SUCCESS);
}
// ========================================================================
// sub_6B0 -- IsPciRootBridgeVgaCompatible: check PCI class code
// ========================================================================
EFI_STATUS
IsPciRootBridgeVgaCompatible (
IN CSM_VIDEO_INSTANCE *Instance,
IN EFI_HANDLE ChildHandle
)
{
EFI_STATUS Status;
UINT8 Class[3];
EFI_PCI_IO_PROTOCOL *PciIo;
//
// Get PCI IO protocol on the child handle
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
(VOID **)&PciIo,
Instance->ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Read PCI class code
//
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
0x0B,
3,
Class
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check if VGA compatible (class 3, subclass 0, prog IF 0)
// or VGA-compatible (class 3, any subclass, prog IF 0)
//
if (Class[2] == 3 && Class[1] == 0 && Class[0] == 0) {
return EFI_SUCCESS; // Is VGA compatible
}
//
// Close protocol
//
gBS->CloseProtocol (
ChildHandle,
&gEfiEdidActiveProtocolGuid,
Instance->ImageHandle,
ChildHandle
);
return EFI_UNSUPPORTED;
}
// ========================================================================
// sub_2E0 -- CopyMemInternal: low-level memcpy
// ========================================================================
VOID *
CopyMemInternal (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
//
// Handle overlapping case: if Source < Dest and overlap detected,
// copy backwards from end
//
if (Source < Destination &&
(UINT8 *)Source + Length - 1 >= (UINT8 *)Destination) {
//
// Copy backwards
//
return CopyMemBackwards (Destination, Source, Length);
}
//
// Copy forwards with 8-byte chunks then remaining bytes
//
return CopyMemForward (Destination, Source, Length);
}
// ========================================================================
// sub_4310 -- CmosReadVideoType: get video type from CMOS
// ========================================================================
UINTN
CmosReadVideoType (
VOID
)
{
UINT8 VideoType;
UINT8 NmiBits;
//
// Read CMOS register 0x4B (video type)
//
NmiBits = __inbyte (0x70) & 0x80;
__outbyte (0x70, NmiBits | CMOS_REG_VIDEO_TYPE);
VideoType = __inbyte (0x71);
if ((UINT8)(VideoType - 1) > 0xFD) {
return 0; // Invalid or non-standard video
}
if (VideoType == CMOS_VIDEO_VGA) {
return 0x80000004; // EFI_VGA_DEVICE
}
return 0x80000006; // EFI_LEGACY_VIDEO_DEVICE
}
// ========================================================================
// sub_46AE -- SetMem: memset with alignment optimization
// ========================================================================
VOID *
SetMem (
OUT VOID *Buffer,
IN UINTN Length,
IN UINT8 Value
)
{
UINT8 *Buf = (UINT8 *)Buffer;
UINT64 QuadValue;
UINTN AlignedCount;
//
// Build 64-bit word: 8 copies of Value
//
QuadValue = Value;
QuadValue |= (Value << 8);
QuadValue |= (QuadValue << 16);
QuadValue |= (QuadValue << 32);
//
// Align to 4-byte boundary
//
if (Length >= 4 && ((UINTN)Buf & 3)) {
UINTN Misalign = 4 - ((UINTN)Buf & 3);
gBS->SetMem (Buf, Misalign, Value);
Buf += Misalign;
Length -= Misalign;
}
//
// Write aligned 32-bit words
//
for (AlignedCount = Length >> 2; AlignedCount > 0; AlignedCount--) {
*(UINT32 *)Buf = (UINT32)QuadValue;
Buf += 4;
Length -= 4;
}
//
// Write remaining bytes
//
if (Length > 0) {
gBS->SetMem (Buf, Length, Value);
}
return Buffer;
}
// ========================================================================
// sub_4700 -- CopyMemOverlapped: memcpy with direction detection
// ========================================================================
VOID *
CopyMemOverlapped (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
UINT8 *Dst = (UINT8 *)Destination;
CONST UINT8 *Src = (CONST UINT8 *)Source;
BOOLEAN Backward = FALSE;
//
// Determine direction: backward if src < dst && overlap
//
if (Src < Dst && (Src + Length) > Dst) {
Backward = TRUE;
Src += Length;
Dst += Length;
}
//
// Fast aligned copy: 8 bytes at a time when both aligned
//
if (Length >= 8 && ((UINTN)Src & 7) == ((UINTN)Dst & 7)) {
if (Backward) {
Src -= 7;
Dst -= 7;
}
//
// Handle leading misaligned bytes
//
UINTN Align = (UINTN)Src & 7;
if (Align != 0) {
if (!Backward) {
Align = 8 - Align;
}
// Copy alignment bytes
// ...
}
//
// Copy aligned 8-byte chunks
//
UINTN Count = Length >> 3;
// qmemcpy with 8-byte alignment
// ...
Length &= 7;
if (Backward) {
Src += 8;
Dst += 8;
}
}
//
// Handle remaining bytes
//
if (Length > 0) {
if (Backward) {
Src--;
Dst--;
}
// qmemcpy remaining
}
return Destination;
}