From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg0-x241.google.com (mail-pg0-x241.google.com [IPv6:2607:f8b0:400e:c05::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 160F120D77828 for ; Sun, 2 Apr 2017 15:45:16 -0700 (PDT) Received: by mail-pg0-x241.google.com with SMTP id 81so25705057pgh.3 for ; Sun, 02 Apr 2017 15:45:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=SpYFMsRs+oRmamNUr9GeJlPV2UgKzNgtrgXCI8KB+oA=; b=XN38AGQJOewHYplXJoRW1plS9Zh8avAeiGumXNNfvcbDXSIn8XNwHNrnoKIsnKcnCZ 4aC/1mcmrBV8CIp+c0uqYTYYd50uDOT++NMF3B92WbAiVcjPkThPE01ULMKk6Oumqq4l 5xSC6u0O8+NeQ9ItAh8LXHilTdjk+uSoi42rRBAk1BaFjzuJGt9buZgSSomddN5OROTl y0Vr+9GHpt5zfIEzqDQeFR3/FNSR4Cqj9IMMfgwCsWw6o5Z5/0KEMaDD6Ha0QdvbOM7t 4K/tfMnR+X1gG1GDeak8+TIpKN0Rg39z35xga1TTtUNo70x5o4JT2aMntb8+TvL/DHui DigQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SpYFMsRs+oRmamNUr9GeJlPV2UgKzNgtrgXCI8KB+oA=; b=AtCxl8BRlb0w0vLn7pveGaI4HLZT0dvo+3UEGt9d0stf7QYa0LJL80DemVRyUJ0Jgr WhIQl5SgurJJ3qxcyr26XMalS77Au0hTcRNA4Z2nBl5gVgKIi6/6m2eRPBGqHRS5GIJA XOwF0H2zGpl8R9+ZvsCPQh+v1K5RyHimyhPsWwIrkPMGzNnaqSy5gwo9u8X9sGQgzWpt 0RQt0ihdpSMQb7vJ6Cdlrkeq0o2QNM7h7M01nRhiQLdApQ4I2cpC1zyaXHepa62CuW67 eYWydF77g3QNTPr3lPqpBRY8pMcfieP5TYZ7deJ1R2g5cc3DkagZ7sw6uA6oSZ9g4qUf uDaA== X-Gm-Message-State: AFeK/H23tv7Y+2XpZODfdWyr3hUP1ZC5d3yyAKu7GspWs4kgax2Ua0PN/9SZ8x0pOYWBQQ== X-Received: by 10.99.96.72 with SMTP id u69mr14495662pgb.194.1491173115480; Sun, 02 Apr 2017 15:45:15 -0700 (PDT) Received: from localhost.localdomain ([210.246.60.121]) by smtp.gmail.com with ESMTPSA id l127sm21891336pga.7.2017.04.02.15.45.12 (version=TLS1 cipher=AES128-SHA bits=128/128); Sun, 02 Apr 2017 15:45:15 -0700 (PDT) From: Phil Dennis-Jordan To: edk2-devel@lists.01.org Cc: Phil Dennis-Jordan , Jordan Justen , Laszlo Ersek Date: Mon, 3 Apr 2017 10:44:57 +1200 Message-Id: <1491173097-37305-4-git-send-email-lists@philjordan.eu> X-Mailer: git-send-email 2.3.2 (Apple Git-55) In-Reply-To: <1491173097-37305-1-git-send-email-lists@philjordan.eu> References: <1491173097-37305-1-git-send-email-lists@philjordan.eu> Subject: [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Apr 2017 22:45:16 -0000 From: Phil Dennis-Jordan In addition to the QXL, Cirrus, etc. VGA adapters, Qemu also implements a basic version of VMWare's SVGA2 display device. Drivers for this device exist for some guest OSes which do not support Qemu's other display adapters, so supporting it in OVMF is useful in conjunction with those OSes. This change adds support for the SVGA2 device's framebuffer to QemuVideoDxe's graphics output protocol implementation, based on VMWare's documentation. The most basic initialisation, framebuffer layout query, and mode setting operations are implemented. The device relies on port-based 32-bit I/O, unfortunately on misaligned addresses. This limits the driver's support to the x86 family of platforms. Cc: Jordan Justen Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Phil Dennis-Jordan --- Notes: v2: - Unaligned I/O helper functions moved to separate commit [Laszlo] - Multi-line function call whitespace fixes. OvmfPkg/QemuVideoDxe/Qemu.h | 37 +++++++ OvmfPkg/QemuVideoDxe/Driver.c | 76 ++++++++++++++ OvmfPkg/QemuVideoDxe/Gop.c | 74 +++++++++++++- OvmfPkg/QemuVideoDxe/Initialize.c | 107 ++++++++++++++++++++ 4 files changed, 293 insertions(+), 1 deletion(-) diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h index 2ce37defc5b8..b5c84c9e695e 100644 --- a/OvmfPkg/QemuVideoDxe/Qemu.h +++ b/OvmfPkg/QemuVideoDxe/Qemu.h @@ -56,6 +56,10 @@ typedef struct { UINT32 HorizontalResolution; UINT32 VerticalResolution; UINT32 ColorDepth; + // + // VMWare specific: + // + UINT32 PixelsPerLine; // includes any dead space } QEMU_VIDEO_MODE_DATA; #define PIXEL_RED_SHIFT 0 @@ -92,6 +96,7 @@ typedef enum { QEMU_VIDEO_CIRRUS_5446, QEMU_VIDEO_BOCHS, QEMU_VIDEO_BOCHS_MMIO, + QEMU_VIDEO_VMWARE_SVGA2, } QEMU_VIDEO_VARIANT; typedef struct { @@ -119,6 +124,8 @@ typedef struct { QEMU_VIDEO_VARIANT Variant; FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure; UINTN FrameBufferBltConfigureSize; + + UINT16 VMWareSVGA2_BasePort; } QEMU_VIDEO_PRIVATE_DATA; /// @@ -502,9 +509,39 @@ QemuVideoBochsModeSetup ( BOOLEAN IsQxl ); +EFI_STATUS +QemuVideoVmwareModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private + ); + VOID InstallVbeShim ( IN CONST CHAR16 *CardName, IN EFI_PHYSICAL_ADDRESS FrameBufferBase ); + +VOID +QemuVideoVMWSVGA2RegisterWrite ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 reg, + UINT32 value + ); + +UINT32 +QemuVideoVMWSVGA2RegisterRead ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 reg + ); + +EFI_STATUS +QemuVideoVMWSVGA2CompleteModeData ( + IN QEMU_VIDEO_PRIVATE_DATA *Private, + OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode + ); + +void InitializeVMWSVGA2GraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_BOCHS_MODES *ModeData + ); + #endif diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c index fc8025ec46de..f01aec6f7b0e 100644 --- a/OvmfPkg/QemuVideoDxe/Driver.c +++ b/OvmfPkg/QemuVideoDxe/Driver.c @@ -15,6 +15,7 @@ **/ #include "Qemu.h" +#include #include EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = { @@ -58,6 +59,16 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = { QEMU_VIDEO_BOCHS_MMIO, L"QEMU VirtIO VGA" },{ +#if defined MDE_CPU_IA32 || defined MDE_CPU_X64 + // + // Support only platforms which can do unaligned port I/O + // + PCI_VENDOR_ID_VMWARE, + PCI_DEVICE_ID_VMWARE_SVGA2, + QEMU_VIDEO_VMWARE_SVGA2, + L"QEMU VMWare SVGA2" + },{ +#endif 0 /* end of list */ } }; @@ -317,6 +328,45 @@ QemuVideoControllerDriverStart ( } // + // Check if accessing VMWARE_SVGA2 interface works + // + if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA2) { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *iodesc; + UINT32 TargetId; + UINT32 Svga2IDRead; + + Private->PciIo->GetBarAttributes ( + Private->PciIo, + PCI_BAR_IDX0, + NULL, + (VOID**) &iodesc + ); + Private->VMWareSVGA2_BasePort = iodesc->AddrRangeMin; + + TargetId = SVGA_ID_2; + while (1) { + QemuVideoVMWSVGA2RegisterWrite (Private, SVGA_REG_ID, TargetId); + Svga2IDRead = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_ID); + if ((Svga2IDRead == TargetId) || (TargetId <= SVGA_ID_0)) { + break; + } + --TargetId; + } + + if (Svga2IDRead != TargetId) { + DEBUG (( + DEBUG_ERROR, + "QemuVideo: QEMU_VIDEO_VMWARE_SVGA2 ID mismatch " + "(got 0x%x, base address 0x%x)\n", + Svga2IDRead, + Private->VMWareSVGA2_BasePort + )); + Status = EFI_DEVICE_ERROR; + goto RestoreAttributes; + } + } + + // // Get ParentDevicePath // Status = gBS->HandleProtocol ( @@ -371,6 +421,9 @@ QemuVideoControllerDriverStart ( case QEMU_VIDEO_BOCHS: Status = QemuVideoBochsModeSetup (Private, IsQxl); break; + case QEMU_VIDEO_VMWARE_SVGA2: + Status = QemuVideoVmwareModeSetup (Private); + break; default: ASSERT (FALSE); Status = EFI_DEVICE_ERROR; @@ -975,3 +1028,26 @@ InitializeQemuVideo ( return Status; } + +void InitializeVMWSVGA2GraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_BOCHS_MODES *ModeData + ) +{ + QemuVideoVMWSVGA2RegisterWrite (Private, SVGA_REG_WIDTH, ModeData->Width); + QemuVideoVMWSVGA2RegisterWrite (Private, SVGA_REG_HEIGHT, ModeData->Height); + + UINT32 capabilities = QemuVideoVMWSVGA2RegisterRead ( + Private, + SVGA_REG_CAPABILITIES + ); + if ((capabilities & SVGA_CAP_8BIT_EMULATION) != 0) { + QemuVideoVMWSVGA2RegisterWrite( + Private, + SVGA_REG_BITS_PER_PIXEL, + ModeData->ColorDepth + ); + } + SetDefaultPalette (Private); + ClearScreen (Private); +} diff --git a/OvmfPkg/QemuVideoDxe/Gop.c b/OvmfPkg/QemuVideoDxe/Gop.c index 359e9217d3d1..59918676e764 100644 --- a/OvmfPkg/QemuVideoDxe/Gop.c +++ b/OvmfPkg/QemuVideoDxe/Gop.c @@ -14,6 +14,7 @@ **/ #include "Qemu.h" +#include STATIC VOID @@ -76,6 +77,63 @@ QemuVideoCompleteModeData ( } +EFI_STATUS +QemuVMSVGA2VideoCompleteModeData ( + IN QEMU_VIDEO_PRIVATE_DATA *Private, + OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode + ) +{ + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc; + UINT32 RedMask, GreenMask, BlueMask; + UINT32 BitsPerPixel, BytesPerLine, FBOffset; + + Info = Mode->Info; + Info->Version = 0; + Info->PixelFormat = PixelBitMask; + + RedMask = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_RED_MASK); + Info->PixelInformation.RedMask = RedMask; + + GreenMask = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_GREEN_MASK); + Info->PixelInformation.GreenMask = GreenMask; + + BlueMask = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_BLUE_MASK); + Info->PixelInformation.BlueMask = BlueMask; + + QemuVideoVMWSVGA2RegisterWrite (Private, SVGA_REG_ENABLE, 1); + + FBOffset = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_FB_OFFSET); + BytesPerLine = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_BYTES_PER_LINE); + BitsPerPixel = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_BITS_PER_PIXEL); + + if (BitsPerPixel == 32) { + if (BlueMask == 0xff && GreenMask == 0xff00 && RedMask == 0xff0000) { + Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + } else if (BlueMask == 0xff0000 && GreenMask == 0xff00 && RedMask == 0xff) { + Info->PixelFormat = PixelRedGreenBlueReserved8BitPerColor; + } + } + + Info->PixelInformation.ReservedMask = ((0x2u << (BitsPerPixel - 1u)) - 1u) + & ~(RedMask | GreenMask | BlueMask); + Info->PixelsPerScanLine = BytesPerLine / (BitsPerPixel / 8); + + Private->PciIo->GetBarAttributes ( + Private->PciIo, + PCI_BAR_IDX1, + NULL, + (VOID**) &FrameBufDesc + ); + + Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin + FBOffset; + Mode->FrameBufferSize = BytesPerLine * Info->VerticalResolution; + + FreePool (FrameBufDesc); + return EFI_SUCCESS; +} + + // // Graphics Output Protocol Member Functions // @@ -129,6 +187,10 @@ Routine Description: (*Info)->VerticalResolution = ModeData->VerticalResolution; QemuVideoCompleteModeInfo (ModeData, *Info); + if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA2) { + (*Info)->PixelsPerScanLine = ModeData->PixelsPerLine; + } + return EFI_SUCCESS; } @@ -176,6 +238,12 @@ Routine Description: case QEMU_VIDEO_BOCHS: InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]); break; + case QEMU_VIDEO_VMWARE_SVGA2: + InitializeVMWSVGA2GraphicsMode ( + Private, + &QemuVideoBochsModes[ModeData->InternalModeIndex] + ); + break; default: ASSERT (FALSE); return EFI_DEVICE_ERROR; @@ -186,7 +254,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_SVGA2) { + QemuVMSVGA2VideoCompleteModeData(Private, This->Mode); + } else { + QemuVideoCompleteModeData (Private, This->Mode); + } // // Re-initialize the frame buffer configure when mode changes. diff --git a/OvmfPkg/QemuVideoDxe/Initialize.c b/OvmfPkg/QemuVideoDxe/Initialize.c index d5d8cfef9661..8a6db566ab05 100644 --- a/OvmfPkg/QemuVideoDxe/Initialize.c +++ b/OvmfPkg/QemuVideoDxe/Initialize.c @@ -14,6 +14,8 @@ **/ #include "Qemu.h" +#include "UnalignedIoInternal.h" +#include /// @@ -346,3 +348,108 @@ QemuVideoBochsModeSetup ( return EFI_SUCCESS; } +VOID +QemuVideoVMWSVGA2RegisterWrite ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 reg, + UINT32 value + ) +{ + UnalignedIoWrite32 (Private->VMWareSVGA2_BasePort + SVGA_INDEX_PORT, reg); + UnalignedIoWrite32 (Private->VMWareSVGA2_BasePort + SVGA_VALUE_PORT, value); +} + +UINT32 +QemuVideoVMWSVGA2RegisterRead ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 reg + ) +{ + UnalignedIoWrite32 (Private->VMWareSVGA2_BasePort + SVGA_INDEX_PORT, reg); + return UnalignedIoRead32 (Private->VMWareSVGA2_BasePort + SVGA_VALUE_PORT); +} + +EFI_STATUS +QemuVideoVmwareModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +{ + UINT32 FBSize; + UINT32 MaxWidth, MaxHeight; + UINT32 Capabilities; + UINT32 HostBitsPerPixel; + UINT32 Index; + QEMU_VIDEO_MODE_DATA *ModeData; + QEMU_VIDEO_BOCHS_MODES *VideoMode; + + QemuVideoVMWSVGA2RegisterWrite (Private, SVGA_REG_ENABLE, 0); + + Private->ModeData = + AllocatePool (sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT); + if (Private->ModeData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + FBSize = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_FB_SIZE); + MaxWidth = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_MAX_WIDTH); + MaxHeight = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_MAX_HEIGHT); + Capabilities = QemuVideoVMWSVGA2RegisterRead (Private, SVGA_REG_CAPABILITIES); + if ((Capabilities & SVGA_CAP_8BIT_EMULATION) != 0) { + HostBitsPerPixel = QemuVideoVMWSVGA2RegisterRead( + Private, + SVGA_REG_HOST_BITS_PER_PIXEL + ); + QemuVideoVMWSVGA2RegisterWrite ( + Private, + SVGA_REG_BITS_PER_PIXEL, + HostBitsPerPixel + ); + } else { + HostBitsPerPixel = QemuVideoVMWSVGA2RegisterRead( + Private, + SVGA_REG_BITS_PER_PIXEL + ); + } + + ModeData = Private->ModeData; + VideoMode = &QemuVideoBochsModes[0]; + for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index ++) { + UINTN RequiredFbSize; + + ASSERT (HostBitsPerPixel % 8 == 0); + RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height * + (HostBitsPerPixel / 8); + if (RequiredFbSize <= FBSize + && VideoMode->Width <= MaxWidth + && VideoMode->Height <= MaxHeight) + { + UINT32 BytesPerLine; + + QemuVideoVMWSVGA2RegisterWrite ( + Private, + SVGA_REG_WIDTH, + VideoMode->Width + ); + QemuVideoVMWSVGA2RegisterWrite ( + Private, + SVGA_REG_HEIGHT, + VideoMode->Height + ); + BytesPerLine = QemuVideoVMWSVGA2RegisterRead ( + Private, + SVGA_REG_BYTES_PER_LINE + ); + ModeData->PixelsPerLine = BytesPerLine / (HostBitsPerPixel / 8); + + ModeData->InternalModeIndex = Index; + ModeData->HorizontalResolution = VideoMode->Width; + ModeData->VerticalResolution = VideoMode->Height; + ModeData->ColorDepth = HostBitsPerPixel; + + ModeData ++; + } + VideoMode ++; + } + Private->MaxMode = ModeData - Private->ModeData; + return EFI_SUCCESS; +} -- 2.3.2 (Apple Git-55)