Reapply "OvmfPkg/QemuVideoDxe: VMWare SVGA device support"

This reverts commit 98856a724c, reapplying
c137d95081.

Note that the commit now being reverted is technically correct; the only
reason we're reverting it is because it should not have been pushed past
the Soft Feature Freeze for the edk2-stable201811 tag.

Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@linaro.org>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: yuchenlin <yuchenlin@synology.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1319
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: yuchenlin <yuchenlin@synology.com>
This commit is contained in:
Laszlo Ersek 2018-11-09 20:15:31 +01:00
parent 615c2c766e
commit 2e77f0e7b5
4 changed files with 379 additions and 7 deletions

View File

@ -14,8 +14,10 @@
**/
#include "Qemu.h"
#include <IndustryStandard/VmwareSvga.h>
#include <IndustryStandard/Acpi.h>
#include "Qemu.h"
#include "UnalignedIoInternal.h"
EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
QemuVideoControllerDriverSupported,
@ -69,6 +71,12 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
0x1050,
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU VirtIO VGA"
},{
PCI_CLASS_DISPLAY_VGA,
VMWARE_PCI_VENDOR_ID_VMWARE,
VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2,
QEMU_VIDEO_VMWARE_SVGA,
L"QEMU VMWare SVGA"
},{
0 /* end of list */
}
@ -256,6 +264,7 @@ QemuVideoControllerDriverStart (
goto ClosePciIo;
}
Private->Variant = Card->Variant;
Private->FrameBufferVramBarIndex = PCI_BAR_IDX0;
//
// IsQxl is based on the detected Card->Variant, which at a later point might
@ -330,6 +339,58 @@ QemuVideoControllerDriverStart (
}
}
//
// Check if accessing Vmware SVGA interface works
//
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IoDesc;
UINT32 TargetId;
UINT32 SvgaIdRead;
IoDesc = NULL;
Status = Private->PciIo->GetBarAttributes (
Private->PciIo,
PCI_BAR_IDX0,
NULL,
(VOID**) &IoDesc
);
if (EFI_ERROR (Status) ||
IoDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_IO ||
IoDesc->AddrRangeMin > MAX_UINT16 + 1 - (VMWARE_SVGA_VALUE_PORT + 4)) {
if (IoDesc != NULL) {
FreePool (IoDesc);
}
Status = EFI_DEVICE_ERROR;
goto RestoreAttributes;
}
Private->VmwareSvgaBasePort = (UINT16) IoDesc->AddrRangeMin;
FreePool (IoDesc);
TargetId = VMWARE_SVGA_ID_2;
while (TRUE) {
VmwareSvgaWrite (Private, VmwareSvgaRegId, TargetId);
SvgaIdRead = VmwareSvgaRead (Private, VmwareSvgaRegId);
if ((SvgaIdRead == TargetId) || (TargetId <= VMWARE_SVGA_ID_0)) {
break;
}
TargetId--;
}
if (SvgaIdRead != TargetId) {
DEBUG ((
DEBUG_ERROR,
"QemuVideo: QEMU_VIDEO_VMWARE_SVGA ID mismatch "
"(got 0x%x, base address 0x%x)\n",
SvgaIdRead,
Private->VmwareSvgaBasePort
));
Status = EFI_DEVICE_ERROR;
goto RestoreAttributes;
}
Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;
}
//
// Get ParentDevicePath
//
@ -385,6 +446,9 @@ QemuVideoControllerDriverStart (
case QEMU_VIDEO_BOCHS:
Status = QemuVideoBochsModeSetup (Private, IsQxl);
break;
case QEMU_VIDEO_VMWARE_SVGA:
Status = QemuVideoVmwareSvgaModeSetup (Private);
break;
default:
ASSERT (FALSE);
Status = EFI_DEVICE_ERROR;
@ -446,6 +510,9 @@ DestructQemuVideoGraphics:
FreeModeData:
FreePool (Private->ModeData);
if (Private->VmwareSvgaModeInfo != NULL) {
FreePool (Private->VmwareSvgaModeInfo);
}
UninstallGopDevicePath:
gBS->UninstallProtocolInterface (Private->Handle,
@ -567,6 +634,9 @@ QemuVideoControllerDriverStop (
);
FreePool (Private->ModeData);
if (Private->VmwareSvgaModeInfo != NULL) {
FreePool (Private->VmwareSvgaModeInfo);
}
gBS->UninstallProtocolInterface (Private->Handle,
&gEfiDevicePathProtocolGuid, Private->GopDevicePath);
FreePool (Private->GopDevicePath);
@ -764,7 +834,7 @@ ClearScreen (
Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthFillUint32,
0,
Private->FrameBufferVramBarIndex,
0,
0x400000 >> 2,
&Color
@ -901,6 +971,38 @@ BochsRead (
return Data;
}
VOID
VmwareSvgaWrite (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Register,
UINT32 Value
)
{
UnalignedIoWrite32 (
Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
Register
);
UnalignedIoWrite32 (
Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT,
Value
);
}
UINT32
VmwareSvgaRead (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Register
)
{
UnalignedIoWrite32 (
Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,
Register
);
return UnalignedIoRead32 (
Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT
);
}
VOID
VgaOutb (
QEMU_VIDEO_PRIVATE_DATA *Private,
@ -955,6 +1057,35 @@ InitializeBochsGraphicsMode (
ClearScreen (Private);
}
VOID
InitializeVmwareSvgaGraphicsMode (
QEMU_VIDEO_PRIVATE_DATA *Private,
QEMU_VIDEO_BOCHS_MODES *ModeData
)
{
UINT32 Capabilities;
VmwareSvgaWrite (Private, VmwareSvgaRegWidth, ModeData->Width);
VmwareSvgaWrite (Private, VmwareSvgaRegHeight, ModeData->Height);
Capabilities = VmwareSvgaRead (
Private,
VmwareSvgaRegCapabilities
);
if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
VmwareSvgaWrite (
Private,
VmwareSvgaRegBitsPerPixel,
ModeData->ColorDepth
);
}
VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 1);
SetDefaultPalette (Private);
ClearScreen (Private);
}
EFI_STATUS
EFIAPI
InitializeQemuVideo (

View File

@ -13,6 +13,7 @@
**/
#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
STATIC
@ -78,6 +79,46 @@ QemuVideoCompleteModeData (
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
QemuVideoVmwareSvgaCompleteModeData (
IN QEMU_VIDEO_PRIVATE_DATA *Private,
OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
UINT32 BytesPerLine, FbOffset, BytesPerPixel;
Info = Mode->Info;
CopyMem (Info, &Private->VmwareSvgaModeInfo[Mode->Mode], sizeof (*Info));
BytesPerPixel = Private->ModeData[Mode->Mode].ColorDepth / 8;
BytesPerLine = Info->PixelsPerScanLine * BytesPerPixel;
FbOffset = VmwareSvgaRead (Private, VmwareSvgaRegFbOffset);
Status = Private->PciIo->GetBarAttributes (
Private->PciIo,
PCI_BAR_IDX1,
NULL,
(VOID**) &FrameBufDesc
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin + FbOffset;
Mode->FrameBufferSize = BytesPerLine * Info->VerticalResolution;
Mode->FrameBufferSize = EFI_PAGES_TO_SIZE (
EFI_SIZE_TO_PAGES (Mode->FrameBufferSize)
);
FreePool (FrameBufDesc);
return Status;
}
//
// Graphics Output Protocol Member Functions
//
@ -126,10 +167,14 @@ Routine Description:
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
ModeData = &Private->ModeData[ModeNumber];
(*Info)->HorizontalResolution = ModeData->HorizontalResolution;
(*Info)->VerticalResolution = ModeData->VerticalResolution;
QemuVideoCompleteModeInfo (ModeData, *Info);
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
CopyMem (*Info, &Private->VmwareSvgaModeInfo[ModeNumber], sizeof (**Info));
} else {
ModeData = &Private->ModeData[ModeNumber];
(*Info)->HorizontalResolution = ModeData->HorizontalResolution;
(*Info)->VerticalResolution = ModeData->VerticalResolution;
QemuVideoCompleteModeInfo (ModeData, *Info);
}
return EFI_SUCCESS;
}
@ -179,6 +224,12 @@ Routine Description:
case QEMU_VIDEO_BOCHS:
InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]);
break;
case QEMU_VIDEO_VMWARE_SVGA:
InitializeVmwareSvgaGraphicsMode (
Private,
&QemuVideoBochsModes[ModeData->InternalModeIndex]
);
break;
default:
ASSERT (FALSE);
return EFI_DEVICE_ERROR;
@ -189,7 +240,11 @@ Routine Description:
This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
QemuVideoCompleteModeData (Private, This->Mode);
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
QemuVideoVmwareSvgaCompleteModeData (Private, This->Mode);
} else {
QemuVideoCompleteModeData (Private, This->Mode);
}
//
// Re-initialize the frame buffer configure when mode changes.

View File

@ -13,6 +13,7 @@
**/
#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
@ -346,3 +347,159 @@ QemuVideoBochsModeSetup (
return EFI_SUCCESS;
}
EFI_STATUS
QemuVideoVmwareSvgaModeSetup (
QEMU_VIDEO_PRIVATE_DATA *Private
)
{
EFI_STATUS Status;
UINT32 FbSize;
UINT32 MaxWidth, MaxHeight;
UINT32 Capabilities;
UINT32 BitsPerPixel;
UINT32 Index;
QEMU_VIDEO_MODE_DATA *ModeData;
QEMU_VIDEO_BOCHS_MODES *VideoMode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo;
VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 0);
Private->ModeData =
AllocatePool (sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT);
if (Private->ModeData == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ModeDataAllocError;
}
Private->VmwareSvgaModeInfo =
AllocatePool (
sizeof (Private->VmwareSvgaModeInfo[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
);
if (Private->VmwareSvgaModeInfo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ModeInfoAllocError;
}
FbSize = VmwareSvgaRead (Private, VmwareSvgaRegFbSize);
MaxWidth = VmwareSvgaRead (Private, VmwareSvgaRegMaxWidth);
MaxHeight = VmwareSvgaRead (Private, VmwareSvgaRegMaxHeight);
Capabilities = VmwareSvgaRead (Private, VmwareSvgaRegCapabilities);
if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {
BitsPerPixel = VmwareSvgaRead (
Private,
VmwareSvgaRegHostBitsPerPixel
);
VmwareSvgaWrite (
Private,
VmwareSvgaRegBitsPerPixel,
BitsPerPixel
);
} else {
BitsPerPixel = VmwareSvgaRead (
Private,
VmwareSvgaRegBitsPerPixel
);
}
if (FbSize == 0 ||
MaxWidth == 0 ||
MaxHeight == 0 ||
BitsPerPixel == 0 ||
BitsPerPixel % 8 != 0) {
Status = EFI_DEVICE_ERROR;
goto Rollback;
}
ModeData = Private->ModeData;
ModeInfo = Private->VmwareSvgaModeInfo;
VideoMode = &QemuVideoBochsModes[0];
for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index++) {
UINTN RequiredFbSize;
RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
(BitsPerPixel / 8);
if (RequiredFbSize <= FbSize &&
VideoMode->Width <= MaxWidth &&
VideoMode->Height <= MaxHeight) {
UINT32 BytesPerLine;
UINT32 RedMask, GreenMask, BlueMask, PixelMask;
VmwareSvgaWrite (
Private,
VmwareSvgaRegWidth,
VideoMode->Width
);
VmwareSvgaWrite (
Private,
VmwareSvgaRegHeight,
VideoMode->Height
);
ModeData->InternalModeIndex = Index;
ModeData->HorizontalResolution = VideoMode->Width;
ModeData->VerticalResolution = VideoMode->Height;
ModeData->ColorDepth = BitsPerPixel;
//
// Setting VmwareSvgaRegWidth/VmwareSvgaRegHeight actually changes
// the device's display mode, so we save all properties of each mode up
// front to avoid inadvertent mode changes later.
//
ModeInfo->Version = 0;
ModeInfo->HorizontalResolution = ModeData->HorizontalResolution;
ModeInfo->VerticalResolution = ModeData->VerticalResolution;
ModeInfo->PixelFormat = PixelBitMask;
RedMask = VmwareSvgaRead (Private, VmwareSvgaRegRedMask);
ModeInfo->PixelInformation.RedMask = RedMask;
GreenMask = VmwareSvgaRead (Private, VmwareSvgaRegGreenMask);
ModeInfo->PixelInformation.GreenMask = GreenMask;
BlueMask = VmwareSvgaRead (Private, VmwareSvgaRegBlueMask);
ModeInfo->PixelInformation.BlueMask = BlueMask;
//
// Reserved mask is whatever bits in the pixel not containing RGB data,
// so start with binary 1s for every bit in the pixel, then mask off
// bits already used for RGB. Special case 32 to avoid undefined
// behaviour in the shift.
//
if (BitsPerPixel == 32) {
if (BlueMask == 0xff && GreenMask == 0xff00 && RedMask == 0xff0000) {
ModeInfo->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
} else if (BlueMask == 0xff0000 &&
GreenMask == 0xff00 &&
RedMask == 0xff) {
ModeInfo->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
}
PixelMask = MAX_UINT32;
} else {
PixelMask = (1u << BitsPerPixel) - 1;
}
ModeInfo->PixelInformation.ReservedMask =
PixelMask & ~(RedMask | GreenMask | BlueMask);
BytesPerLine = VmwareSvgaRead (Private, VmwareSvgaRegBytesPerLine);
ModeInfo->PixelsPerScanLine = BytesPerLine / (BitsPerPixel / 8);
ModeData++;
ModeInfo++;
}
VideoMode++;
}
Private->MaxMode = ModeData - Private->ModeData;
return EFI_SUCCESS;
Rollback:
FreePool (Private->VmwareSvgaModeInfo);
Private->VmwareSvgaModeInfo = NULL;
ModeInfoAllocError:
FreePool (Private->ModeData);
Private->ModeData = NULL;
ModeDataAllocError:
return Status;
}

View File

@ -92,6 +92,7 @@ typedef enum {
QEMU_VIDEO_CIRRUS_5446,
QEMU_VIDEO_BOCHS,
QEMU_VIDEO_BOCHS_MMIO,
QEMU_VIDEO_VMWARE_SVGA,
} QEMU_VIDEO_VARIANT;
typedef struct {
@ -116,10 +117,13 @@ typedef struct {
//
UINTN MaxMode;
QEMU_VIDEO_MODE_DATA *ModeData;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *VmwareSvgaModeInfo;
QEMU_VIDEO_VARIANT Variant;
FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure;
UINTN FrameBufferBltConfigureSize;
UINT8 FrameBufferVramBarIndex;
UINT16 VmwareSvgaBasePort;
} QEMU_VIDEO_PRIVATE_DATA;
///
@ -503,9 +507,34 @@ QemuVideoBochsModeSetup (
BOOLEAN IsQxl
);
EFI_STATUS
QemuVideoVmwareSvgaModeSetup (
QEMU_VIDEO_PRIVATE_DATA *Private
);
VOID
InstallVbeShim (
IN CONST CHAR16 *CardName,
IN EFI_PHYSICAL_ADDRESS FrameBufferBase
);
VOID
VmwareSvgaWrite (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Register,
UINT32 Value
);
UINT32
VmwareSvgaRead (
QEMU_VIDEO_PRIVATE_DATA *Private,
UINT16 Register
);
VOID
InitializeVmwareSvgaGraphicsMode (
QEMU_VIDEO_PRIVATE_DATA *Private,
QEMU_VIDEO_BOCHS_MODES *ModeData
);
#endif