blob: c28171d1371991a1f46150773af91b10571cc72f [file] [log] [blame]
/** @file
This driver is a sample implementation of the Graphics Output Protocol for
the QEMU (Cirrus Logic 5446) video controller.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Qemu.h"
#include <IndustryStandard/Acpi.h>
EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
QemuVideoControllerDriverSupported,
QemuVideoControllerDriverStart,
QemuVideoControllerDriverStop,
0x10,
NULL,
NULL
};
QEMU_VIDEO_CARD gQemuVideoCardList[] = {
{
PCI_CLASS_DISPLAY_VGA,
CIRRUS_LOGIC_VENDOR_ID,
CIRRUS_LOGIC_5430_DEVICE_ID,
QEMU_VIDEO_CIRRUS_5430,
L"Cirrus 5430"
},{
PCI_CLASS_DISPLAY_VGA,
CIRRUS_LOGIC_VENDOR_ID,
CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
QEMU_VIDEO_CIRRUS_5430,
L"Cirrus 5430"
},{
PCI_CLASS_DISPLAY_VGA,
CIRRUS_LOGIC_VENDOR_ID,
CIRRUS_LOGIC_5446_DEVICE_ID,
QEMU_VIDEO_CIRRUS_5446,
L"Cirrus 5446"
},{
PCI_CLASS_DISPLAY_VGA,
0x1234,
0x1111,
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU Standard VGA"
},{
PCI_CLASS_DISPLAY_OTHER,
0x1234,
0x1111,
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU Standard VGA (secondary)"
},{
PCI_CLASS_DISPLAY_VGA,
0x1b36,
0x0100,
QEMU_VIDEO_BOCHS,
L"QEMU QXL VGA"
},{
PCI_CLASS_DISPLAY_VGA,
0x1af4,
0x1050,
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU VirtIO VGA"
},{
PCI_CLASS_DISPLAY_VGA,
0x15ad,
0x0405,
QEMU_VIDEO_VMWARE_SVGA,
L"QEMU VMWare SVGA"
},{
0 /* end of list */
}
};
static QEMU_VIDEO_CARD *
QemuVideoDetect (
IN UINT8 SubClass,
IN UINT16 VendorId,
IN UINT16 DeviceId
)
{
UINTN Index = 0;
while (gQemuVideoCardList[Index].VendorId != 0) {
if ((gQemuVideoCardList[Index].SubClass == SubClass) &&
(gQemuVideoCardList[Index].VendorId == VendorId) &&
(gQemuVideoCardList[Index].DeviceId == DeviceId))
{
return gQemuVideoCardList + Index;
}
Index++;
}
return NULL;
}
/**
Check if this device is supported.
@param This The driver binding protocol.
@param Controller The controller handle to check.
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The bus supports this controller.
@retval EFI_UNSUPPORTED This device isn't supported.
**/
EFI_STATUS
EFIAPI
QemuVideoControllerDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
QEMU_VIDEO_CARD *Card;
//
// Open the PCI I/O Protocol
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Read the PCI Configuration Header from the PCI Device
//
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = EFI_UNSUPPORTED;
if (!IS_PCI_DISPLAY (&Pci)) {
goto Done;
}
Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
if (Card != NULL) {
DEBUG ((DEBUG_INFO, "QemuVideo: %s detected\n", Card->Name));
Status = EFI_SUCCESS;
}
Done:
//
// Close the PCI I/O Protocol
//
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Start to process the controller.
@param This The USB bus driver binding instance.
@param Controller The controller to check.
@param RemainingDevicePath The remaining device patch.
@retval EFI_SUCCESS The controller is controlled by the usb bus.
@retval EFI_ALREADY_STARTED The controller is already controlled by the usb
bus.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
**/
EFI_STATUS
EFIAPI
QemuVideoControllerDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_TPL OldTpl;
EFI_STATUS Status;
QEMU_VIDEO_PRIVATE_DATA *Private;
BOOLEAN IsQxl;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
PCI_TYPE00 Pci;
QEMU_VIDEO_CARD *Card;
EFI_PCI_IO_PROTOCOL *ChildPciIo;
UINT64 SupportedVgaIo;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Allocate Private context data for GOP interface.
//
Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
if (Private == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto RestoreTpl;
}
//
// Set up context record
//
Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
//
// Open PCI I/O Protocol
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **)&Private->PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto FreePrivate;
}
//
// Read the PCI Configuration Header from the PCI Device
//
Status = Private->PciIo->Pci.Read (
Private->PciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci
);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
//
// Determine card variant.
//
Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
if (Card == NULL) {
Status = EFI_DEVICE_ERROR;
goto ClosePciIo;
}
Private->Variant = Card->Variant;
//
// IsQxl is based on the detected Card->Variant, which at a later point might
// not match Private->Variant.
//
IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);
//
// Save original PCI attributes
//
Status = Private->PciIo->Attributes (
Private->PciIo,
EfiPciIoAttributeOperationGet,
0,
&Private->OriginalPciAttributes
);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
//
// Get supported PCI attributes
//
Status = Private->PciIo->Attributes (
Private->PciIo,
EfiPciIoAttributeOperationSupported,
0,
&SupportedVgaIo
);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
SupportedVgaIo &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
if ((SupportedVgaIo == 0) && IS_PCI_VGA (&Pci)) {
Status = EFI_UNSUPPORTED;
goto ClosePciIo;
}
//
// Set new PCI attributes
//
Status = Private->PciIo->Attributes (
Private->PciIo,
EfiPciIoAttributeOperationEnable,
EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo,
NULL
);
if (EFI_ERROR (Status)) {
goto ClosePciIo;
}
//
// Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
//
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
Status = Private->PciIo->GetBarAttributes (
Private->PciIo,
PCI_BAR_IDX2,
NULL,
(VOID **)&MmioDesc
);
if (EFI_ERROR (Status) ||
(MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM))
{
DEBUG ((DEBUG_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
Private->Variant = QEMU_VIDEO_BOCHS;
} else {
DEBUG ((
DEBUG_INFO,
"QemuVideo: Using mmio bar @ 0x%lx\n",
MmioDesc->AddrRangeMin
));
}
if (!EFI_ERROR (Status)) {
FreePool (MmioDesc);
}
}
//
// VMWare SVGA is handled like Bochs (with port IO only).
//
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
Private->Variant = QEMU_VIDEO_BOCHS;
Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;
}
//
// Check if accessing the bochs interface works.
//
if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||
(Private->Variant == QEMU_VIDEO_BOCHS))
{
UINT16 BochsId;
BochsId = BochsRead (Private, VBE_DISPI_INDEX_ID);
if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
DEBUG ((DEBUG_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
Status = EFI_DEVICE_ERROR;
goto RestoreAttributes;
}
}
//
// Get ParentDevicePath
//
Status = gBS->HandleProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **)&ParentDevicePath
);
if (EFI_ERROR (Status)) {
goto RestoreAttributes;
}
//
// Set Gop Device Path
//
ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
Private->GopDevicePath = AppendDevicePathNode (
ParentDevicePath,
(EFI_DEVICE_PATH_PROTOCOL *)&AcpiDeviceNode
);
if (Private->GopDevicePath == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto RestoreAttributes;
}
//
// Create new child handle and install the device path protocol on it.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Private->Handle,
&gEfiDevicePathProtocolGuid,
Private->GopDevicePath,
NULL
);
if (EFI_ERROR (Status)) {
goto FreeGopDevicePath;
}
//
// Construct video mode buffer
//
switch (Private->Variant) {
case QEMU_VIDEO_CIRRUS_5430:
case QEMU_VIDEO_CIRRUS_5446:
Status = QemuVideoCirrusModeSetup (Private);
break;
case QEMU_VIDEO_BOCHS_MMIO:
case QEMU_VIDEO_BOCHS:
Status = QemuVideoBochsModeSetup (Private, IsQxl);
break;
default:
ASSERT (FALSE);
Status = EFI_DEVICE_ERROR;
break;
}
if (EFI_ERROR (Status)) {
goto UninstallGopDevicePath;
}
//
// Start the GOP software stack.
//
Status = QemuVideoGraphicsOutputConstructor (Private);
if (EFI_ERROR (Status)) {
goto FreeModeData;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&Private->Handle,
&gEfiGraphicsOutputProtocolGuid,
&Private->GraphicsOutput,
NULL
);
if (EFI_ERROR (Status)) {
goto DestructQemuVideoGraphics;
}
//
// Reference parent handle from child handle.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **)&ChildPciIo,
This->DriverBindingHandle,
Private->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
goto UninstallGop;
}
#if defined MDE_CPU_IA32 || defined MDE_CPU_X64
if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||
(Private->Variant == QEMU_VIDEO_BOCHS))
{
InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
}
#endif
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
UninstallGop:
gBS->UninstallProtocolInterface (
Private->Handle,
&gEfiGraphicsOutputProtocolGuid,
&Private->GraphicsOutput
);
DestructQemuVideoGraphics:
QemuVideoGraphicsOutputDestructor (Private);
FreeModeData:
FreePool (Private->ModeData);
UninstallGopDevicePath:
gBS->UninstallProtocolInterface (
Private->Handle,
&gEfiDevicePathProtocolGuid,
Private->GopDevicePath
);
FreeGopDevicePath:
FreePool (Private->GopDevicePath);
RestoreAttributes:
Private->PciIo->Attributes (
Private->PciIo,
EfiPciIoAttributeOperationSet,
Private->OriginalPciAttributes,
NULL
);
ClosePciIo:
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
FreePrivate:
FreePool (Private);
RestoreTpl:
gBS->RestoreTPL (OldTpl);
return Status;
}
/**
Stop this device
@param This The USB bus driver binding protocol.
@param Controller The controller to release.
@param NumberOfChildren The number of children of this device that
opened the controller BY_CHILD.
@param ChildHandleBuffer The array of child handle.
@retval EFI_SUCCESS The controller or children are stopped.
@retval EFI_DEVICE_ERROR Failed to stop the driver.
**/
EFI_STATUS
EFIAPI
QemuVideoControllerDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_STATUS Status;
QEMU_VIDEO_PRIVATE_DATA *Private;
if (NumberOfChildren == 0) {
//
// Close the PCI I/O Protocol
//
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return EFI_SUCCESS;
}
//
// free all resources for whose access we need the child handle, because the
// child handle is going away
//
ASSERT (NumberOfChildren == 1);
Status = gBS->OpenProtocol (
ChildHandleBuffer[0],
&gEfiGraphicsOutputProtocolGuid,
(VOID **)&GraphicsOutput,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get our private context information
//
Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
ASSERT (Private->Handle == ChildHandleBuffer[0]);
QemuVideoGraphicsOutputDestructor (Private);
//
// Remove the GOP protocol interface from the system
//
Status = gBS->UninstallMultipleProtocolInterfaces (
Private->Handle,
&gEfiGraphicsOutputProtocolGuid,
&Private->GraphicsOutput,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Restore original PCI attributes
//
Private->PciIo->Attributes (
Private->PciIo,
EfiPciIoAttributeOperationSet,
Private->OriginalPciAttributes,
NULL
);
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Private->Handle
);
FreePool (Private->ModeData);
gBS->UninstallProtocolInterface (
Private->Handle,
&gEfiDevicePathProtocolGuid,
Private->GopDevicePath
);
FreePool (Private->GopDevicePath);
//
// Free our instance data
//
gBS->FreePool (Private);
return EFI_SUCCESS;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Address TODO: add argument description
@param Data TODO: add argument description
TODO: add return values
**/
VOID
outb (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Address,
UINT8 Data
)
{
Private->PciIo->Io.Write (
Private->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Address TODO: add argument description
@param Data TODO: add argument description
TODO: add return values
**/
VOID
outw (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Address,
UINT16 Data
)
{
Private->PciIo->Io.Write (
Private->PciIo,
EfiPciIoWidthUint16,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Address TODO: add argument description
TODO: add return values
**/
UINT8
inb (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Address
)
{
UINT8 Data;
Private->PciIo->Io.Read (
Private->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
return Data;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Address TODO: add argument description
TODO: add return values
**/
UINT16
inw (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Address
)
{
UINT16 Data;
Private->PciIo->Io.Read (
Private->PciIo,
EfiPciIoWidthUint16,
EFI_PCI_IO_PASS_THROUGH_BAR,
Address,
1,
&Data
);
return Data;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Index TODO: add argument description
@param Red TODO: add argument description
@param Green TODO: add argument description
@param Blue TODO: add argument description
TODO: add return values
**/
VOID
SetPaletteColor (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Index,
UINT8 Red,
UINT8 Green,
UINT8 Blue
)
{
VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8)Index);
VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Red >> 2));
VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Green >> 2));
VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Blue >> 2));
}
/**
TODO: Add function description
@param Private TODO: add argument description
TODO: add return values
**/
VOID
SetDefaultPalette (
QEMU_VIDEO_PRIVATE_DATA *Private
)
{
UINTN Index;
UINTN RedIndex;
UINTN GreenIndex;
UINTN BlueIndex;
Index = 0;
for (RedIndex = 0; RedIndex < 8; RedIndex++) {
for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
SetPaletteColor (Private, Index, (UINT8)(RedIndex << 5), (UINT8)(GreenIndex << 5), (UINT8)(BlueIndex << 6));
Index++;
}
}
}
}
/**
TODO: Add function description
@param Private TODO: add argument description
TODO: add return values
**/
VOID
ClearScreen (
QEMU_VIDEO_PRIVATE_DATA *Private
)
{
UINT32 Color;
Color = 0;
Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthFillUint32,
Private->FrameBufferVramBarIndex,
0,
0x400000 >> 2,
&Color
);
}
/**
TODO: Add function description
@param Private TODO: add argument description
TODO: add return values
**/
VOID
DrawLogo (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN ScreenWidth,
UINTN ScreenHeight
)
{
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param ModeData TODO: add argument description
TODO: add return values
**/
VOID
InitializeCirrusGraphicsMode (
QEMU_VIDEO_PRIVATE_DATA *Private,
QEMU_VIDEO_CIRRUS_MODES *ModeData
)
{
UINT8 Byte;
UINTN Index;
outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
for (Index = 0; Index < 15; Index++) {
outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
}
if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
Byte = (UINT8)((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
outb (Private, SEQ_DATA_REGISTER, Byte);
}
outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
for (Index = 0; Index < 28; Index++) {
outw (Private, CRTC_ADDRESS_REGISTER, (UINT16)((ModeData->CrtcSettings[Index] << 8) | Index));
}
for (Index = 0; Index < 9; Index++) {
outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16)((GraphicsController[Index] << 8) | Index));
}
inb (Private, INPUT_STATUS_1_REGISTER);
for (Index = 0; Index < 21; Index++) {
outb (Private, ATT_ADDRESS_REGISTER, (UINT8)Index);
outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
}
outb (Private, ATT_ADDRESS_REGISTER, 0x20);
outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
SetDefaultPalette (Private);
ClearScreen (Private);
}
VOID
BochsWrite (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Reg,
UINT16 Data
)
{
EFI_STATUS Status;
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
Status = Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthUint16,
PCI_BAR_IDX2,
0x500 + (Reg << 1),
1,
&Data
);
ASSERT_EFI_ERROR (Status);
} else {
outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
outw (Private, VBE_DISPI_IOPORT_DATA, Data);
}
}
UINT16
BochsRead (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Reg
)
{
EFI_STATUS Status;
UINT16 Data;
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
Status = Private->PciIo->Mem.Read (
Private->PciIo,
EfiPciIoWidthUint16,
PCI_BAR_IDX2,
0x500 + (Reg << 1),
1,
&Data
);
ASSERT_EFI_ERROR (Status);
} else {
outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
Data = inw (Private, VBE_DISPI_IOPORT_DATA);
}
return Data;
}
VOID
VgaOutb (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Reg,
UINT8 Data
)
{
EFI_STATUS Status;
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
Status = Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthUint8,
PCI_BAR_IDX2,
0x400 - 0x3c0 + Reg,
1,
&Data
);
ASSERT_EFI_ERROR (Status);
} else {
outb (Private, Reg, Data);
}
}
STATIC
UINT8
VgaInb (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINTN Reg
)
{
EFI_STATUS Status;
UINT8 Data;
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
Data = 0;
Status = Private->PciIo->Mem.Read (
Private->PciIo,
EfiPciIoWidthUint8,
PCI_BAR_IDX2,
0x400 - 0x3c0 + Reg,
1,
&Data
);
ASSERT_EFI_ERROR (Status);
} else {
Data = inb (Private, Reg);
}
return Data;
}
VOID
InitializeBochsGraphicsMode (
QEMU_VIDEO_PRIVATE_DATA *Private,
QEMU_VIDEO_MODE_DATA *ModeData
)
{
DEBUG ((
DEBUG_INFO,
"InitializeBochsGraphicsMode: %dx%d @ %d\n",
ModeData->HorizontalResolution,
ModeData->VerticalResolution,
ModeData->ColorDepth
));
/* set color mode */
VgaOutb (Private, MISC_OUTPUT_REGISTER, 0x01);
/* reset flip flop + unblank */
VgaInb (Private, INPUT_STATUS_1_REGISTER);
VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);
BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);
BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);
BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);
BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16)ModeData->ColorDepth);
BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16)ModeData->HorizontalResolution);
BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16)ModeData->HorizontalResolution);
BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16)ModeData->VerticalResolution);
BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16)ModeData->VerticalResolution);
BochsWrite (
Private,
VBE_DISPI_INDEX_ENABLE,
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED
);
SetDefaultPalette (Private);
ClearScreen (Private);
}
EFI_STATUS
EFIAPI
InitializeQemuVideo (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gQemuVideoDriverBinding,
ImageHandle,
&gQemuVideoComponentName,
&gQemuVideoComponentName2
);
ASSERT_EFI_ERROR (Status);
return Status;
}