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 <IndustryStandard/Acpi.h>
#include "Qemu.h"
#include "UnalignedIoInternal.h"
EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = { EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
QemuVideoControllerDriverSupported, QemuVideoControllerDriverSupported,
@ -69,6 +71,12 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
0x1050, 0x1050,
QEMU_VIDEO_BOCHS_MMIO, QEMU_VIDEO_BOCHS_MMIO,
L"QEMU VirtIO VGA" 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 */ 0 /* end of list */
} }
@ -256,6 +264,7 @@ QemuVideoControllerDriverStart (
goto ClosePciIo; goto ClosePciIo;
} }
Private->Variant = Card->Variant; Private->Variant = Card->Variant;
Private->FrameBufferVramBarIndex = PCI_BAR_IDX0;
// //
// IsQxl is based on the detected Card->Variant, which at a later point might // 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 // Get ParentDevicePath
// //
@ -385,6 +446,9 @@ QemuVideoControllerDriverStart (
case QEMU_VIDEO_BOCHS: case QEMU_VIDEO_BOCHS:
Status = QemuVideoBochsModeSetup (Private, IsQxl); Status = QemuVideoBochsModeSetup (Private, IsQxl);
break; break;
case QEMU_VIDEO_VMWARE_SVGA:
Status = QemuVideoVmwareSvgaModeSetup (Private);
break;
default: default:
ASSERT (FALSE); ASSERT (FALSE);
Status = EFI_DEVICE_ERROR; Status = EFI_DEVICE_ERROR;
@ -446,6 +510,9 @@ DestructQemuVideoGraphics:
FreeModeData: FreeModeData:
FreePool (Private->ModeData); FreePool (Private->ModeData);
if (Private->VmwareSvgaModeInfo != NULL) {
FreePool (Private->VmwareSvgaModeInfo);
}
UninstallGopDevicePath: UninstallGopDevicePath:
gBS->UninstallProtocolInterface (Private->Handle, gBS->UninstallProtocolInterface (Private->Handle,
@ -567,6 +634,9 @@ QemuVideoControllerDriverStop (
); );
FreePool (Private->ModeData); FreePool (Private->ModeData);
if (Private->VmwareSvgaModeInfo != NULL) {
FreePool (Private->VmwareSvgaModeInfo);
}
gBS->UninstallProtocolInterface (Private->Handle, gBS->UninstallProtocolInterface (Private->Handle,
&gEfiDevicePathProtocolGuid, Private->GopDevicePath); &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
FreePool (Private->GopDevicePath); FreePool (Private->GopDevicePath);
@ -764,7 +834,7 @@ ClearScreen (
Private->PciIo->Mem.Write ( Private->PciIo->Mem.Write (
Private->PciIo, Private->PciIo,
EfiPciIoWidthFillUint32, EfiPciIoWidthFillUint32,
0, Private->FrameBufferVramBarIndex,
0, 0,
0x400000 >> 2, 0x400000 >> 2,
&Color &Color
@ -901,6 +971,38 @@ BochsRead (
return Data; 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 VOID
VgaOutb ( VgaOutb (
QEMU_VIDEO_PRIVATE_DATA *Private, QEMU_VIDEO_PRIVATE_DATA *Private,
@ -955,6 +1057,35 @@ InitializeBochsGraphicsMode (
ClearScreen (Private); 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 EFI_STATUS
EFIAPI EFIAPI
InitializeQemuVideo ( InitializeQemuVideo (

View File

@ -13,6 +13,7 @@
**/ **/
#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h" #include "Qemu.h"
STATIC STATIC
@ -78,6 +79,46 @@ QemuVideoCompleteModeData (
return EFI_SUCCESS; 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 // Graphics Output Protocol Member Functions
// //
@ -126,10 +167,14 @@ Routine Description:
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
CopyMem (*Info, &Private->VmwareSvgaModeInfo[ModeNumber], sizeof (**Info));
} else {
ModeData = &Private->ModeData[ModeNumber]; ModeData = &Private->ModeData[ModeNumber];
(*Info)->HorizontalResolution = ModeData->HorizontalResolution; (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
(*Info)->VerticalResolution = ModeData->VerticalResolution; (*Info)->VerticalResolution = ModeData->VerticalResolution;
QemuVideoCompleteModeInfo (ModeData, *Info); QemuVideoCompleteModeInfo (ModeData, *Info);
}
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -179,6 +224,12 @@ Routine Description:
case QEMU_VIDEO_BOCHS: case QEMU_VIDEO_BOCHS:
InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]); InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]);
break; break;
case QEMU_VIDEO_VMWARE_SVGA:
InitializeVmwareSvgaGraphicsMode (
Private,
&QemuVideoBochsModes[ModeData->InternalModeIndex]
);
break;
default: default:
ASSERT (FALSE); ASSERT (FALSE);
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
@ -189,7 +240,11 @@ Routine Description:
This->Mode->Info->VerticalResolution = ModeData->VerticalResolution; This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {
QemuVideoVmwareSvgaCompleteModeData (Private, This->Mode);
} else {
QemuVideoCompleteModeData (Private, This->Mode); QemuVideoCompleteModeData (Private, This->Mode);
}
// //
// Re-initialize the frame buffer configure when mode changes. // Re-initialize the frame buffer configure when mode changes.

View File

@ -13,6 +13,7 @@
**/ **/
#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h" #include "Qemu.h"
@ -346,3 +347,159 @@ QemuVideoBochsModeSetup (
return EFI_SUCCESS; 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_CIRRUS_5446,
QEMU_VIDEO_BOCHS, QEMU_VIDEO_BOCHS,
QEMU_VIDEO_BOCHS_MMIO, QEMU_VIDEO_BOCHS_MMIO,
QEMU_VIDEO_VMWARE_SVGA,
} QEMU_VIDEO_VARIANT; } QEMU_VIDEO_VARIANT;
typedef struct { typedef struct {
@ -116,10 +117,13 @@ typedef struct {
// //
UINTN MaxMode; UINTN MaxMode;
QEMU_VIDEO_MODE_DATA *ModeData; QEMU_VIDEO_MODE_DATA *ModeData;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *VmwareSvgaModeInfo;
QEMU_VIDEO_VARIANT Variant; QEMU_VIDEO_VARIANT Variant;
FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure; FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure;
UINTN FrameBufferBltConfigureSize; UINTN FrameBufferBltConfigureSize;
UINT8 FrameBufferVramBarIndex;
UINT16 VmwareSvgaBasePort;
} QEMU_VIDEO_PRIVATE_DATA; } QEMU_VIDEO_PRIVATE_DATA;
/// ///
@ -503,9 +507,34 @@ QemuVideoBochsModeSetup (
BOOLEAN IsQxl BOOLEAN IsQxl
); );
EFI_STATUS
QemuVideoVmwareSvgaModeSetup (
QEMU_VIDEO_PRIVATE_DATA *Private
);
VOID VOID
InstallVbeShim ( InstallVbeShim (
IN CONST CHAR16 *CardName, IN CONST CHAR16 *CardName,
IN EFI_PHYSICAL_ADDRESS FrameBufferBase 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 #endif