X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FQemuVideoDxe%2FDriver.c;h=b91909a14e590b262d520e4383b02820109313a9;hb=HEAD;hp=cb3e34970dc0e1efe7f9d449230d150a1758ed8e;hpb=eaf4f336ea42dc32e1a5b31d6b7822c125a15d34;p=mirror_edk2.git
diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c
index cb3e34970d..c28171d137 100644
--- a/OvmfPkg/QemuVideoDxe/Driver.c
+++ b/OvmfPkg/QemuVideoDxe/Driver.c
@@ -2,21 +2,16 @@
This driver is a sample implementation of the Graphics Output Protocol for
the QEMU (Cirrus Logic 5446) video controller.
- Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Qemu.h"
+#include
-EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
+EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
QemuVideoControllerDriverSupported,
QemuVideoControllerDriverStart,
QemuVideoControllerDriverStop,
@@ -25,6 +20,83 @@ EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
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.
@@ -39,15 +111,15 @@ EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
EFI_STATUS
EFIAPI
QemuVideoControllerDriverSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ 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;
- EFI_DEV_PATH *Node;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ QEMU_VIDEO_CARD *Card;
//
// Open the PCI I/O Protocol
@@ -55,7 +127,7 @@ QemuVideoControllerDriverSupported (
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
- (VOID **) &PciIo,
+ (VOID **)&PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
@@ -79,46 +151,14 @@ QemuVideoControllerDriverSupported (
}
Status = EFI_UNSUPPORTED;
- //
- // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
- // at a time, so see if this is one that is turned on.
- //
- // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
- //
- // See if this is a Cirrus Logic PCI controller
- //
- if (Pci.Hdr.VendorId == CIRRUS_LOGIC_VENDOR_ID) {
- //
- // See if this is a 5430 or a 5446 PCI controller
- //
- if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_DEVICE_ID ||
- Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID ||
- Pci.Hdr.DeviceId == CIRRUS_LOGIC_5446_DEVICE_ID) {
-
- Status = EFI_SUCCESS;
- //
- // If this is an Intel 945 graphics controller,
- // go further check RemainingDevicePath validation
- //
- if (RemainingDevicePath != NULL) {
- Node = (EFI_DEV_PATH *) RemainingDevicePath;
- //
- // Check if RemainingDevicePath is the End of Device Path Node,
- // if yes, return EFI_SUCCESS
- //
- if (!IsDevicePathEnd (Node)) {
- //
- // If RemainingDevicePath isn't the End of Device Path Node,
- // check its validation
- //
- if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
- Node->DevPath.SubType != ACPI_ADR_DP ||
- DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
- 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:
@@ -126,11 +166,11 @@ Done:
// Close the PCI I/O Protocol
//
gBS->CloseProtocol (
- Controller,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
return Status;
}
@@ -151,32 +191,37 @@ Done:
EFI_STATUS
EFIAPI
QemuVideoControllerDriverStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
- EFI_STATUS Status;
- QEMU_VIDEO_PRIVATE_DATA *Private;
- BOOLEAN PciAttributesSaved;
- EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
- ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
+ 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);
- PciAttributesSaved = FALSE;
//
- // Allocate Private context data for GOP inteface.
+ // Allocate Private context data for GOP interface.
//
Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
if (Private == NULL) {
Status = EFI_OUT_OF_RESOURCES;
- goto Error;
+ goto RestoreTpl;
}
//
// Set up context record
//
- Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
- Private->Handle = NULL;
+ Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
//
// Open PCI I/O Protocol
@@ -184,38 +229,143 @@ QemuVideoControllerDriverStart (
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
- (VOID **) &Private->PciIo,
+ (VOID **)&Private->PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
- goto Error;
+ 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
- );
+ Private->PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->OriginalPciAttributes
+ );
if (EFI_ERROR (Status)) {
- goto Error;
+ goto ClosePciIo;
}
- PciAttributesSaved = TRUE;
+ //
+ // Get supported PCI attributes
+ //
Status = Private->PciIo->Attributes (
- Private->PciIo,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
- NULL
- );
+ Private->PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &SupportedVgaIo
+ );
if (EFI_ERROR (Status)) {
- goto Error;
+ 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;
+ }
}
//
@@ -224,113 +374,155 @@ QemuVideoControllerDriverStart (
Status = gBS->HandleProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
- (VOID **) &ParentDevicePath
+ (VOID **)&ParentDevicePath
);
if (EFI_ERROR (Status)) {
- goto Error;
+ goto RestoreAttributes;
}
//
// Set Gop Device Path
//
- if (RemainingDevicePath == NULL) {
- 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
- );
- } else if (!IsDevicePathEnd (RemainingDevicePath)) {
- //
- // If RemainingDevicePath isn't the End of Device Path Node,
- // only scan the specified device by RemainingDevicePath
- //
- Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
- } else {
- //
- // If RemainingDevicePath is the End of Device Path Node,
- // don't create child device and return EFI_SUCCESS
- //
- Private->GopDevicePath = NULL;
+ 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;
}
-
- if (Private->GopDevicePath != NULL) {
- //
- // Creat child handle and device path protocol firstly
- //
- Private->Handle = NULL;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Private->Handle,
- &gEfiDevicePathProtocolGuid,
- Private->GopDevicePath,
- NULL
- );
+
+ //
+ // 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
//
- Status = QemuVideoVideoModeSetup (Private);
- if (EFI_ERROR (Status)) {
- goto Error;
+ 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 (Private->GopDevicePath == NULL) {
- //
- // If RemainingDevicePath is the End of Device Path Node,
- // don't create child device and return EFI_SUCCESS
- //
- Status = EFI_SUCCESS;
- } else {
+ if (EFI_ERROR (Status)) {
+ goto UninstallGopDevicePath;
+ }
- //
- // Start the GOP software stack.
- //
- Status = QemuVideoGraphicsOutputConstructor (Private);
- ASSERT_EFI_ERROR (Status);
+ //
+ // Start the GOP software stack.
+ //
+ Status = QemuVideoGraphicsOutputConstructor (Private);
+ if (EFI_ERROR (Status)) {
+ goto FreeModeData;
+ }
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Private->Handle,
- &gEfiGraphicsOutputProtocolGuid,
- &Private->GraphicsOutput,
- NULL
- );
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto DestructQemuVideoGraphics;
}
-Error:
+ //
+ // 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)) {
- if (Private) {
- if (Private->PciIo) {
- if (PciAttributesSaved == TRUE) {
- //
- // Restore original PCI attributes
- //
- Private->PciIo->Attributes (
- Private->PciIo,
- EfiPciIoAttributeOperationSet,
- Private->OriginalPciAttributes,
- NULL
- );
- }
- //
- // Close the PCI I/O Protocol
- //
- gBS->CloseProtocol (
- Private->Handle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- Private->Handle
- );
- }
+ goto UninstallGop;
+ }
- gBS->FreePool (Private);
- }
+ #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;
}
@@ -350,21 +542,39 @@ Error:
EFI_STATUS
EFIAPI
QemuVideoControllerDriverStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
)
{
- EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
- EFI_STATUS Status;
+ 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 (
- Controller,
+ ChildHandleBuffer[0],
&gEfiGraphicsOutputProtocolGuid,
- (VOID **) &GraphicsOutput,
+ (VOID **)&GraphicsOutput,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -377,6 +587,7 @@ QemuVideoControllerDriverStop (
// Get our private context information
//
Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
+ ASSERT (Private->Handle == ChildHandleBuffer[0]);
QemuVideoGraphicsOutputDestructor (Private);
//
@@ -397,21 +608,26 @@ QemuVideoControllerDriverStop (
// Restore original PCI attributes
//
Private->PciIo->Attributes (
- Private->PciIo,
- EfiPciIoAttributeOperationSet,
- Private->OriginalPciAttributes,
- NULL
- );
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
- //
- // Close the PCI I/O Protocol
- //
gBS->CloseProtocol (
- Controller,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Private->Handle
+ );
+
+ FreePool (Private->ModeData);
+ gBS->UninstallProtocolInterface (
+ Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->GopDevicePath
+ );
+ FreePool (Private->GopDevicePath);
//
// Free our instance data
@@ -434,18 +650,18 @@ QemuVideoControllerDriverStop (
VOID
outb (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN Address,
- UINT8 Data
+ UINTN Address,
+ UINT8 Data
)
{
Private->PciIo->Io.Write (
- Private->PciIo,
- EfiPciIoWidthUint8,
- EFI_PCI_IO_PASS_THROUGH_BAR,
- Address,
- 1,
- &Data
- );
+ Private->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
}
/**
@@ -461,18 +677,18 @@ outb (
VOID
outw (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN Address,
- UINT16 Data
+ UINTN Address,
+ UINT16 Data
)
{
Private->PciIo->Io.Write (
- Private->PciIo,
- EfiPciIoWidthUint16,
- EFI_PCI_IO_PASS_THROUGH_BAR,
- Address,
- 1,
- &Data
- );
+ Private->PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
}
/**
@@ -487,19 +703,19 @@ outw (
UINT8
inb (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN Address
+ UINTN Address
)
{
- UINT8 Data;
+ UINT8 Data;
Private->PciIo->Io.Read (
- Private->PciIo,
- EfiPciIoWidthUint8,
- EFI_PCI_IO_PASS_THROUGH_BAR,
- Address,
- 1,
- &Data
- );
+ Private->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
return Data;
}
@@ -515,19 +731,19 @@ inb (
UINT16
inw (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN Address
+ UINTN Address
)
{
UINT16 Data;
Private->PciIo->Io.Read (
- Private->PciIo,
- EfiPciIoWidthUint16,
- EFI_PCI_IO_PASS_THROUGH_BAR,
- Address,
- 1,
- &Data
- );
+ Private->PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
return Data;
}
@@ -546,16 +762,16 @@ inw (
VOID
SetPaletteColor (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN Index,
- UINT8 Red,
- UINT8 Green,
- UINT8 Blue
+ UINTN Index,
+ UINT8 Red,
+ UINT8 Green,
+ UINT8 Blue
)
{
- outb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
- outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
- outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
- outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
+ 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));
}
/**
@@ -571,16 +787,16 @@ SetDefaultPalette (
QEMU_VIDEO_PRIVATE_DATA *Private
)
{
- UINTN Index;
- UINTN RedIndex;
- UINTN GreenIndex;
- UINTN BlueIndex;
+ 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));
+ SetPaletteColor (Private, Index, (UINT8)(RedIndex << 5), (UINT8)(GreenIndex << 5), (UINT8)(BlueIndex << 6));
Index++;
}
}
@@ -606,7 +822,7 @@ ClearScreen (
Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthFillUint32,
- 0,
+ Private->FrameBufferVramBarIndex,
0,
0x400000 >> 2,
&Color
@@ -624,8 +840,8 @@ ClearScreen (
VOID
DrawLogo (
QEMU_VIDEO_PRIVATE_DATA *Private,
- UINTN ScreenWidth,
- UINTN ScreenHeight
+ UINTN ScreenWidth,
+ UINTN ScreenHeight
)
{
}
@@ -640,27 +856,13 @@ DrawLogo (
**/
VOID
-InitializeGraphicsMode (
+InitializeCirrusGraphicsMode (
QEMU_VIDEO_PRIVATE_DATA *Private,
- QEMU_VIDEO_VIDEO_MODES *ModeData
+ QEMU_VIDEO_CIRRUS_MODES *ModeData
)
{
- UINT8 Byte;
- UINTN Index;
- UINT16 DeviceId;
- EFI_STATUS Status;
-
- Status = Private->PciIo->Pci.Read (
- Private->PciIo,
- EfiPciIoWidthUint16,
- PCI_DEVICE_ID_OFFSET,
- 1,
- &DeviceId
- );
- //
- // Read the PCI Configuration Header from the PCI Device
- //
- ASSERT_EFI_ERROR (Status);
+ UINT8 Byte;
+ UINTN Index;
outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
@@ -669,9 +871,9 @@ InitializeGraphicsMode (
outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
}
- if (DeviceId != CIRRUS_LOGIC_5446_DEVICE_ID) {
+ if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
- Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
+ Byte = (UINT8)((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
outb (Private, SEQ_DATA_REGISTER, Byte);
}
@@ -681,17 +883,17 @@ InitializeGraphicsMode (
outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
for (Index = 0; Index < 28; Index++) {
- outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | 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));
+ 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, (UINT8)Index);
outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
}
@@ -706,14 +908,160 @@ InitializeGraphicsMode (
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
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
@@ -725,18 +1073,5 @@ InitializeQemuVideo (
);
ASSERT_EFI_ERROR (Status);
- //
- // Install EFI Driver Supported EFI Version Protocol required for
- // EFI drivers that are on PCI and other plug in cards.
- //
- gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
- Status = gBS->InstallMultipleProtocolInterfaces (
- &ImageHandle,
- &gEfiDriverSupportedEfiVersionProtocolGuid,
- &gQemuVideoDriverSupportedEfiVersion,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
return Status;
}