public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support
@ 2017-04-02 22:44 Phil Dennis-Jordan
  2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-02 22:44 UTC (permalink / raw)
  To: edk2-devel

This extends the QemuVideoDxe driver to support the VMWare SVGA2 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.

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.

Phil Dennis-Jordan (3):
  OvmfPkg: VMWare SVGA2 display device register definitions
  OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
  OvmfPkg/QemuVideoDxe: VMWare SVGA II device support.

 OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf          |   6 ++
 OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 +++++++++++++++++++
 OvmfPkg/QemuVideoDxe/Qemu.h                    |  37 +++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h     |  59 +++++++++++
 OvmfPkg/QemuVideoDxe/Driver.c                  |  76 ++++++++++++++
 OvmfPkg/QemuVideoDxe/Gop.c                     |  74 +++++++++++++-
 OvmfPkg/QemuVideoDxe/Initialize.c              | 107 ++++++++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c          |  69 +++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c          |  79 +++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c          |  81 +++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c  |  65 ++++++++++++
 11 files changed, 754 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Include/IndustryStandard/VMWareSVGA2.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] 12+ messages in thread

* [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions
  2017-04-02 22:44 [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
@ 2017-04-02 22:44 ` Phil Dennis-Jordan
  2017-04-03 23:17   ` Jordan Justen
  2017-04-04  7:54   ` Laszlo Ersek
  2017-04-02 22:44 ` [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-02 22:44 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 SVGA2
virtual display device in preparation for supporting it in QemuVideoDXE.

It is 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.

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>
---

Notes:
    v2:
    - New, custom header file instead of importing VMWare's verbatim. [Laszlo]

 OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 ++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
new file mode 100644
index 000000000000..9db553155957
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
@@ -0,0 +1,102 @@
+/** @file
+
+  Macro and enum definitions of a subset of port numbers, register identifiers
+  and values required for driving the VMWare SVGA2 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_SVGA2_H_
+#define _VMWARE_SVGA2_H_
+
+//
+// IDs for recognising the device
+//
+#define PCI_VENDOR_ID_VMWARE            0x15AD
+#define 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 SVGA_INDEX_PORT         0x0
+#define SVGA_VALUE_PORT         0x1
+
+//
+// Some of the device's register indices for basic framebuffer functionality.
+//
+enum {
+  SVGA_REG_ID = 0,
+  SVGA_REG_ENABLE = 1,
+  SVGA_REG_WIDTH = 2,
+  SVGA_REG_HEIGHT = 3,
+  SVGA_REG_MAX_WIDTH = 4,
+  SVGA_REG_MAX_HEIGHT = 5,
+
+  SVGA_REG_BITS_PER_PIXEL = 7,
+
+  SVGA_REG_RED_MASK = 9,
+  SVGA_REG_GREEN_MASK = 10,
+  SVGA_REG_BLUE_MASK = 11,
+  SVGA_REG_BYTES_PER_LINE = 12,
+
+  SVGA_REG_FB_OFFSET = 14,
+
+  SVGA_REG_FB_SIZE = 16,
+  SVGA_REG_CAPABILITIES = 17,
+
+  SVGA_REG_HOST_BITS_PER_PIXEL = 28,
+};
+
+//
+// Values used with SVGA_REG_ID for sanity-checking the device and getting
+// its version.
+//
+#define SVGA_MAGIC         0x900000UL
+#define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))
+
+#define SVGA_VERSION_2     2
+#define SVGA_ID_2          SVGA_MAKE_ID(SVGA_VERSION_2)
+
+#define SVGA_VERSION_1     1
+#define SVGA_ID_1          SVGA_MAKE_ID(SVGA_VERSION_1)
+
+#define SVGA_VERSION_0     0
+#define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
+
+//
+// One of the capability bits advertised by SVGA_REG_CAPABILITIES.
+//
+#define SVGA_CAP_8BIT_EMULATION     0x00000100
+
+#endif
-- 
2.3.2 (Apple Git-55)



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
  2017-04-02 22:44 [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
  2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
@ 2017-04-02 22:44 ` Phil Dennis-Jordan
  2017-04-04  8:19   ` Laszlo Ersek
  2017-04-02 22:44 ` [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support Phil Dennis-Jordan
  2017-04-02 22:48 ` [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
  3 siblings, 1 reply; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-02 22:44 UTC (permalink / raw)
  To: edk2-devel; +Cc: Phil Dennis-Jordan, Jordan Justen, Laszlo Ersek

From: Phil Dennis-Jordan <phil@philjordan.eu>

The VMWare SVGA2 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 Pci.Read/Pci.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 Read32, 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>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
---

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.

 OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf         |  6 ++
 OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h    | 59 ++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c         | 69 +++++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c         | 79 +++++++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c         | 81 ++++++++++++++++++++
 OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c | 65 ++++++++++++++++
 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..a069f3b98087
--- /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 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  I/O port from which to read.
+
+  @return The value read from the specified location.
+
+**/
+UINT32
+UnalignedIoRead32 (
+  IN      UINTN                     Port
+  );
+
+#endif
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
new file mode 100644
index 000000000000..8bb74c784c06
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
@@ -0,0 +1,69 @@
+/** @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), "Nd"((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  I/O port from which to read.
+
+  @return The value read from the specified location.
+
+**/
+UINT32
+UnalignedIoRead32 (
+  IN      UINTN                     Port
+  )
+{
+  UINT32 Data;
+  __asm__ __volatile__ ( "inl %1, %0" : "=a"(Data) : "Nd"((UINT16)Port) );
+  return Data;
+}
+
diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
new file mode 100644
index 000000000000..ac365a8b6be5
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
@@ -0,0 +1,79 @@
+/** @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  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written 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  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..2eda40a47e2b
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
@@ -0,0 +1,81 @@
+/** @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 I/O port operations are not supported, then ASSERT().
+  If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written to the I/O port.
+
+**/
+UINT32
+EFIAPI
+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 I/O port operations are not supported, then ASSERT().
+  If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+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..1d37ecb7bec0
--- /dev/null
+++ b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
@@ -0,0 +1,65 @@
+/** @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 "UnalignedIoInternal.h"
+#include <Library/DebugLib.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 0;
+}
+
+/**
+  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  I/O port from which to read.
+
+  @return The value read from the specified location.
+
+**/
+UINT32
+UnalignedIoRead32 (
+  IN      UINTN                     Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
-- 
2.3.2 (Apple Git-55)



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support.
  2017-04-02 22:44 [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
  2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
  2017-04-02 22:44 ` [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
@ 2017-04-02 22:44 ` Phil Dennis-Jordan
  2017-04-04 10:13   ` Laszlo Ersek
  2017-04-02 22:48 ` [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
  3 siblings, 1 reply; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-02 22:44 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 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 <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.

 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 <IndustryStandard/VMWareSVGA2.h>
 #include <IndustryStandard/Acpi.h>
 
 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 <IndustryStandard/VMWareSVGA2.h>
 
 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 <IndustryStandard/VMWareSVGA2.h>
 
 
 ///
@@ -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)



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support
  2017-04-02 22:44 [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
                   ` (2 preceding siblings ...)
  2017-04-02 22:44 ` [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support Phil Dennis-Jordan
@ 2017-04-02 22:48 ` Phil Dennis-Jordan
  3 siblings, 0 replies; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-02 22:48 UTC (permalink / raw)
  To: edk2-devel-01

Looks like I missed off the branch link, sorry:

https://github.com/pmj/edk2/commits/ovmf_vmware_svga2_v2

On Mon, Apr 3, 2017 at 10:44 AM, Phil Dennis-Jordan <lists@philjordan.eu> wrote:
> This extends the QemuVideoDxe driver to support the VMWare SVGA2 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.
>
> 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.
>
> Phil Dennis-Jordan (3):
>   OvmfPkg: VMWare SVGA2 display device register definitions
>   OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
>   OvmfPkg/QemuVideoDxe: VMWare SVGA II device support.
>
>  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf          |   6 ++
>  OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 +++++++++++++++++++
>  OvmfPkg/QemuVideoDxe/Qemu.h                    |  37 +++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h     |  59 +++++++++++
>  OvmfPkg/QemuVideoDxe/Driver.c                  |  76 ++++++++++++++
>  OvmfPkg/QemuVideoDxe/Gop.c                     |  74 +++++++++++++-
>  OvmfPkg/QemuVideoDxe/Initialize.c              | 107 ++++++++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c          |  69 +++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c          |  79 +++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c          |  81 +++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c  |  65 ++++++++++++
>  11 files changed, 754 insertions(+), 1 deletion(-)
>  create mode 100644 OvmfPkg/Include/IndustryStandard/VMWareSVGA2.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] 12+ messages in thread

* Re: [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions
  2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
@ 2017-04-03 23:17   ` Jordan Justen
  2017-04-04 10:40     ` Laszlo Ersek
  2017-04-04  7:54   ` Laszlo Ersek
  1 sibling, 1 reply; 12+ messages in thread
From: Jordan Justen @ 2017-04-03 23:17 UTC (permalink / raw)
  To: Phil Dennis-Jordan, edk2-devel; +Cc: Phil Dennis-Jordan, Laszlo Ersek

On 2017-04-02 15:44:55, Phil Dennis-Jordan wrote:
> From: Phil Dennis-Jordan <phil@philjordan.eu>
> 
> This adds a header file defining symbolic constants for the VMWare SVGA2
> virtual display device in preparation for supporting it in QemuVideoDXE.
> 
> It is 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.
> 
> 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>
> ---
> 
> Notes:
>     v2:
>     - New, custom header file instead of importing VMWare's verbatim. [Laszlo]
> 
>  OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 ++++++++++++++++++++
>  1 file changed, 102 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h

I think EDK II's file naming convention would prefer VmwareSvga2.h, or
possibly VmWareSvga2.h. (But, the former looks better to me.)

Since it covers svga and svga2, should we just drop the '2' from the
filename?

> new file mode 100644
> index 000000000000..9db553155957
> --- /dev/null
> +++ b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
> @@ -0,0 +1,102 @@
> +/** @file
> +
> +  Macro and enum definitions of a subset of port numbers, register identifiers
> +  and values required for driving the VMWare SVGA2 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_SVGA2_H_
> +#define _VMWARE_SVGA2_H_
> +
> +//
> +// IDs for recognising the device
> +//
> +#define PCI_VENDOR_ID_VMWARE            0x15AD
> +#define 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 SVGA_INDEX_PORT         0x0
> +#define SVGA_VALUE_PORT         0x1

Thanks for taking Laszlo's advice about pulling out the minimal
definitions and EDK II-ifying it. (I think he may be right about the
Xen contribution.)

One request I have is, how about prefixing all the SVGA items as
VMWARE_SVGA? SVGA seems to generic of a term here.

Thanks,

-Jordan

> +
> +//
> +// Some of the device's register indices for basic framebuffer functionality.
> +//
> +enum {
> +  SVGA_REG_ID = 0,
> +  SVGA_REG_ENABLE = 1,
> +  SVGA_REG_WIDTH = 2,
> +  SVGA_REG_HEIGHT = 3,
> +  SVGA_REG_MAX_WIDTH = 4,
> +  SVGA_REG_MAX_HEIGHT = 5,
> +
> +  SVGA_REG_BITS_PER_PIXEL = 7,
> +
> +  SVGA_REG_RED_MASK = 9,
> +  SVGA_REG_GREEN_MASK = 10,
> +  SVGA_REG_BLUE_MASK = 11,
> +  SVGA_REG_BYTES_PER_LINE = 12,
> +
> +  SVGA_REG_FB_OFFSET = 14,
> +
> +  SVGA_REG_FB_SIZE = 16,
> +  SVGA_REG_CAPABILITIES = 17,
> +
> +  SVGA_REG_HOST_BITS_PER_PIXEL = 28,
> +};
> +
> +//
> +// Values used with SVGA_REG_ID for sanity-checking the device and getting
> +// its version.
> +//
> +#define SVGA_MAGIC         0x900000UL
> +#define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))
> +
> +#define SVGA_VERSION_2     2
> +#define SVGA_ID_2          SVGA_MAKE_ID(SVGA_VERSION_2)
> +
> +#define SVGA_VERSION_1     1
> +#define SVGA_ID_1          SVGA_MAKE_ID(SVGA_VERSION_1)
> +
> +#define SVGA_VERSION_0     0
> +#define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
> +
> +//
> +// One of the capability bits advertised by SVGA_REG_CAPABILITIES.
> +//
> +#define SVGA_CAP_8BIT_EMULATION     0x00000100
> +
> +#endif
> -- 
> 2.3.2 (Apple Git-55)
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions
  2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
  2017-04-03 23:17   ` Jordan Justen
@ 2017-04-04  7:54   ` Laszlo Ersek
  1 sibling, 0 replies; 12+ messages in thread
From: Laszlo Ersek @ 2017-04-04  7:54 UTC (permalink / raw)
  To: Phil Dennis-Jordan, edk2-devel; +Cc: Jordan Justen, Phil Dennis-Jordan

On 04/03/17 00:44, Phil Dennis-Jordan wrote:
> From: Phil Dennis-Jordan <phil@philjordan.eu>
> 
> This adds a header file defining symbolic constants for the VMWare SVGA2
> virtual display device in preparation for supporting it in QemuVideoDXE.
> 
> It is 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.
> 
> 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>
> ---
> 
> Notes:
>     v2:
>     - New, custom header file instead of importing VMWare's verbatim. [Laszlo]
> 
>  OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 ++++++++++++++++++++
>  1 file changed, 102 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
> new file mode 100644
> index 000000000000..9db553155957
> --- /dev/null
> +++ b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
> @@ -0,0 +1,102 @@
> +/** @file
> +
> +  Macro and enum definitions of a subset of port numbers, register identifiers
> +  and values required for driving the VMWare SVGA2 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_SVGA2_H_
> +#define _VMWARE_SVGA2_H_
> +
> +//
> +// IDs for recognising the device
> +//
> +#define PCI_VENDOR_ID_VMWARE            0x15AD
> +#define 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 SVGA_INDEX_PORT         0x0
> +#define SVGA_VALUE_PORT         0x1

Please call these VMW_SVGA_...

> +
> +//
> +// Some of the device's register indices for basic framebuffer functionality.
> +//
> +enum {
> +  SVGA_REG_ID = 0,
> +  SVGA_REG_ENABLE = 1,
> +  SVGA_REG_WIDTH = 2,
> +  SVGA_REG_HEIGHT = 3,
> +  SVGA_REG_MAX_WIDTH = 4,
> +  SVGA_REG_MAX_HEIGHT = 5,
> +
> +  SVGA_REG_BITS_PER_PIXEL = 7,
> +
> +  SVGA_REG_RED_MASK = 9,
> +  SVGA_REG_GREEN_MASK = 10,
> +  SVGA_REG_BLUE_MASK = 11,
> +  SVGA_REG_BYTES_PER_LINE = 12,
> +
> +  SVGA_REG_FB_OFFSET = 14,
> +
> +  SVGA_REG_FB_SIZE = 16,
> +  SVGA_REG_CAPABILITIES = 17,
> +
> +  SVGA_REG_HOST_BITS_PER_PIXEL = 28,
> +};

In edk2, enums are usually defined like this:

typedef enum {
  VmwSvgaRegId = 0,
  VmwSvgaRegEnable = 1,
  ...
} VMW_SVGA_REGISTER;

Upper-case underscore-separated identifiers are used for macros and type
names (typedefs) only; please see 4.3.5 "Type and Macro Names" in the
EDK II C Coding Standards (v2.1 draft).

> +
> +//
> +// Values used with SVGA_REG_ID for sanity-checking the device and getting
> +// its version.
> +//
> +#define SVGA_MAGIC         0x900000UL

The macro names should all start with VMW_ please.

> +#define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))

Please define WMV_SVGA_MAGIC only as 0x900000U, not 0x900000UL.

> +
> +#define SVGA_VERSION_2     2
> +#define SVGA_ID_2          SVGA_MAKE_ID(SVGA_VERSION_2)

Please insert a space between VMW_SVGA_MAKE_ID and the opening parenthesis.

> +
> +#define SVGA_VERSION_1     1
> +#define SVGA_ID_1          SVGA_MAKE_ID(SVGA_VERSION_1)
> +
> +#define SVGA_VERSION_0     0
> +#define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
> +
> +//
> +// One of the capability bits advertised by SVGA_REG_CAPABILITIES.
> +//
> +#define SVGA_CAP_8BIT_EMULATION     0x00000100

I suggest to #include <Base.h> in this header (inside the include
guard), and then defining this macro as BIT8.

> +
> +#endif
> 

With those changes, you can add:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
  2017-04-02 22:44 ` [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
@ 2017-04-04  8:19   ` Laszlo Ersek
  2017-04-05  9:16     ` Phil Dennis-Jordan
  0 siblings, 1 reply; 12+ messages in thread
From: Laszlo Ersek @ 2017-04-04  8:19 UTC (permalink / raw)
  To: Phil Dennis-Jordan, edk2-devel; +Cc: Jordan Justen, Phil Dennis-Jordan

On 04/03/17 00:44, Phil Dennis-Jordan wrote:
> From: Phil Dennis-Jordan <phil@philjordan.eu>
> 
> The VMWare SVGA2 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 Pci.Read/Pci.Write functions do not support
> such unaligned I/O.

Pci.Read and Pci.Write are for accessing config space; I think you mean
Io.Read and Io.Write.

> 
> 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 Read32, for the Ia32 and X64 architectures. Port I/O

s/Read32/IoRead32/ I believe

> 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>

Please add here:

Suggested-by: Jordan Justen <jordan.l.justen@intel.com>

as the idea comes from Jordan (from 4 years ago or so); is that correct?

> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
> ---
> 
> 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.
> 
>  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf         |  6 ++
>  OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h    | 59 ++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c         | 69 +++++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c         | 79 +++++++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c         | 81 ++++++++++++++++++++
>  OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c | 65 ++++++++++++++++
>  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..a069f3b98087
> --- /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.
> +
> +**/

Can you please rewrap all new files added in this commit to 79
characters? (Even comments that you are copying from under MdePkg.)

> +
> +#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 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  I/O port from which to read.
> +
> +  @return The value read from the specified location.
> +
> +**/
> +UINT32
> +UnalignedIoRead32 (
> +  IN      UINTN                     Port
> +  );
> +
> +#endif
> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
> new file mode 100644
> index 000000000000..8bb74c784c06
> --- /dev/null
> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
> @@ -0,0 +1,69 @@
> +/** @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), "Nd"((UINT16)Port) );

Please insert a space after each second quote character:

"a" (Value)

"Nd" ((UINT16)Port)

Also, a question: what does the N character (constraint?) do in the
input operand specification? I tried to check the gcc inline assembly
docs at <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>, and I
couldn't find it. Thanks.

> +  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  I/O port from which to read.
> +
> +  @return The value read from the specified location.
> +
> +**/
> +UINT32
> +UnalignedIoRead32 (
> +  IN      UINTN                     Port
> +  )
> +{
> +  UINT32 Data;
> +  __asm__ __volatile__ ( "inl %1, %0" : "=a"(Data) : "Nd"((UINT16)Port) );
> +  return Data;
> +}
> +

Same comment about inserting spaces.

> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
> new file mode 100644
> index 000000000000..ac365a8b6be5
> --- /dev/null
> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
> @@ -0,0 +1,79 @@
> +/** @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  Port  The I/O port to write.
> +  @param  Value The value to write to the I/O port.
> +
> +  @return The value written 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  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;
> +}

OK, these appear to be verbatim copies from
"MdePkg/Library/BaseIoLibIntrinsic/IoLibIcc.c".

> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
> new file mode 100644
> index 000000000000..2eda40a47e2b
> --- /dev/null
> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
> @@ -0,0 +1,81 @@
> +/** @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 I/O port operations are not supported, then ASSERT().
> +  If Port is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Port  The I/O port to write.
> +  @param  Value The value to write to the I/O port.
> +
> +  @return The value written to the I/O port.
> +
> +**/
> +UINT32
> +EFIAPI

Please drop EFIAPI here. Your internal header file doesn't specify it
(which is fine, as it is not a public library interface), so we
shouldn't add EFIAPI here either (even if it would indeed compile, as
this file is for VS only, and there EFIAPI is the only / default calling
convention).

> +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 I/O port operations are not supported, then ASSERT().
> +  If Port is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Port  The I/O port to read.
> +
> +  @return The value read.
> +
> +**/
> +UINT32
> +EFIAPI
> +UnalignedIoRead32 (
> +  IN      UINTN                     Port
> +  )
> +{
> +  UINT32                            Value;
> +
> +  _ReadWriteBarrier ();
> +  Value = _inpd ((UINT16)Port);
> +  _ReadWriteBarrier ();
> +  return Value;
> +}

Seems OK. (We'll only know for sure if someone builds this on VS :))

> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
> new file mode 100644
> index 000000000000..1d37ecb7bec0
> --- /dev/null
> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
> @@ -0,0 +1,65 @@
> +/** @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 "UnalignedIoInternal.h"
> +#include <Library/DebugLib.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 0;

Well, not really relevant, but I still suggest to return Value, not 0.

> +}
> +
> +/**
> +  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  I/O port from which to read.
> +
> +  @return The value read from the specified location.
> +
> +**/
> +UINT32
> +UnalignedIoRead32 (
> +  IN      UINTN                     Port
> +  )
> +{
> +  ASSERT (FALSE);
> +  return 0;
> +}
> 

With those changes:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Jordan, do you have any comments? (For the whole series too, of course?)

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support.
  2017-04-02 22:44 ` [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support Phil Dennis-Jordan
@ 2017-04-04 10:13   ` Laszlo Ersek
  0 siblings, 0 replies; 12+ messages in thread
From: Laszlo Ersek @ 2017-04-04 10:13 UTC (permalink / raw)
  To: Phil Dennis-Jordan, edk2-devel; +Cc: Jordan Justen, Phil Dennis-Jordan

On 04/03/17 00:44, 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 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 <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.
> 
>  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

I suggest to call this VmwPixelsPerLine.

>  } 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_VMW_SVGA? In the IndustryStandard header file, we just use
VMW_SVGA.

>  } QEMU_VIDEO_VARIANT;
>  
>  typedef struct {
> @@ -119,6 +124,8 @@ typedef struct {
>    QEMU_VIDEO_VARIANT                    Variant;
>    FRAME_BUFFER_CONFIGURE                *FrameBufferBltConfigure;
>    UINTN                                 FrameBufferBltConfigureSize;
> +
> +  UINT16                                VMWareSVGA2_BasePort;

I suggest to drop the empty line, and to call this VmwSvgaBasePort.

>  } QEMU_VIDEO_PRIVATE_DATA;
>  
>  ///
> @@ -502,9 +509,39 @@ QemuVideoBochsModeSetup (
>    BOOLEAN                  IsQxl
>    );
>  
> +EFI_STATUS
> +QemuVideoVmwareModeSetup (
> +  QEMU_VIDEO_PRIVATE_DATA *Private
> +  );

Call this QemuVideoVmwSvgaModeSetup?

> +
>  VOID
>  InstallVbeShim (
>    IN CONST CHAR16         *CardName,
>    IN EFI_PHYSICAL_ADDRESS FrameBufferBase
>    );
> +
> +VOID
> +QemuVideoVMWSVGA2RegisterWrite (
> +  QEMU_VIDEO_PRIVATE_DATA *Private,
> +  UINT16                  reg,
> +  UINT32                  value
> +  );

VmwSvgaWrite?

> +
> +UINT32
> +QemuVideoVMWSVGA2RegisterRead (
> +  QEMU_VIDEO_PRIVATE_DATA *Private,
> +  UINT16                  reg
> +  );

VmwSvgaRead?

> +
> +EFI_STATUS
> +QemuVideoVMWSVGA2CompleteModeData (
> +  IN  QEMU_VIDEO_PRIVATE_DATA           *Private,
> +  OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
> +  );

QemuVideoVmwSvgaCompleteModeData?

> +
> +void InitializeVMWSVGA2GraphicsMode (
> +  QEMU_VIDEO_PRIVATE_DATA  *Private,
> +  QEMU_VIDEO_BOCHS_MODES   *ModeData
> +  );
> +

InitializeVmwSvga2GraphicsMode?

>  #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 <IndustryStandard/VMWareSVGA2.h>

Aha! So we did use "2" in the header file name. Haven't noticed that
until this point. I suggest we stay consistent in all spots, so either
please drop the "2" from the header file name in patch #1 (and the
include guard macro too), or else please use it everywhere.

Also, we should put <> includes before "" includes. (I guess some of the
current code doesn't conform to that, just below...)

>  #include <IndustryStandard/Acpi.h>
>  
>  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

Can you please drop the #if?

>          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;

Please call this IoDesc.

> +    UINT32 TargetId;
> +    UINT32 Svga2IDRead;

Please call this Svga2IdRead.

Also, please aligh these two variable names with IoDesc horizontally.

> +
> +    Private->PciIo->GetBarAttributes (
> +                      Private->PciIo,
> +                      PCI_BAR_IDX0,
> +                      NULL,
> +                      (VOID**) &iodesc
> +                      );

Please check the return status of this protocol member call.

If
- the call fails, or
- IoDesc->ResType differs from ACPI_ADDRESS_SPACE_TYPE_IO, or
- IoDesc->AddrRangeMin is larger than or equal to MAX_UINT16,
then set Status to EFI_DEVICE_ERROR, and jump to RestoreAttributes.

> +    Private->VMWareSVGA2_BasePort = iodesc->AddrRangeMin;

I think you should do an explicit cast here, to UINT16; the AddrRangeMin
field has type UINT64, and VS will whine if you don't cast the RHS of
the assignment explicitly.

> +
> +    TargetId = SVGA_ID_2;
> +    while (1) {

Please use "while (TRUE)" or "for (;;)".

"while (1)" is not unused in edk2, but the two other forms are more
idiomatic.

> +      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 (

Can you please move this function higher up, so that it follows
InitializeBochsGraphicsMode() directly?


Also, it should start like:

VOID
InitializeVMWSVGA2GraphicsMode (
  ...

Please update the function declaration in "Qemu.h" as well.

> +  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
> +                          );

Please
- call this variable Capabilities,
- move its definition to the top of the containing scope,
- use a separate assignment -- initialization of automatic storage
duration variables ("locals") is forbidden in edk2, even if the
initializer were a constant.

> +  if ((capabilities & SVGA_CAP_8BIT_EMULATION) != 0) {
> +    QemuVideoVMWSVGA2RegisterWrite(
> +      Private,
> +      SVGA_REG_BITS_PER_PIXEL,
> +      ModeData->ColorDepth
> +      );
> +  }
> +  SetDefaultPalette (Private);
> +  ClearScreen (Private);
> +}

I don't understand how ClearScreen() can work here. ClearScreen() writes
MMIO BAR 0. But, on this video card, BAR 0 is expected to be an IO BAR,
which contains the register selector and register value ports.

> 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 <IndustryStandard/VMWareSVGA2.h>

<> should go before ""

>  
>  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);

I don't think this belongs here. Can you put it in
InitializeVMWSVGA2GraphicsMode() instead?

> +
> +  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);

I have no idea what this does. Please add a comment that explains it in
detail.

> +  Info->PixelsPerScanLine = BytesPerLine / (BitsPerPixel / 8);
> +
> +  Private->PciIo->GetBarAttributes (
> +                        Private->PciIo,
> +                        PCI_BAR_IDX1,
> +                        NULL,
> +                        (VOID**) &FrameBufDesc
> +                        );

So, indeed the video memory is in BAR1. ClearScreen() doesn't match
that. You might want to introduce another field in
QEMU_VIDEO_PRIVATE_DATA, to carry the BAR number that corresponds to the
video memory.

> +
> +  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;
>  }

This doesn't seem right. QemuVideoCompleteModeInfo() is called on two paths:

  QemuVideoGraphicsOutputSetMode()
    //
    // for non-vmware
    //
    QemuVideoCompleteModeData()
      QemuVideoCompleteModeInfo()

and

  QemuVideoGraphicsOutputQueryMode()
    QemuVideoCompleteModeInfo()

The first call path is for the mode being *selected*, the second call
path is for querying *any* mode.

Now, on the first call path, you found QemuVideoCompleteModeInfo()
inappropriate for vmw, because you introduced the following in its place:

  QemuVideoGraphicsOutputSetMode()
    //
    // for vmw
    //
    QemuVMSVGA2VideoCompleteModeData()
      //
      // manual setting of pixel mask
      // no call to QemuVideoCompleteModeInfo()
      //

But in that case, I don't see how calling QemuVideoCompleteModeInfo() in
QemuVideoGraphicsOutputQueryMode() -- that is, on the second path --,
and only overriding PixelsPerScanLine, could be correct for vmw. The
pixel mask values filled in by QemuVideoCompleteModeInfo() will be
incorrect.

The mode information should be populated uniformly on both code paths,
regardless of whether we are selecting a mode for actual use (==
changing hardware state), or we are just querying some random mode (==
not changing hardware state).

Are you saying that the pixel mask values cannot be fetched & returned
without actually selecting those graphics modes?

In that case, I think you should pre-compute the pixel mask values in
QemuVideoVmwareModeSetup(), where you already iterate through all the
modes. (I.e., similarly to PixelsPerLine.)

Then both the pixel format setting and the PixelsPerScanLine setting,
for vmw, should be extracted to a function similar to
QemuVideoCompleteModeInfo(). That new function should be called on both
paths above; that is, from QemuVMSVGA2VideoCompleteModeData(), and also
from QemuVideoGraphicsOutputQueryMode(). This new function should
populate Info from the precomputed, cached values, including all the
pixel format fields and the PixelsPerScanLine field.

(Even with PixelsPerScanLine you have an inconsistency now: although in
QueryMode, you use the PixelsPerLine value precomputed in
QemuVideoVmwareModeSetup(), in QemuVMSVGA2VideoCompleteModeData(), you
still read the SVGA_REG_BYTES_PER_LINE register directly again. I think
that shouldn't be necessary.)

>  
> @@ -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 <IndustryStandard/VMWareSVGA2.h>

<> includes should go before "" includes.

>  
>  
>  ///
> @@ -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);
> +}

Please call "reg" and "value" Register and Value. (Don't forget to
update "Qemu.h" too.)

Also, I think these two functions should be moved to "Driver.c", just
under BochsWrite() / BochsRead().

> +
> +EFI_STATUS
> +QemuVideoVmwareModeSetup (
> +  QEMU_VIDEO_PRIVATE_DATA *Private
> +  )
> +{
> +  UINT32                 FBSize;

Please call this 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(

Missing space right after "QemuVideoVMWSVGA2RegisterRead".

> +                         Private,
> +                         SVGA_REG_HOST_BITS_PER_PIXEL
> +                         );
> +    QemuVideoVMWSVGA2RegisterWrite (
> +      Private,
> +      SVGA_REG_BITS_PER_PIXEL,
> +      HostBitsPerPixel
> +      );
> +  } else {
> +    HostBitsPerPixel = QemuVideoVMWSVGA2RegisterRead(

Missing space right after "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)
> +    {

This should be:

  if (Expression1 &&
      Expression2 &&
      Expression3) {
    //
    // dependent code
    //
  }


> +      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;
> +}
> 

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions
  2017-04-03 23:17   ` Jordan Justen
@ 2017-04-04 10:40     ` Laszlo Ersek
  0 siblings, 0 replies; 12+ messages in thread
From: Laszlo Ersek @ 2017-04-04 10:40 UTC (permalink / raw)
  To: Jordan Justen, Phil Dennis-Jordan, edk2-devel; +Cc: Phil Dennis-Jordan

On 04/04/17 01:17, Jordan Justen wrote:
> On 2017-04-02 15:44:55, Phil Dennis-Jordan wrote:
>> From: Phil Dennis-Jordan <phil@philjordan.eu>
>>
>> This adds a header file defining symbolic constants for the VMWare SVGA2
>> virtual display device in preparation for supporting it in QemuVideoDXE.
>>
>> It is 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.
>>
>> 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>
>> ---
>>
>> Notes:
>>     v2:
>>     - New, custom header file instead of importing VMWare's verbatim. [Laszlo]
>>
>>  OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h | 102 ++++++++++++++++++++
>>  1 file changed, 102 insertions(+)
>>
>> diff --git a/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
> 
> I think EDK II's file naming convention would prefer VmwareSvga2.h, or
> possibly VmWareSvga2.h. (But, the former looks better to me.)
> 
> Since it covers svga and svga2, should we just drop the '2' from the
> filename?

Yeah, I suggested sort of the same things, after you -- I reviewed the
patches without reading your (earlier) feedback. I suggested VMW_ and
Vmw as prefixes, but I'm equally fine with the more verbose VMWARE_ and
Vmware.

I also agree with dropping "2" from file names / identifiers / macros
etc. (Or, at least, we should be consistent about the use of "2".)


> 
>> new file mode 100644
>> index 000000000000..9db553155957
>> --- /dev/null
>> +++ b/OvmfPkg/Include/IndustryStandard/VMWareSVGA2.h
>> @@ -0,0 +1,102 @@
>> +/** @file
>> +
>> +  Macro and enum definitions of a subset of port numbers, register identifiers
>> +  and values required for driving the VMWare SVGA2 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_SVGA2_H_
>> +#define _VMWARE_SVGA2_H_
>> +
>> +//
>> +// IDs for recognising the device
>> +//
>> +#define PCI_VENDOR_ID_VMWARE            0x15AD
>> +#define 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 SVGA_INDEX_PORT         0x0
>> +#define SVGA_VALUE_PORT         0x1
> 
> Thanks for taking Laszlo's advice about pulling out the minimal
> definitions and EDK II-ifying it. (I think he may be right about the
> Xen contribution.)
> 
> One request I have is, how about prefixing all the SVGA items as
> VMWARE_SVGA? SVGA seems to generic of a term here.

+1 (as commented elsewhere)

Thanks!
Laszlo

> 
> Thanks,
> 
> -Jordan
> 
>> +
>> +//
>> +// Some of the device's register indices for basic framebuffer functionality.
>> +//
>> +enum {
>> +  SVGA_REG_ID = 0,
>> +  SVGA_REG_ENABLE = 1,
>> +  SVGA_REG_WIDTH = 2,
>> +  SVGA_REG_HEIGHT = 3,
>> +  SVGA_REG_MAX_WIDTH = 4,
>> +  SVGA_REG_MAX_HEIGHT = 5,
>> +
>> +  SVGA_REG_BITS_PER_PIXEL = 7,
>> +
>> +  SVGA_REG_RED_MASK = 9,
>> +  SVGA_REG_GREEN_MASK = 10,
>> +  SVGA_REG_BLUE_MASK = 11,
>> +  SVGA_REG_BYTES_PER_LINE = 12,
>> +
>> +  SVGA_REG_FB_OFFSET = 14,
>> +
>> +  SVGA_REG_FB_SIZE = 16,
>> +  SVGA_REG_CAPABILITIES = 17,
>> +
>> +  SVGA_REG_HOST_BITS_PER_PIXEL = 28,
>> +};
>> +
>> +//
>> +// Values used with SVGA_REG_ID for sanity-checking the device and getting
>> +// its version.
>> +//
>> +#define SVGA_MAGIC         0x900000UL
>> +#define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))
>> +
>> +#define SVGA_VERSION_2     2
>> +#define SVGA_ID_2          SVGA_MAKE_ID(SVGA_VERSION_2)
>> +
>> +#define SVGA_VERSION_1     1
>> +#define SVGA_ID_1          SVGA_MAKE_ID(SVGA_VERSION_1)
>> +
>> +#define SVGA_VERSION_0     0
>> +#define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
>> +
>> +//
>> +// One of the capability bits advertised by SVGA_REG_CAPABILITIES.
>> +//
>> +#define SVGA_CAP_8BIT_EMULATION     0x00000100
>> +
>> +#endif
>> -- 
>> 2.3.2 (Apple Git-55)
>>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
  2017-04-04  8:19   ` Laszlo Ersek
@ 2017-04-05  9:16     ` Phil Dennis-Jordan
  2017-04-05  9:37       ` Laszlo Ersek
  0 siblings, 1 reply; 12+ messages in thread
From: Phil Dennis-Jordan @ 2017-04-05  9:16 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel-01, Jordan Justen, Phil Dennis-Jordan

On Tue, Apr 4, 2017 at 8:19 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> On 04/03/17 00:44, Phil Dennis-Jordan wrote:
>> From: Phil Dennis-Jordan <phil@philjordan.eu>
>>
>> The VMWare SVGA2 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 Pci.Read/Pci.Write functions do not support
>> such unaligned I/O.
>
> Pci.Read and Pci.Write are for accessing config space; I think you mean
> Io.Read and Io.Write.
>
>>
>> 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 Read32, for the Ia32 and X64 architectures. Port I/O
>
> s/Read32/IoRead32/ I believe
>
>> 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>
>
> Please add here:
>
> Suggested-by: Jordan Justen <jordan.l.justen@intel.com>
>
> as the idea comes from Jordan (from 4 years ago or so); is that correct?
>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
>> ---
>>
>> 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.
>>
>>  OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf         |  6 ++
>>  OvmfPkg/QemuVideoDxe/UnalignedIoInternal.h    | 59 ++++++++++++++
>>  OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c         | 69 +++++++++++++++++
>>  OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c         | 79 +++++++++++++++++++
>>  OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c         | 81 ++++++++++++++++++++
>>  OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c | 65 ++++++++++++++++
>>  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..a069f3b98087
>> --- /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.
>> +
>> +**/
>
> Can you please rewrap all new files added in this commit to 79
> characters? (Even comments that you are copying from under MdePkg.)
>
>> +
>> +#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 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  I/O port from which to read.
>> +
>> +  @return The value read from the specified location.
>> +
>> +**/
>> +UINT32
>> +UnalignedIoRead32 (
>> +  IN      UINTN                     Port
>> +  );
>> +
>> +#endif
>> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
>> new file mode 100644
>> index 000000000000..8bb74c784c06
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoGcc.c
>> @@ -0,0 +1,69 @@
>> +/** @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), "Nd"((UINT16)Port) );
>
> Please insert a space after each second quote character:
>
> "a" (Value)
>
> "Nd" ((UINT16)Port)
>
> Also, a question: what does the N character (constraint?) do in the
> input operand specification? I tried to check the gcc inline assembly
> docs at <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>, and I
> couldn't find it. Thanks.

The N constraint is x86-specific and indicates an 8-bit unsigned
immediate value can be used as the operand. This enables emitting the
OUT  imm8, EAX
instruction variant, see
https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
In practice, this is most likely not going to happen here, even if
link time optimisation happens to inline the call, as the port number
isn't hardcoded. I can remove it if you like.

>> +  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  I/O port from which to read.
>> +
>> +  @return The value read from the specified location.
>> +
>> +**/
>> +UINT32
>> +UnalignedIoRead32 (
>> +  IN      UINTN                     Port
>> +  )
>> +{
>> +  UINT32 Data;
>> +  __asm__ __volatile__ ( "inl %1, %0" : "=a"(Data) : "Nd"((UINT16)Port) );
>> +  return Data;
>> +}
>> +
>
> Same comment about inserting spaces.
>
>> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
>> new file mode 100644
>> index 000000000000..ac365a8b6be5
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoIcc.c
>> @@ -0,0 +1,79 @@
>> +/** @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  Port  The I/O port to write.
>> +  @param  Value The value to write to the I/O port.
>> +
>> +  @return The value written 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  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;
>> +}
>
> OK, these appear to be verbatim copies from
> "MdePkg/Library/BaseIoLibIntrinsic/IoLibIcc.c".
>
>> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
>> new file mode 100644
>> index 000000000000..2eda40a47e2b
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoMsc.c
>> @@ -0,0 +1,81 @@
>> +/** @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 I/O port operations are not supported, then ASSERT().
>> +  If Port is not aligned on a 32-bit boundary, then ASSERT().
>> +
>> +  @param  Port  The I/O port to write.
>> +  @param  Value The value to write to the I/O port.
>> +
>> +  @return The value written to the I/O port.
>> +
>> +**/
>> +UINT32
>> +EFIAPI
>
> Please drop EFIAPI here. Your internal header file doesn't specify it
> (which is fine, as it is not a public library interface), so we
> shouldn't add EFIAPI here either (even if it would indeed compile, as
> this file is for VS only, and there EFIAPI is the only / default calling
> convention).
>
>> +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 I/O port operations are not supported, then ASSERT().
>> +  If Port is not aligned on a 32-bit boundary, then ASSERT().
>> +
>> +  @param  Port  The I/O port to read.
>> +
>> +  @return The value read.
>> +
>> +**/
>> +UINT32
>> +EFIAPI
>> +UnalignedIoRead32 (
>> +  IN      UINTN                     Port
>> +  )
>> +{
>> +  UINT32                            Value;
>> +
>> +  _ReadWriteBarrier ();
>> +  Value = _inpd ((UINT16)Port);
>> +  _ReadWriteBarrier ();
>> +  return Value;
>> +}
>
> Seems OK. (We'll only know for sure if someone builds this on VS :))
>
>> diff --git a/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
>> new file mode 100644
>> index 000000000000..1d37ecb7bec0
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/UnalignedIoUnsupported.c
>> @@ -0,0 +1,65 @@
>> +/** @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 "UnalignedIoInternal.h"
>> +#include <Library/DebugLib.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 0;
>
> Well, not really relevant, but I still suggest to return Value, not 0.
>
>> +}
>> +
>> +/**
>> +  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  I/O port from which to read.
>> +
>> +  @return The value read from the specified location.
>> +
>> +**/
>> +UINT32
>> +UnalignedIoRead32 (
>> +  IN      UINTN                     Port
>> +  )
>> +{
>> +  ASSERT (FALSE);
>> +  return 0;
>> +}
>>
>
> With those changes:
>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks for the detailed review Laszlo, I've gone through and
implemented all of your suggestions and requests and will be posting a
new version of the patch series shortly.

Phil


> Jordan, do you have any comments? (For the whole series too, of course?)
>
> Thanks
> Laszlo


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O.
  2017-04-05  9:16     ` Phil Dennis-Jordan
@ 2017-04-05  9:37       ` Laszlo Ersek
  0 siblings, 0 replies; 12+ messages in thread
From: Laszlo Ersek @ 2017-04-05  9:37 UTC (permalink / raw)
  To: Phil Dennis-Jordan; +Cc: edk2-devel-01, Jordan Justen, Phil Dennis-Jordan

On 04/05/17 11:16, Phil Dennis-Jordan wrote:
> On Tue, Apr 4, 2017 at 8:19 PM, Laszlo Ersek <lersek@redhat.com> wrote:
>> On 04/03/17 00:44, Phil Dennis-Jordan wrote:

>>> +/**
>>> +  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), "Nd"((UINT16)Port) );
>>
>> Please insert a space after each second quote character:
>>
>> "a" (Value)
>>
>> "Nd" ((UINT16)Port)
>>
>> Also, a question: what does the N character (constraint?) do in the
>> input operand specification? I tried to check the gcc inline assembly
>> docs at <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>, and I
>> couldn't find it. Thanks.
> 
> The N constraint is x86-specific and indicates an 8-bit unsigned
> immediate value can be used as the operand. This enables emitting the
> OUT  imm8, EAX
> instruction variant, see
> https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
> In practice, this is most likely not going to happen here, even if
> link time optimisation happens to inline the call, as the port number
> isn't hardcoded. I can remove it if you like.

Either a comment or removal would be fine, I think.

I feel slightly more attracted to removal because the "N" diverges from
IoWrite32() in "MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c", and that
difference seems to deserve justification.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-04-05  9:37 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-02 22:44 [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan
2017-04-02 22:44 ` [PATCH v2 1/3] OvmfPkg: VMWare SVGA2 display device register definitions Phil Dennis-Jordan
2017-04-03 23:17   ` Jordan Justen
2017-04-04 10:40     ` Laszlo Ersek
2017-04-04  7:54   ` Laszlo Ersek
2017-04-02 22:44 ` [PATCH v2 2/3] OvmfPkg/QemuVideoDxe: Helper functions for unaligned port I/O Phil Dennis-Jordan
2017-04-04  8:19   ` Laszlo Ersek
2017-04-05  9:16     ` Phil Dennis-Jordan
2017-04-05  9:37       ` Laszlo Ersek
2017-04-02 22:44 ` [PATCH v2 3/3] OvmfPkg/QemuVideoDxe: VMWare SVGA II device support Phil Dennis-Jordan
2017-04-04 10:13   ` Laszlo Ersek
2017-04-02 22:48 ` [PATCH v2 0/3] OvmfPkg/QemuVideoDxe: Add VMWare SVGA2 framebuffer support Phil Dennis-Jordan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox