* [PATCH v4 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA framebuffer support
@ 2017-04-05 12:55 Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 1/3] OvmfPkg: VMWare SVGA display device register definitions Phil Dennis-Jordan
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-05 12:55 UTC (permalink / raw)
To: edk2-devel
This extends the QemuVideoDxe driver to support the VMWare SVGA display
device implemented by Qemu. Drivers for this device exist for guest OSes
which do not support Qemu's other display adapters, so supporting it in
OVMF is useful in conjunction with those OSes.
I've tried to follow the existing pattern for device-specific code in
OVMF's QemuVideoDxe driver as much as possible, with a minimum of
additional code.
For the functionality this driver uses, 2 I/O ports are used with
32-bit wide reads and writes. Unfortunately, one of them is not 32-bit
aligned. This is fine as far as x86/x86-64 is concerned, but neither
EDK2's IoLib nor other platforms support such an access pattern.
This issue was already encountered/discussed on the edk2-devel list 4
years ago: http://edk2-devel.narkive.com/bwH3r0us/unaligned-i-o
I've therefore added UnalignedIoWrite/Read32() helper functions for
Ia32/X64, which I've based on IoLib's aligned ones.
Because querying mode properties on the device is only possible by
actually entering the mode, all display modes are queried on startup
and saved for when they are queried.
Feature branch: https://github.com/pmj/edk2/tree/ovmf_vmware_svga_v4
v2:
- Unaligned I/O helpers are now in a separate commit. [Laszlo]
- New header file with only essential device constants [Laszlo]
- ArmVirtPkg build failures fixed [Laszlo]
- Code formatting improvements in main driver code.
v3:
- Hardware describing header definitions now prefixed [Jordan, Laszlo]
- "2" dropped from "SVGA2" wherever it made sense. [Jordan, Laszlo]
- Various formatting tweaks to the unaligned IO helpers [Laszlo]
- Mode properties are now queried and stored up front. [Laszlo]
- Lots of formatting fixes in the driver code. [Laszlo]
- PCI BAR confusion resolved. [Laszlo]
- Found & fixed a memory leak.
v4: (only patch 3/3 changed)
- Struct assignment fix, pixel mask simplified, comment & whitespace
fixes. [Laszlo]
Phil Dennis-Jordan (3):
OvmfPkg: VMWare SVGA display device register definitions
OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
OvmfPkg/QemuVideoDxe: VMWare SVGA device support
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf | 6 +
OvmfPkg/Include/IndustryStandard/VmwareSvga.h | 104 +++++++++++++
OvmfPkg/QemuVideoDxe/Qemu.h | 29 ++++
OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h | 59 +++++++
OvmfPkg/QemuVideoDxe/Driver.c | 128 +++++++++++++++-
OvmfPkg/QemuVideoDxe/Gop.c | 61 +++++++-
OvmfPkg/QemuVideoDxe/Initialize.c | 161 ++++++++++++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c | 70 +++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c | 80 ++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c | 78 ++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c | 66 ++++++++
11 files changed, 835 insertions(+), 7 deletions(-)
create mode 100644 OvmfPkg/Include/IndustryStandard/VmwareSvga.h
create mode 100644 OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h
create mode 100644 OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
create mode 100644 OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
create mode 100644 OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
create mode 100644 OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
--
2.3.2 (Apple Git-55)
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/3] OvmfPkg: VMWare SVGA display device register definitions
2017-04-05 12:55 [PATCH v4 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA framebuffer support Phil Dennis-Jordan
@ 2017-04-05 12:55 ` Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support Phil Dennis-Jordan
2 siblings, 0 replies; 7+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-05 12:55 UTC (permalink / raw)
To: edk2-devel; +Cc: Phil Dennis-Jordan, Jordan Justen, Laszlo Ersek
From: Phil Dennis-Jordan <phil@philjordan.eu>
This adds a header file defining symbolic constants for the VMWare SVGA
virtual display device in preparation for supporting it in
QemuVideoDxe.
It is mostly an extract of the file lib/vmware/svga_reg.h from commit
329dd537456f93a806841ec8a8213aed11395def of VMWare's vmware-svga
repository at git://git.code.sf.net/p/vmware-svga/git (See also
http://vmware-svga.sourceforge.net/ )
Only the bare essentials necessary for initialisation, modesetting and
framebuffer access have been kept from the original file; macro names
have been prefixed with VMWARE_SVGA_ instead of SVGA2_, and the enum
definition has been adapted to comply with EDK2 naming conventions.
The original file was released by VMWare under the MIT license, this
has been retained.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
Notes:
v2:
- New, custom header file instead of importing VMWare's verbatim. [Laszlo]
v3:
- Prefixed macros with VMWARE_SVGA_ instead of SVGA2_ [Jordan, Laszlo]
- Adjusted enum definition to comply with EDK2 convention [Jordan, Laszlo]
- Tweaks to definitions of numeric constants [Laszlo]
- Renamed the file to fit with convention [Jordan, Laszlo]
- Dropped the "2" from SVGA2 wherever appropriate.
v4: (no changes)
OvmfPkg/Include/IndustryStandard/VmwareSvga.h | 104 ++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/OvmfPkg/Include/IndustryStandard/VmwareSvga.h b/OvmfPkg/Include/IndustryStandard/VmwareSvga.h
new file mode 100644
index 000000000000..693d44bab6c3
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/VmwareSvga.h
@@ -0,0 +1,104 @@
+/** @file
+
+ Macro and enum definitions of a subset of port numbers, register identifiers
+ and values required for driving the VMWare SVGA virtual display adapter,
+ also implemented by Qemu.
+
+ This file's contents was extracted from file lib/vmware/svga_reg.h in commit
+ 329dd537456f93a806841ec8a8213aed11395def of VMWare's vmware-svga repository:
+ git://git.code.sf.net/p/vmware-svga/git
+
+
+ Copyright 1998-2009 VMware, Inc. All rights reserved.
+ Portions Copyright 2017 Phil Dennis-Jordan <phil@philjordan.eu>
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+**/
+
+#ifndef _VMWARE_SVGA_H_
+#define _VMWARE_SVGA_H_
+
+#include <Base.h>
+
+//
+// IDs for recognising the device
+//
+#define VMWARE_PCI_VENDOR_ID_VMWARE 0x15AD
+#define VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+
+//
+// I/O port BAR offsets for register selection and read/write.
+//
+// The register index is written to the 32-bit index port, followed by a 32-bit
+// read or write on the value port to read or set that register's contents.
+//
+#define VMWARE_SVGA_INDEX_PORT 0x0
+#define VMWARE_SVGA_VALUE_PORT 0x1
+
+//
+// Some of the device's register indices for basic framebuffer functionality.
+//
+typedef enum {
+ VmwareSvgaRegId = 0,
+ VmwareSvgaRegEnable = 1,
+ VmwareSvgaRegWidth = 2,
+ VmwareSvgaRegHeight = 3,
+ VmwareSvgaRegMaxWidth = 4,
+ VmwareSvgaRegMaxHeight = 5,
+
+ VmwareSvgaRegBitsPerPixel = 7,
+
+ VmwareSvgaRegRedMask = 9,
+ VmwareSvgaRegGreenMask = 10,
+ VmwareSvgaRegBlueMask = 11,
+ VmwareSvgaRegBytesPerLine = 12,
+
+ VmwareSvgaRegFbOffset = 14,
+
+ VmwareSvgaRegFbSize = 16,
+ VmwareSvgaRegCapabilities = 17,
+
+ VmwareSvgaRegHostBitsPerPixel = 28,
+} VMWARE_SVGA_REGISTER;
+
+//
+// Values used with VmwareSvgaRegId for sanity-checking the device and getting
+// its version.
+//
+#define VMWARE_SVGA_MAGIC 0x900000U
+#define VMWARE_SVGA_MAKE_ID(ver) (VMWARE_SVGA_MAGIC << 8 | (ver))
+
+#define VMWARE_SVGA_VERSION_2 2
+#define VMWARE_SVGA_ID_2 VMWARE_SVGA_MAKE_ID (VMWARE_SVGA_VERSION_2)
+
+#define VMWARE_SVGA_VERSION_1 1
+#define VMWARE_SVGA_ID_1 VMWARE_SVGA_MAKE_ID (VMWARE_SVGA_VERSION_1)
+
+#define VMWARE_SVGA_VERSION_0 0
+#define VMWARE_SVGA_ID_0 VMWARE_SVGA_MAKE_ID (VMWARE_SVGA_VERSION_0)
+
+//
+// One of the capability bits advertised by VmwareSvgaRegCapabilities.
+//
+#define VMWARE_SVGA_CAP_8BIT_EMULATION BIT8
+
+#endif
--
2.3.2 (Apple Git-55)
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
2017-04-05 12:55 [PATCH v4 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA framebuffer support Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 1/3] OvmfPkg: VMWare SVGA display device register definitions Phil Dennis-Jordan
@ 2017-04-05 12:55 ` Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support Phil Dennis-Jordan
2 siblings, 0 replies; 7+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-05 12:55 UTC (permalink / raw)
To: edk2-devel; +Cc: Phil Dennis-Jordan, Jordan Justen, Laszlo Ersek
From: Phil Dennis-Jordan <phil@philjordan.eu>
The VMWare SVGA display device implemented by Qemu (-vga vmware) uses
an I/O-type BAR which is laid out such that some register offsets are
not aligned to the read/write width with which they are expected to be
accessed. (The register value port has an offset of 1 and requires
32 bit wide read/write access.)
The EFI_PCI_IO_PROTOCOL's Io.Read/Io.Write functions do not support
such unaligned I/O.
Before a driver for this device can be added to QemuVideoDxe, helper
functions for unaligned I/O are therefore required. This adds the
functions UnalignedIoWrite32 and UnalignedIoRead32, based on IoLib's
IoWrite32 and IoRead32, for the Ia32 and X64 architectures. Port I/O
requires inline assembly, so implementations are provided for the GCC,
ICC, and Microsoft compiler families. Such I/O is not possible on other
architectures, a dummy (ASSERT()ing) implementation is therefore
provided to satisfy the linker.
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Suggested-by: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
Notes:
v2:
- Separate commit for the unaligned I/O helper functions. [Laszlo]
- Dummy implementations return values despite ASSERT(). [Laszlo]
- Build failure in ArmVirtPkg fixed. [Laszlo]
- More consistent API docs and function ordering.
v3:
- Fixed typos in commit message [Laszlo]
- Added Suggested-by: tag [Laszlo]
- Rewrapped comment lines to 79 chars [Laszlo]
- Corrected whitespace in function calls [Laszlo]
- EFIAPI dropped. [Laszlo]
- Fixed return value in dummy UnsignedIoWrite32 [Laszlo]
- Dropped "N" imm8 constraint in GCC inline asm [Laszlo]
v4: (no changes)
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf | 6 ++
OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h | 59 +++++++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c | 70 +++++++++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c | 80 ++++++++++++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c | 78 +++++++++++++++++++
OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c | 66 ++++++++++++++++
6 files changed, 359 insertions(+)
diff --git a/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf b/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
index affb6ffd88e0..346a5aed94fa 100644
--- a/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
+++ b/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
@@ -41,6 +41,12 @@ [Sources.common]
[Sources.Ia32, Sources.X64]
VbeShim.c
+ UnalignedIoGcc.c | GCC
+ UnalignedIoMsc.c | MSFT
+ UnalignedIoIcc.c | INTEL
+
+[Sources.IPF, Sources.EBC, Sources.ARM, Sources.AARCH64]
+ UnalignedIoUnsupported.c
[Packages]
MdePkg/MdePkg.dec
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h b/OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h
new file mode 100644
index 000000000000..234de6c21bd1
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h
@@ -0,0 +1,59 @@
+/** @file
+ Unaligned port I/O, with implementations for various x86 compilers and a
+ dummy for platforms which do not support unaligned port I/O.
+
+ Copyright (c) 2017, Phil Dennis-Jordan.<BR>
+ 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.
+
+**/
+
+#ifndef _UNALIGNED_IO_INTERNAL_H_
+#define _UNALIGNED_IO_INTERNAL_H_
+
+/**
+ Performs a 32-bit write to the specified, possibly unaligned I/O-type address.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port I/O port address
+ @param[in] Value 32-bit word to write
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+UnalignedIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ );
+
+/**
+ Reads a 32-bit word from the specified, possibly unaligned I/O-type address.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is
+ returned. This function must guarantee that all I/O read and write operations
+ are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+UnalignedIoRead32 (
+ IN UINTN Port
+ );
+
+#endif
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
new file mode 100644
index 000000000000..105d55d3b903
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
@@ -0,0 +1,70 @@
+/** @file
+ Unaligned Port I/O. This file has compiler specifics for GCC as there is no
+ ANSI C standard for doing IO.
+
+ Based on IoLibGcc.c.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ 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.
+
+**/
+
+
+#include "UnalignedIoInternal.h"
+
+/**
+ Performs a 32-bit write to the specified, possibly unaligned I/O-type
+ address.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by
+ Value and returns Value. This function must guarantee that all I/O read and
+ write operations are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port I/O port address
+ @param[in] Value 32-bit word to write
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+UnalignedIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ __asm__ __volatile__ ( "outl %0, %1" : : "a" (Value), "d" ((UINT16)Port) );
+ return Value;
+}
+
+/**
+ Reads a 32-bit word from the specified, possibly unaligned I/O-type address.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is
+ returned. This function must guarantee that all I/O read and write operations
+ are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+UnalignedIoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Data;
+ __asm__ __volatile__ ( "inl %1, %0" : "=a" (Data) : "d" ((UINT16)Port) );
+ return Data;
+}
+
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
new file mode 100644
index 000000000000..79f3e446ddba
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
@@ -0,0 +1,80 @@
+/** @file
+ Unaligned port I/O. This file has compiler specifics for ICC as there
+ is no ANSI C standard for doing IO.
+
+ Based on IoLibIcc.c.
+
+ Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+ 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.
+
+**/
+
+
+#include "UnalignedIoInternal.h"
+
+/**
+ Performs a 32-bit write to the specified, possibly unaligned I/O-type
+ address.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by
+ Value and returns Value. This function must guarantee that all I/O read and
+ write operations are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port I/O port address
+ @param[in] Value 32-bit word to write
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+UnalignedIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ __asm {
+ mov eax, dword ptr [Value]
+ mov dx, word ptr [Port]
+ out dx, eax
+ }
+
+ return Value;
+}
+
+/**
+ Reads a 32-bit word from the specified, possibly unaligned I/O-type address.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is
+ returned. This function must guarantee that all I/O read and write operations
+ are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+UnalignedIoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Data;
+
+ __asm {
+ mov dx, word ptr [Port]
+ in eax, dx
+ mov dword ptr [Data], eax
+ }
+
+ return Data;
+}
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
new file mode 100644
index 000000000000..a466baee8486
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
@@ -0,0 +1,78 @@
+/** @file
+ Unaligned port I/O. This file has compiler specifics for Microsoft C as there
+ is no ANSI C standard for doing IO.
+
+ Based on IoLibMsc.c
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ 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.
+
+**/
+
+
+#include "UnalignedIoInternal.h"
+
+unsigned long _inpd (unsigned short port);
+unsigned long _outpd (unsigned short port, unsigned long dataword );
+void _ReadWriteBarrier (void);
+
+/**
+ Performs a 32-bit write to the specified, possibly unaligned I/O-type
+ address.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by
+ Value and returns Value. This function must guarantee that all I/O read and
+ write operations are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port I/O port address
+ @param[in] Value 32-bit word to write
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+UnalignedIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ _ReadWriteBarrier ();
+ _outpd ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ return Value;
+}
+
+/**
+ Reads a 32-bit word from the specified, possibly unaligned I/O-type address.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is
+ returned. This function must guarantee that all I/O read and write operations
+ are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+UnalignedIoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Value;
+
+ _ReadWriteBarrier ();
+ Value = _inpd ((UINT16)Port);
+ _ReadWriteBarrier ();
+ return Value;
+}
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
new file mode 100644
index 000000000000..57560ab38fcf
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
@@ -0,0 +1,66 @@
+/** @file
+ Unaligned port I/O dummy implementation for platforms which do not support it.
+
+ Copyright (c) 2017, Phil Dennis-Jordan.<BR>
+ 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.
+
+**/
+
+
+#include <Library/DebugLib.h>
+#include "UnalignedIoInternal.h"
+
+/**
+ Performs a 32-bit write to the specified, possibly unaligned I/O-type
+ address.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by
+ Value and returns Value. This function must guarantee that all I/O read and
+ write operations are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port I/O port address
+ @param[in] Value 32-bit word to write
+
+ @return The value written to the I/O port.
+
+**/
+UINT32
+UnalignedIoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ ASSERT (FALSE);
+ return Value;
+}
+
+/**
+ Reads a 32-bit word from the specified, possibly unaligned I/O-type address.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is
+ returned. This function must guarantee that all I/O read and write operations
+ are serialized.
+
+ If 32-bit unaligned I/O port operations are not supported, then ASSERT().
+
+ @param[in] Port The I/O port to read.
+
+ @return The value read.
+
+**/
+UINT32
+UnalignedIoRead32 (
+ IN UINTN Port
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
--
2.3.2 (Apple Git-55)
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support
2017-04-05 12:55 [PATCH v4 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA framebuffer support Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 1/3] OvmfPkg: VMWare SVGA display device register definitions Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
@ 2017-04-05 12:55 ` Phil Dennis-Jordan
2017-04-05 13:58 ` Laszlo Ersek
2017-04-06 5:12 ` Laszlo Ersek
2 siblings, 2 replies; 7+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-05 12:55 UTC (permalink / raw)
To: edk2-devel; +Cc: Phil Dennis-Jordan, Jordan Justen, Laszlo Ersek
From: Phil Dennis-Jordan <phil@philjordan.eu>
In addition to the QXL, Cirrus, etc. VGA adapters, Qemu also implements
a basic version of VMWare's SVGA 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 SVGA 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 <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
---
Notes:
v2:
- Unaligned I/O helper functions moved to separate commit [Laszlo]
- Multi-line function call whitespace fixes.
v3:
- Dropped the "2" from "SVGA2" where appropriate. [Jordan, Laszlo]
- Renamed various struct fields and functions with consistent prefixes [Laszlo]
- #include orders fixed [Laszlo]
- Renamedi/moved lots of local variables to comply with convention. [Laszlo]
- Added error checking to PCI BAR queries. [Laszlo]
- Moved some function definitions around for better grouping. [Laszlo]
- Fixed ClearScreen() to use the correct VRAM BAR. [Laszlo]
- Changed modelist initialisation to fetch all mode data on startup, so mode
queries can return everything including channel masks without hitting the
device. Mask calculations hopefully make more sense now. [Laszlo]
- Whitespace fixes. [Laszlo]
- Fixed a memory leak in BAR query.
v4:
- Simplified mode info pixel mask calculation & PCI BAR OOB check. [Laszlo]
- Replaced struct assignment with CopyMem. [Laszlo]
- Whitespace & comment typo fixes. [Laszlo]
OvmfPkg/QemuVideoDxe/Qemu.h | 29 ++++
OvmfPkg/QemuVideoDxe/Driver.c | 128 +++++++++++++++-
OvmfPkg/QemuVideoDxe/Gop.c | 61 +++++++-
OvmfPkg/QemuVideoDxe/Initialize.c | 161 ++++++++++++++++++++
4 files changed, 372 insertions(+), 7 deletions(-)
diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h
index 2ce37defc5b8..7fbb25b3efd3 100644
--- a/OvmfPkg/QemuVideoDxe/Qemu.h
+++ b/OvmfPkg/QemuVideoDxe/Qemu.h
@@ -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 {
@@ -115,10 +116,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;
///
@@ -502,9 +506,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
diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c
index fc8025ec46de..2ed1506a1381 100644
--- a/OvmfPkg/QemuVideoDxe/Driver.c
+++ b/OvmfPkg/QemuVideoDxe/Driver.c
@@ -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,
@@ -58,6 +60,11 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
QEMU_VIDEO_BOCHS_MMIO,
L"QEMU VirtIO VGA"
},{
+ VMWARE_PCI_VENDOR_ID_VMWARE,
+ VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2,
+ QEMU_VIDEO_VMWARE_SVGA,
+ L"QEMU VMWare SVGA"
+ },{
0 /* end of list */
}
};
@@ -242,6 +249,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
@@ -317,6 +325,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
//
Status = gBS->HandleProtocol (
@@ -371,6 +431,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;
@@ -750,7 +813,7 @@ ClearScreen (
Private->PciIo->Mem.Write (
Private->PciIo,
EfiPciIoWidthFillUint32,
- 0,
+ Private->FrameBufferVramBarIndex,
0,
0x400000 >> 2,
&Color
@@ -888,6 +951,38 @@ BochsRead (
}
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,
UINTN Reg,
@@ -941,6 +1036,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 (
diff --git a/OvmfPkg/QemuVideoDxe/Gop.c b/OvmfPkg/QemuVideoDxe/Gop.c
index 359e9217d3d1..512fd27acbda 100644
--- a/OvmfPkg/QemuVideoDxe/Gop.c
+++ b/OvmfPkg/QemuVideoDxe/Gop.c
@@ -13,6 +13,7 @@
**/
+#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
STATIC
@@ -75,6 +76,42 @@ 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;
+
+ FreePool (FrameBufDesc);
+ return Status;
+}
+
//
// Graphics Output Protocol Member Functions
@@ -124,10 +161,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;
}
@@ -176,6 +217,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;
@@ -186,7 +233,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.
diff --git a/OvmfPkg/QemuVideoDxe/Initialize.c b/OvmfPkg/QemuVideoDxe/Initialize.c
index d5d8cfef9661..849186a6f05d 100644
--- a/OvmfPkg/QemuVideoDxe/Initialize.c
+++ b/OvmfPkg/QemuVideoDxe/Initialize.c
@@ -13,6 +13,7 @@
**/
+#include <IndustryStandard/VmwareSvga.h>
#include "Qemu.h"
@@ -346,3 +347,163 @@ 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
+ );
+ BytesPerLine = VmwareSvgaRead (
+ Private,
+ VmwareSvgaRegBytesPerLine
+ );
+
+ 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;
+}
--
2.3.2 (Apple Git-55)
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support
2017-04-05 12:55 ` [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support Phil Dennis-Jordan
@ 2017-04-05 13:58 ` Laszlo Ersek
2017-04-05 19:41 ` Jordan Justen
2017-04-06 5:12 ` Laszlo Ersek
1 sibling, 1 reply; 7+ messages in thread
From: Laszlo Ersek @ 2017-04-05 13:58 UTC (permalink / raw)
To: Phil Dennis-Jordan, edk2-devel; +Cc: Jordan Justen, Phil Dennis-Jordan
On 04/05/17 14:55, Phil Dennis-Jordan wrote:
> From: Phil Dennis-Jordan <phil@philjordan.eu>
>
> In addition to the QXL, Cirrus, etc. VGA adapters, Qemu also implements
> a basic version of VMWare's SVGA 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 SVGA 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 <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
> ---
>
> Notes:
> v2:
> - Unaligned I/O helper functions moved to separate commit [Laszlo]
> - Multi-line function call whitespace fixes.
>
> v3:
> - Dropped the "2" from "SVGA2" where appropriate. [Jordan, Laszlo]
> - Renamed various struct fields and functions with consistent prefixes [Laszlo]
> - #include orders fixed [Laszlo]
> - Renamedi/moved lots of local variables to comply with convention. [Laszlo]
> - Added error checking to PCI BAR queries. [Laszlo]
> - Moved some function definitions around for better grouping. [Laszlo]
> - Fixed ClearScreen() to use the correct VRAM BAR. [Laszlo]
> - Changed modelist initialisation to fetch all mode data on startup, so mode
> queries can return everything including channel masks without hitting the
> device. Mask calculations hopefully make more sense now. [Laszlo]
> - Whitespace fixes. [Laszlo]
> - Fixed a memory leak in BAR query.
>
> v4:
> - Simplified mode info pixel mask calculation & PCI BAR OOB check. [Laszlo]
> - Replaced struct assignment with CopyMem. [Laszlo]
> - Whitespace & comment typo fixes. [Laszlo]
Also, you moved around the "BytesPerLine" assignment.
Then I noticed that you actually moved around the *second* instance of
it, so you continue to have two identical assignments, one of which
should be superfluous:
[snip]
> +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
> + );
> + BytesPerLine = VmwareSvgaRead (
> + Private,
> + VmwareSvgaRegBytesPerLine
> + );
This is #1.
> +
> + 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);
This is #2.
Which one do you want to keep? I think we should drop #1, and keep #2.
Do you wish to submit v5, or are you okay if I remove #1 for you at
commit time?
With this tweak,
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Before committing, I would like to give Jordan a chance to comment as
well. I think Friday this week should be a good day to commit the series.
Impressive work!
Thank you,
Laszlo
> + 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;
> +}
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support
2017-04-05 13:58 ` Laszlo Ersek
@ 2017-04-05 19:41 ` Jordan Justen
0 siblings, 0 replies; 7+ messages in thread
From: Jordan Justen @ 2017-04-05 19:41 UTC (permalink / raw)
To: Laszlo Ersek, Phil Dennis-Jordan, edk2-devel; +Cc: Phil Dennis-Jordan
On 2017-04-05 06:58:33, Laszlo Ersek wrote:
>
> This is #2.
>
> Which one do you want to keep? I think we should drop #1, and keep #2.
>
> Do you wish to submit v5, or are you okay if I remove #1 for you at
> commit time?
>
> With this tweak,
>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>
> Before committing, I would like to give Jordan a chance to comment as
> well. I think Friday this week should be a good day to commit the series.
After convincing myself that, yes, the unaligned i/o was *actually*
required. :) / :(
Series Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
The one comment I had, is given how verbose the 3 inline assembly
source files are in patch 2, maybe nasm code would actually be cleaner
looking. But, considering we'd need both an IA32 and X64 version, it
isn't much better.
> Impressive work!
Agreed. Thanks for your contribution Phil!
-Jordan
>
> > + 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;
> > +}
> >
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support
2017-04-05 12:55 ` [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support Phil Dennis-Jordan
2017-04-05 13:58 ` Laszlo Ersek
@ 2017-04-06 5:12 ` Laszlo Ersek
1 sibling, 0 replies; 7+ messages in thread
From: Laszlo Ersek @ 2017-04-06 5:12 UTC (permalink / raw)
To: Phil Dennis-Jordan, edk2-devel; +Cc: Jordan Justen, Phil Dennis-Jordan
Apologies, I noticed something else:
On 04/05/17 14:55, Phil Dennis-Jordan wrote:
> From: Phil Dennis-Jordan <phil@philjordan.eu>
>
> In addition to the QXL, Cirrus, etc. VGA adapters, Qemu also implements
> a basic version of VMWare's SVGA 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 SVGA 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 <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
> ---
>
> Notes:
> v2:
> - Unaligned I/O helper functions moved to separate commit [Laszlo]
> - Multi-line function call whitespace fixes.
>
> v3:
> - Dropped the "2" from "SVGA2" where appropriate. [Jordan, Laszlo]
> - Renamed various struct fields and functions with consistent prefixes [Laszlo]
> - #include orders fixed [Laszlo]
> - Renamedi/moved lots of local variables to comply with convention. [Laszlo]
> - Added error checking to PCI BAR queries. [Laszlo]
> - Moved some function definitions around for better grouping. [Laszlo]
> - Fixed ClearScreen() to use the correct VRAM BAR. [Laszlo]
> - Changed modelist initialisation to fetch all mode data on startup, so mode
> queries can return everything including channel masks without hitting the
> device. Mask calculations hopefully make more sense now. [Laszlo]
> - Whitespace fixes. [Laszlo]
> - Fixed a memory leak in BAR query.
>
> v4:
> - Simplified mode info pixel mask calculation & PCI BAR OOB check. [Laszlo]
> - Replaced struct assignment with CopyMem. [Laszlo]
> - Whitespace & comment typo fixes. [Laszlo]
>
> OvmfPkg/QemuVideoDxe/Qemu.h | 29 ++++
> OvmfPkg/QemuVideoDxe/Driver.c | 128 +++++++++++++++-
> OvmfPkg/QemuVideoDxe/Gop.c | 61 +++++++-
> OvmfPkg/QemuVideoDxe/Initialize.c | 161 ++++++++++++++++++++
> 4 files changed, 372 insertions(+), 7 deletions(-)
>
> diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h
> index 2ce37defc5b8..7fbb25b3efd3 100644
> --- a/OvmfPkg/QemuVideoDxe/Qemu.h
> +++ b/OvmfPkg/QemuVideoDxe/Qemu.h
> @@ -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 {
> @@ -115,10 +116,13 @@ typedef struct {
> //
> UINTN MaxMode;
> QEMU_VIDEO_MODE_DATA *ModeData;
> + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *VmwareSvgaModeInfo;
This array is dynamically allocated in QemuVideoVmwareSvgaModeSetup(),
which is called from QemuVideoControllerDriverStart(). That's OK.
However, it is not freed (except on the error path in
QemuVideoVmwareSvgaModeSetup(), under the Rollback label). It should be
freed in two additional places:
- in QemuVideoControllerDriverStart(), under the FreeModeData label
(which is also part of an (outer) error path),
- in QemuVideoControllerDriverStop(), near
FreePool (Private->ModeData);
Of course, these additional FreePool() calls should be conditional, as
FreePool() doesn't handle NULL automatically.
I should have noticed this earlier (in v3); sorry about that.
Thanks,
Laszlo
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-04-06 5:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-05 12:55 [PATCH v4 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA framebuffer support Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 1/3] OvmfPkg: VMWare SVGA display device register definitions Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
2017-04-05 12:55 ` [PATCH v4 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA device support Phil Dennis-Jordan
2017-04-05 13:58 ` Laszlo Ersek
2017-04-05 19:41 ` Jordan Justen
2017-04-06 5:12 ` Laszlo Ersek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox