]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/RiscVVirt: Add PciCpuIo2Dxe module
authorSunil V L <sunilvl@ventanamicro.com>
Sat, 28 Jan 2023 15:31:04 +0000 (21:01 +0530)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 16 Feb 2023 05:53:28 +0000 (05:53 +0000)
Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL
to add the translation for IO access. This is copied from
ArmPciCpuIo2Dxe driver.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
Acked-by: Abner Chang <abner.chang@amd.com>
Reviewed-by: Andrei Warkentin <andrei.warkentin@intel.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c [new file with mode: 0644]
OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf [new file with mode: 0644]

diff --git a/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c
new file mode 100644 (file)
index 0000000..f3bf07e
--- /dev/null
@@ -0,0 +1,557 @@
+/** @file\r
+  Produces the CPU I/O 2 Protocol.\r
+\r
+Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
+Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/CpuIo2.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#define MAX_IO_PORT_ADDRESS  0xFFFF\r
+\r
+//\r
+// Handle for the CPU I/O 2 Protocol\r
+//\r
+STATIC EFI_HANDLE  mHandle = NULL;\r
+\r
+//\r
+// Lookup table for increment values based on transfer widths\r
+//\r
+STATIC CONST UINT8  mInStride[] = {\r
+  1, // EfiCpuIoWidthUint8\r
+  2, // EfiCpuIoWidthUint16\r
+  4, // EfiCpuIoWidthUint32\r
+  8, // EfiCpuIoWidthUint64\r
+  0, // EfiCpuIoWidthFifoUint8\r
+  0, // EfiCpuIoWidthFifoUint16\r
+  0, // EfiCpuIoWidthFifoUint32\r
+  0, // EfiCpuIoWidthFifoUint64\r
+  1, // EfiCpuIoWidthFillUint8\r
+  2, // EfiCpuIoWidthFillUint16\r
+  4, // EfiCpuIoWidthFillUint32\r
+  8  // EfiCpuIoWidthFillUint64\r
+};\r
+\r
+//\r
+// Lookup table for increment values based on transfer widths\r
+//\r
+STATIC CONST UINT8  mOutStride[] = {\r
+  1, // EfiCpuIoWidthUint8\r
+  2, // EfiCpuIoWidthUint16\r
+  4, // EfiCpuIoWidthUint32\r
+  8, // EfiCpuIoWidthUint64\r
+  1, // EfiCpuIoWidthFifoUint8\r
+  2, // EfiCpuIoWidthFifoUint16\r
+  4, // EfiCpuIoWidthFifoUint32\r
+  8, // EfiCpuIoWidthFifoUint64\r
+  0, // EfiCpuIoWidthFillUint8\r
+  0, // EfiCpuIoWidthFillUint16\r
+  0, // EfiCpuIoWidthFillUint32\r
+  0  // EfiCpuIoWidthFillUint64\r
+};\r
+\r
+/**\r
+  Check parameters to a CPU I/O 2 Protocol service request.\r
+\r
+  The I/O operations are carried out exactly as requested. The caller is responsible\r
+  for satisfying any alignment and I/O width restrictions that a PI System on a\r
+  platform might require. For example on some platforms, width requests of\r
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will\r
+  be handled by the driver.\r
+\r
+  @param[in] MmioOperation  TRUE for an MMIO operation, FALSE for I/O Port operation.\r
+  @param[in] Width          Signifies the width of the I/O or Memory operation.\r
+  @param[in] Address        The base address of the I/O operation.\r
+  @param[in] Count          The number of I/O operations to perform. The number of\r
+                            bytes moved is Width size * Count, starting at Address.\r
+  @param[in] Buffer         For read operations, the destination buffer to store the results.\r
+                            For write operations, the source buffer from which to write data.\r
+\r
+  @retval EFI_SUCCESS            The parameters for this request pass the checks.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
+                                 and Count is not valid for this PI system.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+CpuIoCheckParameter (\r
+  IN BOOLEAN                    MmioOperation,\r
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,\r
+  IN UINT64                     Address,\r
+  IN UINTN                      Count,\r
+  IN VOID                       *Buffer\r
+  )\r
+{\r
+  UINT64  MaxCount;\r
+  UINT64  Limit;\r
+\r
+  //\r
+  // Check to see if Buffer is NULL\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check to see if Width is in the valid range\r
+  //\r
+  if ((UINT32)Width >= EfiCpuIoWidthMaximum) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // For FIFO type, the target address won't increase during the access,\r
+  // so treat Count as 1\r
+  //\r
+  if ((Width >= EfiCpuIoWidthFifoUint8) && (Width <= EfiCpuIoWidthFifoUint64)) {\r
+    Count = 1;\r
+  }\r
+\r
+  //\r
+  // Check to see if Width is in the valid range for I/O Port operations\r
+  //\r
+  Width = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);\r
+  if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check to see if Address is aligned\r
+  //\r
+  if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Check to see if any address associated with this transfer exceeds the maximum\r
+  // allowed address.  The maximum address implied by the parameters passed in is\r
+  // Address + Size * Count.  If the following condition is met, then the transfer\r
+  // is not supported.\r
+  //\r
+  //    Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1\r
+  //\r
+  // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count\r
+  // can also be the maximum integer value supported by the CPU, this range\r
+  // check must be adjusted to avoid all overflow conditions.\r
+  //\r
+  // The following form of the range check is equivalent but assumes that\r
+  // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).\r
+  //\r
+  Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);\r
+  if (Count == 0) {\r
+    if (Address > Limit) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    MaxCount = RShiftU64 (Limit, Width);\r
+    if (MaxCount < (Count - 1)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check to see if Buffer is aligned\r
+  //\r
+  if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads memory-mapped registers.\r
+\r
+  The I/O operations are carried out exactly as requested. The caller is responsible\r
+  for satisfying any alignment and I/O width restrictions that a PI System on a\r
+  platform might require. For example on some platforms, width requests of\r
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will\r
+  be handled by the driver.\r
+\r
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,\r
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for\r
+  each of the Count operations that is performed.\r
+\r
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,\r
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times on the same Address.\r
+\r
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,\r
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times from the first element of Buffer.\r
+\r
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.\r
+  @param[in]  Address  The base address of the I/O operation.\r
+  @param[in]  Count    The number of I/O operations to perform. The number of\r
+                       bytes moved is Width size * Count, starting at Address.\r
+  @param[out] Buffer   For read operations, the destination buffer to store the results.\r
+                       For write operations, the source buffer from which to write data.\r
+\r
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
+                                 and Count is not valid for this PI system.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceRead (\r
+  IN  EFI_CPU_IO2_PROTOCOL       *This,\r
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,\r
+  IN  UINT64                     Address,\r
+  IN  UINTN                      Count,\r
+  OUT VOID                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      InStride;\r
+  UINT8                      OutStride;\r
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;\r
+  UINT8                      *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride       = mInStride[Width];\r
+  OutStride      = mOutStride[Width];\r
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiCpuIoWidthUint8) {\r
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {\r
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {\r
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {\r
+      *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Writes memory-mapped registers.\r
+\r
+  The I/O operations are carried out exactly as requested. The caller is responsible\r
+  for satisfying any alignment and I/O width restrictions that a PI System on a\r
+  platform might require. For example on some platforms, width requests of\r
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will\r
+  be handled by the driver.\r
+\r
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,\r
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for\r
+  each of the Count operations that is performed.\r
+\r
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,\r
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times on the same Address.\r
+\r
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,\r
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times from the first element of Buffer.\r
+\r
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.\r
+  @param[in]  Address  The base address of the I/O operation.\r
+  @param[in]  Count    The number of I/O operations to perform. The number of\r
+                       bytes moved is Width size * Count, starting at Address.\r
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.\r
+                       For write operations, the source buffer from which to write data.\r
+\r
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
+                                 and Count is not valid for this PI system.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceWrite (\r
+  IN EFI_CPU_IO2_PROTOCOL       *This,\r
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,\r
+  IN UINT64                     Address,\r
+  IN UINTN                      Count,\r
+  IN VOID                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      InStride;\r
+  UINT8                      OutStride;\r
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;\r
+  UINT8                      *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride       = mInStride[Width];\r
+  OutStride      = mOutStride[Width];\r
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiCpuIoWidthUint8) {\r
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {\r
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {\r
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {\r
+      MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads I/O registers.\r
+\r
+  The I/O operations are carried out exactly as requested. The caller is responsible\r
+  for satisfying any alignment and I/O width restrictions that a PI System on a\r
+  platform might require. For example on some platforms, width requests of\r
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will\r
+  be handled by the driver.\r
+\r
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,\r
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for\r
+  each of the Count operations that is performed.\r
+\r
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,\r
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times on the same Address.\r
+\r
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,\r
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times from the first element of Buffer.\r
+\r
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.\r
+  @param[in]  Address  The base address of the I/O operation.\r
+  @param[in]  Count    The number of I/O operations to perform. The number of\r
+                       bytes moved is Width size * Count, starting at Address.\r
+  @param[out] Buffer   For read operations, the destination buffer to store the results.\r
+                       For write operations, the source buffer from which to write data.\r
+\r
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
+                                 and Count is not valid for this PI system.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceRead (\r
+  IN  EFI_CPU_IO2_PROTOCOL       *This,\r
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,\r
+  IN  UINT64                     Address,\r
+  IN  UINTN                      Count,\r
+  OUT VOID                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      InStride;\r
+  UINT8                      OutStride;\r
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;\r
+  UINT8                      *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Address += PcdGet64 (PcdPciIoTranslation);\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride       = mInStride[Width];\r
+  OutStride      = mOutStride[Width];\r
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);\r
+\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiCpuIoWidthUint8) {\r
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {\r
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {\r
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write I/O registers.\r
+\r
+  The I/O operations are carried out exactly as requested. The caller is responsible\r
+  for satisfying any alignment and I/O width restrictions that a PI System on a\r
+  platform might require. For example on some platforms, width requests of\r
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will\r
+  be handled by the driver.\r
+\r
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,\r
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for\r
+  each of the Count operations that is performed.\r
+\r
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,\r
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times on the same Address.\r
+\r
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,\r
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is\r
+  incremented for each of the Count operations that is performed. The read or\r
+  write operation is performed Count times from the first element of Buffer.\r
+\r
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.\r
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.\r
+  @param[in]  Address  The base address of the I/O operation.\r
+  @param[in]  Count    The number of I/O operations to perform. The number of\r
+                       bytes moved is Width size * Count, starting at Address.\r
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.\r
+                       For write operations, the source buffer from which to write data.\r
+\r
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
+                                 and Count is not valid for this PI system.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceWrite (\r
+  IN EFI_CPU_IO2_PROTOCOL       *This,\r
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,\r
+  IN UINT64                     Address,\r
+  IN UINTN                      Count,\r
+  IN VOID                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      InStride;\r
+  UINT8                      OutStride;\r
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;\r
+  UINT8                      *Uint8Buffer;\r
+\r
+  //\r
+  // Make sure the parameters are valid\r
+  //\r
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Address += PcdGet64 (PcdPciIoTranslation);\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride       = mInStride[Width];\r
+  OutStride      = mOutStride[Width];\r
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);\r
+\r
+  for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiCpuIoWidthUint8) {\r
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);\r
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {\r
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {\r
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// CPU I/O 2 Protocol instance\r
+//\r
+STATIC EFI_CPU_IO2_PROTOCOL  mCpuIo2 = {\r
+  {\r
+    CpuMemoryServiceRead,\r
+    CpuMemoryServiceWrite\r
+  },\r
+  {\r
+    CpuIoServiceRead,\r
+    CpuIoServiceWrite\r
+  }\r
+};\r
+\r
+/**\r
+  The user Entry Point for module CpuIo2Dxe. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciCpuIo2Initialize (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mHandle,\r
+                  &gEfiCpuIo2ProtocolGuid,\r
+                  &mCpuIo2,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
new file mode 100644 (file)
index 0000000..4f78cfa
--- /dev/null
@@ -0,0 +1,48 @@
+## @file\r
+#  Produces the CPU I/O 2 Protocol by using the services of the I/O Library.\r
+#\r
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
+# Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x0001001B\r
+  BASE_NAME                      = PciCpuIo2Dxe\r
+  FILE_GUID                      = 9BD3C765-2579-4CF0-9349-D77205565030\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PciCpuIo2Initialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = RISCV64\r
+#\r
+\r
+[Sources]\r
+  PciCpuIo2Dxe.c\r
+\r
+[Packages]\r
+  OvmfPkg/OvmfPkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  BaseLib\r
+  DebugLib\r
+  IoLib\r
+  PcdLib\r
+  UefiBootServicesTableLib\r
+\r
+[Pcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation\r
+\r
+[Protocols]\r
+  gEfiCpuIo2ProtocolGuid                         ## PRODUCES\r
+\r
+[Depex]\r
+  TRUE\r