2011-04-12 17:08:51 +02:00
|
|
|
/** @file
|
|
|
|
This driver is a sample implementation of the Graphics Output Protocol for
|
|
|
|
the QEMU (Cirrus Logic 5446) video controller.
|
|
|
|
|
2019-05-09 19:38:07 +02:00
|
|
|
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
2011-04-12 17:08:51 +02:00
|
|
|
|
2019-04-04 01:06:33 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2011-04-12 17:08:51 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
2018-11-09 20:15:31 +01:00
|
|
|
#include "Qemu.h"
|
2018-11-02 04:23:59 +01:00
|
|
|
#include <IndustryStandard/Acpi.h>
|
2011-04-12 17:08:51 +02:00
|
|
|
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
|
|
|
|
QemuVideoControllerDriverSupported,
|
|
|
|
QemuVideoControllerDriverStart,
|
|
|
|
QemuVideoControllerDriverStop,
|
|
|
|
0x10,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
QEMU_VIDEO_CARD gQemuVideoCardList[] = {
|
|
|
|
{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2012-11-27 20:11:11 +01:00
|
|
|
CIRRUS_LOGIC_VENDOR_ID,
|
|
|
|
CIRRUS_LOGIC_5430_DEVICE_ID,
|
|
|
|
QEMU_VIDEO_CIRRUS_5430,
|
|
|
|
L"Cirrus 5430"
|
|
|
|
},{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2012-11-27 20:11:11 +01:00
|
|
|
CIRRUS_LOGIC_VENDOR_ID,
|
|
|
|
CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
|
|
|
|
QEMU_VIDEO_CIRRUS_5430,
|
|
|
|
L"Cirrus 5430"
|
|
|
|
},{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2012-11-27 20:11:11 +01:00
|
|
|
CIRRUS_LOGIC_VENDOR_ID,
|
|
|
|
CIRRUS_LOGIC_5446_DEVICE_ID,
|
|
|
|
QEMU_VIDEO_CIRRUS_5446,
|
|
|
|
L"Cirrus 5446"
|
2012-11-27 20:11:29 +01:00
|
|
|
},{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2012-11-27 20:11:29 +01:00
|
|
|
0x1234,
|
|
|
|
0x1111,
|
2012-11-27 20:11:45 +01:00
|
|
|
QEMU_VIDEO_BOCHS_MMIO,
|
2012-11-27 20:11:29 +01:00
|
|
|
L"QEMU Standard VGA"
|
2018-05-17 11:21:33 +02:00
|
|
|
},{
|
|
|
|
PCI_CLASS_DISPLAY_OTHER,
|
|
|
|
0x1234,
|
|
|
|
0x1111,
|
|
|
|
QEMU_VIDEO_BOCHS_MMIO,
|
|
|
|
L"QEMU Standard VGA (secondary)"
|
2012-11-27 20:11:29 +01:00
|
|
|
},{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2012-11-27 20:11:29 +01:00
|
|
|
0x1b36,
|
|
|
|
0x0100,
|
|
|
|
QEMU_VIDEO_BOCHS,
|
|
|
|
L"QEMU QXL VGA"
|
2015-06-23 22:47:27 +02:00
|
|
|
},{
|
2018-05-17 11:21:32 +02:00
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
2015-06-23 22:47:27 +02:00
|
|
|
0x1af4,
|
|
|
|
0x1050,
|
|
|
|
QEMU_VIDEO_BOCHS_MMIO,
|
|
|
|
L"QEMU VirtIO VGA"
|
2018-11-07 04:47:13 +01:00
|
|
|
},{
|
|
|
|
PCI_CLASS_DISPLAY_VGA,
|
|
|
|
0x15ad,
|
|
|
|
0x0405,
|
|
|
|
QEMU_VIDEO_VMWARE_SVGA,
|
|
|
|
L"QEMU VMWare SVGA"
|
2012-11-27 20:11:11 +01:00
|
|
|
},{
|
|
|
|
0 /* end of list */
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static QEMU_VIDEO_CARD *
|
|
|
|
QemuVideoDetect (
|
2018-05-17 11:21:32 +02:00
|
|
|
IN UINT8 SubClass,
|
2012-11-27 20:11:11 +01:00
|
|
|
IN UINT16 VendorId,
|
|
|
|
IN UINT16 DeviceId
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index = 0;
|
|
|
|
|
|
|
|
while (gQemuVideoCardList[Index].VendorId != 0) {
|
2018-05-17 11:21:32 +02:00
|
|
|
if ((gQemuVideoCardList[Index].SubClass == SubClass) &&
|
|
|
|
(gQemuVideoCardList[Index].VendorId == VendorId) &&
|
2012-11-27 20:11:11 +01:00
|
|
|
(gQemuVideoCardList[Index].DeviceId == DeviceId))
|
|
|
|
{
|
|
|
|
return gQemuVideoCardList + Index;
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
Index++;
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
/**
|
|
|
|
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;
|
2012-11-27 20:11:11 +01:00
|
|
|
QEMU_VIDEO_CARD *Card;
|
2011-04-12 17:08:51 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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;
|
2018-05-17 11:21:32 +02:00
|
|
|
if (!IS_PCI_DISPLAY (&Pci)) {
|
2016-08-18 11:01:56 +02:00
|
|
|
goto Done;
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2018-05-17 11:21:32 +02:00
|
|
|
Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
|
2012-11-27 20:11:11 +01:00
|
|
|
if (Card != NULL) {
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "QemuVideo: %s detected\n", Card->Name));
|
2012-11-27 20:11:11 +01:00
|
|
|
Status = EFI_SUCCESS;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
)
|
|
|
|
{
|
2014-03-22 08:13:44 +01:00
|
|
|
EFI_TPL OldTpl;
|
2012-11-27 20:11:45 +01:00
|
|
|
EFI_STATUS Status;
|
|
|
|
QEMU_VIDEO_PRIVATE_DATA *Private;
|
OvmfPkg: QemuVideoDxe: work around misreported QXL framebuffer size
When setting up the list of GOP modes offered on QEMU's stdvga ("VGA") and
QXL ("qxl-vga") video devices, QemuVideoBochsModeSetup() filters those
modes against the available framebuffer size. (Refer to SVN r15288 / git
commit ec88061e.)
The VBE_DISPI_INDEX_VIDEO_MEMORY_64K register of both stdvga and QXL is
supposed to report the size of the drawable, VGA-compatibility
framebuffer. Instead, up to and including qemu-2.1, this register actually
reports the full video RAM (PCI BAR 0) size.
In case of stdvga, this happens to be correct, because on that card the
full PCI BAR 0 is usable for drawing; there is no difference between
"drawable framebuffer size" and "video RAM (PCI BAR 0) size".
However, on the QXL card, only an initial portion of the video RAM is
suitable for drawing, as compatibility framebuffer; and the value
currently reported by VBE_DISPI_INDEX_VIDEO_MEMORY_64K overshoots the
valid size. Beyond the drawable range, the video RAM contains buffers and
structures for the QXL guest-host protocol.
Luckily, the size of the drawable QXL framebuffer can also be read from a
register in the QXL ROM BAR (PCI BAR 2), so let's retrieve it from there.
Without this fix, OVMF offers too large resolutions on the QXL card (up to
the full size of the video RAM). If a GOP client selects such a resolution
and draws into the video RAM past the compatibility segment, then the
guest corrupts its communication structures (which is invalid guest
behavior).
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15978 6f19259b-4bc3-4df7-8a09-765794883524
2014-08-29 19:27:20 +02:00
|
|
|
BOOLEAN IsQxl;
|
2012-11-27 20:11:45 +01:00
|
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
2014-03-03 09:40:28 +01:00
|
|
|
ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
|
2012-11-27 20:11:45 +01:00
|
|
|
PCI_TYPE00 Pci;
|
|
|
|
QEMU_VIDEO_CARD *Card;
|
2013-12-15 21:47:39 +01:00
|
|
|
EFI_PCI_IO_PROTOCOL *ChildPciIo;
|
2019-06-06 09:42:37 +02:00
|
|
|
UINT64 SupportedVgaIo;
|
2012-11-27 20:11:29 +01:00
|
|
|
|
2014-03-22 08:13:44 +01:00
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
//
|
2020-02-07 02:08:10 +01:00
|
|
|
// Allocate Private context data for GOP interface.
|
2011-04-12 17:08:51 +02:00
|
|
|
//
|
|
|
|
Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
|
|
|
|
if (Private == NULL) {
|
2014-03-22 08:13:44 +01:00
|
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
goto RestoreTpl;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto FreePrivate;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
//
|
|
|
|
// 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)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto ClosePciIo;
|
2012-11-27 20:11:11 +01:00
|
|
|
}
|
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
//
|
|
|
|
// Determine card variant.
|
|
|
|
//
|
2018-05-17 11:21:32 +02:00
|
|
|
Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
|
2012-11-27 20:11:11 +01:00
|
|
|
if (Card == NULL) {
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
2014-03-03 09:40:19 +01:00
|
|
|
goto ClosePciIo;
|
2012-11-27 20:11:11 +01:00
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
Private->Variant = Card->Variant;
|
|
|
|
|
OvmfPkg: QemuVideoDxe: work around misreported QXL framebuffer size
When setting up the list of GOP modes offered on QEMU's stdvga ("VGA") and
QXL ("qxl-vga") video devices, QemuVideoBochsModeSetup() filters those
modes against the available framebuffer size. (Refer to SVN r15288 / git
commit ec88061e.)
The VBE_DISPI_INDEX_VIDEO_MEMORY_64K register of both stdvga and QXL is
supposed to report the size of the drawable, VGA-compatibility
framebuffer. Instead, up to and including qemu-2.1, this register actually
reports the full video RAM (PCI BAR 0) size.
In case of stdvga, this happens to be correct, because on that card the
full PCI BAR 0 is usable for drawing; there is no difference between
"drawable framebuffer size" and "video RAM (PCI BAR 0) size".
However, on the QXL card, only an initial portion of the video RAM is
suitable for drawing, as compatibility framebuffer; and the value
currently reported by VBE_DISPI_INDEX_VIDEO_MEMORY_64K overshoots the
valid size. Beyond the drawable range, the video RAM contains buffers and
structures for the QXL guest-host protocol.
Luckily, the size of the drawable QXL framebuffer can also be read from a
register in the QXL ROM BAR (PCI BAR 2), so let's retrieve it from there.
Without this fix, OVMF offers too large resolutions on the QXL card (up to
the full size of the video RAM). If a GOP client selects such a resolution
and draws into the video RAM past the compatibility segment, then the
guest corrupts its communication structures (which is invalid guest
behavior).
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15978 6f19259b-4bc3-4df7-8a09-765794883524
2014-08-29 19:27:20 +02:00
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
//
|
|
|
|
// Save original PCI attributes
|
|
|
|
//
|
|
|
|
Status = Private->PciIo->Attributes (
|
|
|
|
Private->PciIo,
|
|
|
|
EfiPciIoAttributeOperationGet,
|
|
|
|
0,
|
|
|
|
&Private->OriginalPciAttributes
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto ClosePciIo;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
2019-06-06 09:42:37 +02:00
|
|
|
//
|
|
|
|
// 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);
|
2020-02-24 17:35:39 +01:00
|
|
|
if ((SupportedVgaIo == 0) && IS_PCI_VGA (&Pci)) {
|
2019-06-06 09:42:37 +02:00
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
goto ClosePciIo;
|
|
|
|
}
|
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
//
|
|
|
|
// Set new PCI attributes
|
|
|
|
//
|
2011-04-12 17:08:51 +02:00
|
|
|
Status = Private->PciIo->Attributes (
|
|
|
|
Private->PciIo,
|
|
|
|
EfiPciIoAttributeOperationEnable,
|
2019-06-06 09:42:37 +02:00
|
|
|
EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo,
|
2011-04-12 17:08:51 +02:00
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto ClosePciIo;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:45 +01:00
|
|
|
//
|
|
|
|
// Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
|
|
|
|
//
|
|
|
|
if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
|
2014-03-03 09:40:19 +01:00
|
|
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
|
|
|
|
|
2012-11-27 20:11:45 +01:00
|
|
|
Status = Private->PciIo->GetBarAttributes (
|
|
|
|
Private->PciIo,
|
|
|
|
PCI_BAR_IDX2,
|
|
|
|
NULL,
|
|
|
|
(VOID **)&MmioDesc
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status) ||
|
|
|
|
(MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM))
|
|
|
|
{
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
|
2012-11-27 20:11:45 +01:00
|
|
|
Private->Variant = QEMU_VIDEO_BOCHS;
|
|
|
|
} else {
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"QemuVideo: Using mmio bar @ 0x%lx\n",
|
2012-11-27 20:11:45 +01:00
|
|
|
MmioDesc->AddrRangeMin
|
|
|
|
));
|
|
|
|
}
|
2013-11-20 23:31:14 +01:00
|
|
|
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
FreePool (MmioDesc);
|
|
|
|
}
|
2012-11-27 20:11:45 +01:00
|
|
|
}
|
|
|
|
|
2018-11-07 04:47:13 +01:00
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:29 +01:00
|
|
|
//
|
|
|
|
// Check if accessing the bochs interface works.
|
|
|
|
//
|
2012-11-27 20:11:45 +01:00
|
|
|
if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||
|
|
|
|
(Private->Variant == QEMU_VIDEO_BOCHS))
|
|
|
|
{
|
2012-11-27 20:11:29 +01:00
|
|
|
UINT16 BochsId;
|
|
|
|
BochsId = BochsRead (Private, VBE_DISPI_INDEX_ID);
|
|
|
|
if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
|
2012-11-27 20:11:29 +01:00
|
|
|
Status = EFI_DEVICE_ERROR;
|
2014-03-03 09:40:19 +01:00
|
|
|
goto RestoreAttributes;
|
2012-11-27 20:11:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
//
|
|
|
|
// Get ParentDevicePath
|
|
|
|
//
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
Controller,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
(VOID **)&ParentDevicePath
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto RestoreAttributes;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set Gop Device Path
|
|
|
|
//
|
2014-03-03 09:40:28 +01:00
|
|
|
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;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
2014-03-03 09:40:19 +01:00
|
|
|
|
|
|
|
//
|
2014-03-03 09:40:28 +01:00
|
|
|
// Create new child handle and install the device path protocol on it.
|
2014-03-03 09:40:19 +01:00
|
|
|
//
|
2014-03-03 09:40:28 +01:00
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Private->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->GopDevicePath,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto FreeGopDevicePath;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Construct video mode buffer
|
|
|
|
//
|
2012-11-27 20:11:11 +01:00
|
|
|
switch (Private->Variant) {
|
|
|
|
case QEMU_VIDEO_CIRRUS_5430:
|
|
|
|
case QEMU_VIDEO_CIRRUS_5446:
|
|
|
|
Status = QemuVideoCirrusModeSetup (Private);
|
|
|
|
break;
|
2012-11-27 20:11:45 +01:00
|
|
|
case QEMU_VIDEO_BOCHS_MMIO:
|
2012-11-27 20:11:29 +01:00
|
|
|
case QEMU_VIDEO_BOCHS:
|
OvmfPkg: QemuVideoDxe: work around misreported QXL framebuffer size
When setting up the list of GOP modes offered on QEMU's stdvga ("VGA") and
QXL ("qxl-vga") video devices, QemuVideoBochsModeSetup() filters those
modes against the available framebuffer size. (Refer to SVN r15288 / git
commit ec88061e.)
The VBE_DISPI_INDEX_VIDEO_MEMORY_64K register of both stdvga and QXL is
supposed to report the size of the drawable, VGA-compatibility
framebuffer. Instead, up to and including qemu-2.1, this register actually
reports the full video RAM (PCI BAR 0) size.
In case of stdvga, this happens to be correct, because on that card the
full PCI BAR 0 is usable for drawing; there is no difference between
"drawable framebuffer size" and "video RAM (PCI BAR 0) size".
However, on the QXL card, only an initial portion of the video RAM is
suitable for drawing, as compatibility framebuffer; and the value
currently reported by VBE_DISPI_INDEX_VIDEO_MEMORY_64K overshoots the
valid size. Beyond the drawable range, the video RAM contains buffers and
structures for the QXL guest-host protocol.
Luckily, the size of the drawable QXL framebuffer can also be read from a
register in the QXL ROM BAR (PCI BAR 2), so let's retrieve it from there.
Without this fix, OVMF offers too large resolutions on the QXL card (up to
the full size of the video RAM). If a GOP client selects such a resolution
and draws into the video RAM past the compatibility segment, then the
guest corrupts its communication structures (which is invalid guest
behavior).
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15978 6f19259b-4bc3-4df7-8a09-765794883524
2014-08-29 19:27:20 +02:00
|
|
|
Status = QemuVideoBochsModeSetup (Private, IsQxl);
|
2012-11-27 20:11:29 +01:00
|
|
|
break;
|
2012-11-27 20:11:11 +01:00
|
|
|
default:
|
|
|
|
ASSERT (FALSE);
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto UninstallGopDevicePath;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
//
|
|
|
|
// Start the GOP software stack.
|
|
|
|
//
|
|
|
|
Status = QemuVideoGraphicsOutputConstructor (Private);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto FreeModeData;
|
|
|
|
}
|
2013-12-15 21:47:39 +01:00
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&Private->Handle,
|
|
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
|
|
&Private->GraphicsOutput,
|
|
|
|
NULL
|
2013-12-15 21:47:39 +01:00
|
|
|
);
|
2014-03-03 09:40:19 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
goto DestructQemuVideoGraphics;
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
//
|
|
|
|
// Reference parent handle from child handle.
|
|
|
|
//
|
|
|
|
Status = gBS->OpenProtocol (
|
|
|
|
Controller,
|
|
|
|
&gEfiPciIoProtocolGuid,
|
|
|
|
(VOID **)&ChildPciIo,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
Private->Handle,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
|
|
);
|
2011-04-12 17:08:51 +02:00
|
|
|
if (EFI_ERROR (Status)) {
|
2014-03-03 09:40:19 +01:00
|
|
|
goto UninstallGop;
|
|
|
|
}
|
2011-04-12 17:08:51 +02:00
|
|
|
|
2015-02-23 17:02:29 +01:00
|
|
|
#if defined MDE_CPU_IA32 || defined MDE_CPU_X64
|
OvmfPkg: QemuVideoDxe: Int10h stub for Windows 7 & 2008 (stdvga, QXL)
The Windows 2008 R2 SP1 (and Windows 7) UEFI guest's default video driver
dereferences the real mode Int10h vector, loads the pointed-to handler
code, and executes what it thinks to be VGA BIOS services in an internal
real-mode emulator. Consequently, video mode switching doesn't work in
Windows 2008 R2 SP1 when it runs on the pure UEFI build of OVMF, making
the guest uninstallable.
This patch adds a VGABIOS "shim" to QemuVideoDxe. For the first stdvga or
QXL card bound, an extremely stripped down VGABIOS imitation is installed
in the C segment. It provides a real implementation for the few services
that are in fact necessary for the win2k8r2sp1 UEFI guest, plus some fakes
that the guest invokes but whose effect is not important.
The C segment is not present in the UEFI memory map prepared by OVMF. We
never add memory space that would cover it (either in PEI, in the form of
memory resource descriptor HOBs, or in DXE, via gDS->AddMemorySpace()).
This way the handler body is invisible to all non-buggy UEFI guests, and
the rest of edk2.
The Int10h real-mode IVT entry is covered with a Boot Services Code page,
making that too unaccessible to the rest of edk2. (Thus UEFI guest OSes
different from the Windows 2008 family can reclaim the page. The Windows
2008 family accesses the page at zero regardless of the allocation type.)
The patch is the result of collaboration:
Initial proof of concept IVT entry installation and handler skeleton (in
NASM) by Jordan Justen.
Service tracing and implementation, data collection/analysis, and C coding
by yours truly.
Last minute changes by Gerd Hoffmann:
- Use OEM mode number (0xf1) instead of standard 800x600 mode (0x143). The
resolution of the OEM mode (0xf1) is not standardized; the guest can't
expect anything from it in advance.
- Use 1024x768 rather than 800x600 for more convenience in the Windows
2008 R2 SP1 guest during OS installation, and after normal boot until
the QXL XDDM guest driver is installed.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15540 6f19259b-4bc3-4df7-8a09-765794883524
2014-05-20 18:33:00 +02:00
|
|
|
if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) ||
|
|
|
|
(Private->Variant == QEMU_VIDEO_BOCHS))
|
|
|
|
{
|
|
|
|
InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2015-02-23 17:02:29 +01:00
|
|
|
#endif
|
OvmfPkg: QemuVideoDxe: Int10h stub for Windows 7 & 2008 (stdvga, QXL)
The Windows 2008 R2 SP1 (and Windows 7) UEFI guest's default video driver
dereferences the real mode Int10h vector, loads the pointed-to handler
code, and executes what it thinks to be VGA BIOS services in an internal
real-mode emulator. Consequently, video mode switching doesn't work in
Windows 2008 R2 SP1 when it runs on the pure UEFI build of OVMF, making
the guest uninstallable.
This patch adds a VGABIOS "shim" to QemuVideoDxe. For the first stdvga or
QXL card bound, an extremely stripped down VGABIOS imitation is installed
in the C segment. It provides a real implementation for the few services
that are in fact necessary for the win2k8r2sp1 UEFI guest, plus some fakes
that the guest invokes but whose effect is not important.
The C segment is not present in the UEFI memory map prepared by OVMF. We
never add memory space that would cover it (either in PEI, in the form of
memory resource descriptor HOBs, or in DXE, via gDS->AddMemorySpace()).
This way the handler body is invisible to all non-buggy UEFI guests, and
the rest of edk2.
The Int10h real-mode IVT entry is covered with a Boot Services Code page,
making that too unaccessible to the rest of edk2. (Thus UEFI guest OSes
different from the Windows 2008 family can reclaim the page. The Windows
2008 family accesses the page at zero regardless of the allocation type.)
The patch is the result of collaboration:
Initial proof of concept IVT entry installation and handler skeleton (in
NASM) by Jordan Justen.
Service tracing and implementation, data collection/analysis, and C coding
by yours truly.
Last minute changes by Gerd Hoffmann:
- Use OEM mode number (0xf1) instead of standard 800x600 mode (0x143). The
resolution of the OEM mode (0xf1) is not standardized; the guest can't
expect anything from it in advance.
- Use 1024x768 rather than 800x600 for more convenience in the Windows
2008 R2 SP1 guest during OS installation, and after normal boot until
the QXL XDDM guest driver is installed.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15540 6f19259b-4bc3-4df7-8a09-765794883524
2014-05-20 18:33:00 +02:00
|
|
|
|
2014-03-22 08:13:44 +01:00
|
|
|
gBS->RestoreTPL (OldTpl);
|
2014-03-03 09:40:19 +01:00
|
|
|
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:
|
2014-03-03 09:40:28 +01:00
|
|
|
FreePool (Private->GopDevicePath);
|
2011-04-12 17:08:51 +02:00
|
|
|
|
2014-03-03 09:40:19 +01:00
|
|
|
RestoreAttributes:
|
|
|
|
Private->PciIo->Attributes (
|
|
|
|
Private->PciIo,
|
|
|
|
EfiPciIoAttributeOperationSet,
|
|
|
|
Private->OriginalPciAttributes,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
|
|
|
|
ClosePciIo:
|
|
|
|
gBS->CloseProtocol (
|
|
|
|
Controller,
|
|
|
|
&gEfiPciIoProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
Controller
|
|
|
|
);
|
|
|
|
|
|
|
|
FreePrivate:
|
|
|
|
FreePool (Private);
|
|
|
|
|
2014-03-22 08:13:44 +01:00
|
|
|
RestoreTpl:
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
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;
|
|
|
|
|
2014-03-03 09:40:35 +01:00
|
|
|
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);
|
2011-04-12 17:08:51 +02:00
|
|
|
Status = gBS->OpenProtocol (
|
2014-03-03 09:40:35 +01:00
|
|
|
ChildHandleBuffer[0],
|
2011-04-12 17:08:51 +02:00
|
|
|
&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);
|
2014-03-03 09:40:35 +01:00
|
|
|
ASSERT (Private->Handle == ChildHandleBuffer[0]);
|
2011-04-12 17:08:51 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
2013-12-15 21:47:39 +01:00
|
|
|
gBS->CloseProtocol (
|
|
|
|
Controller,
|
|
|
|
&gEfiPciIoProtocolGuid,
|
|
|
|
This->DriverBindingHandle,
|
|
|
|
Private->Handle
|
|
|
|
);
|
|
|
|
|
2014-03-03 09:40:44 +01:00
|
|
|
FreePool (Private->ModeData);
|
|
|
|
gBS->UninstallProtocolInterface (
|
|
|
|
Private->Handle,
|
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
Private->GopDevicePath
|
|
|
|
);
|
|
|
|
FreePool (Private->GopDevicePath);
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
)
|
|
|
|
{
|
2012-11-27 20:11:45 +01:00
|
|
|
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));
|
2011-04-12 17:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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,
|
2018-11-07 04:47:13 +01:00
|
|
|
Private->FrameBufferVramBarIndex,
|
2011-04-12 17:08:51 +02:00
|
|
|
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
|
2012-11-27 20:11:11 +01:00
|
|
|
InitializeCirrusGraphicsMode (
|
2011-04-12 17:08:51 +02:00
|
|
|
QEMU_VIDEO_PRIVATE_DATA *Private,
|
2012-11-27 20:11:11 +01:00
|
|
|
QEMU_VIDEO_CIRRUS_MODES *ModeData
|
2011-04-12 17:08:51 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:11 +01:00
|
|
|
if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
|
2011-04-12 17:08:51 +02:00
|
|
|
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);
|
|
|
|
|
2012-11-27 20:11:29 +01:00
|
|
|
SetDefaultPalette (Private);
|
|
|
|
ClearScreen (Private);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
BochsWrite (
|
|
|
|
QEMU_VIDEO_PRIVATE_DATA *Private,
|
|
|
|
UINT16 Reg,
|
|
|
|
UINT16 Data
|
|
|
|
)
|
|
|
|
{
|
2012-11-27 20:11:45 +01:00
|
|
|
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);
|
|
|
|
}
|
2012-11-27 20:11:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UINT16
|
|
|
|
BochsRead (
|
|
|
|
QEMU_VIDEO_PRIVATE_DATA *Private,
|
|
|
|
UINT16 Reg
|
|
|
|
)
|
|
|
|
{
|
2012-11-27 20:11:45 +01:00
|
|
|
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);
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2012-11-27 20:11:29 +01:00
|
|
|
return Data;
|
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:45 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-07 11:15:04 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-11-27 20:11:29 +01:00
|
|
|
VOID
|
|
|
|
InitializeBochsGraphicsMode (
|
|
|
|
QEMU_VIDEO_PRIVATE_DATA *Private,
|
2022-01-17 10:58:14 +01:00
|
|
|
QEMU_VIDEO_MODE_DATA *ModeData
|
2012-11-27 20:11:29 +01:00
|
|
|
)
|
|
|
|
{
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"InitializeBochsGraphicsMode: %dx%d @ %d\n",
|
2022-01-17 10:58:14 +01:00
|
|
|
ModeData->HorizontalResolution,
|
|
|
|
ModeData->VerticalResolution,
|
2012-11-27 20:11:29 +01:00
|
|
|
ModeData->ColorDepth
|
|
|
|
));
|
|
|
|
|
2022-09-07 11:15:04 +02:00
|
|
|
/* set color mode */
|
|
|
|
VgaOutb (Private, MISC_OUTPUT_REGISTER, 0x01);
|
|
|
|
|
|
|
|
/* reset flip flop + unblank */
|
|
|
|
VgaInb (Private, INPUT_STATUS_1_REGISTER);
|
2012-11-27 20:11:45 +01:00
|
|
|
VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
|
2012-11-27 20:11:29 +01:00
|
|
|
|
|
|
|
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);
|
2022-01-17 10:58:14 +01:00
|
|
|
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);
|
2012-11-27 20:11:29 +01:00
|
|
|
|
|
|
|
BochsWrite (
|
|
|
|
Private,
|
|
|
|
VBE_DISPI_INDEX_ENABLE,
|
|
|
|
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED
|
|
|
|
);
|
|
|
|
|
2011-04-12 17:08:51 +02:00
|
|
|
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;
|
|
|
|
}
|