From ceb82e7d081399dd91cc6e0e8eabd5b7260afac0 Mon Sep 17 00:00:00 2001
From: Adttil <2429917001@qq.com>
Date: Fri, 29 Nov 2024 08:35:27 +0800
Subject: [PATCH 1/3] VirtioDxe: add support of MMIO Bar for virtio devices

As some virtio devices support MMIO BAR, add support for
it in Virtio10Dxe and VirtioPciDeviceDXE.

Signed-off-by: jiangdongxu <jiangdongxu1@huawei.com>
---
 OvmfPkg/Include/Protocol/VirtioDevice.h       | 12 +++
 .../VirtioMmioDeviceLib/VirtioMmioDevice.c    |  1 +
 OvmfPkg/Virtio10Dxe/Virtio10.c                |  1 +
 OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c  | 89 +++++++++++++++----
 4 files changed, 85 insertions(+), 18 deletions(-)

diff --git a/OvmfPkg/Include/Protocol/VirtioDevice.h b/OvmfPkg/Include/Protocol/VirtioDevice.h
index ad37f4e3..802b8970 100644
--- a/OvmfPkg/Include/Protocol/VirtioDevice.h
+++ b/OvmfPkg/Include/Protocol/VirtioDevice.h
@@ -466,6 +466,16 @@ EFI_STATUS
   IN  VOID                      *Mapping
   );
 
+/**
+ * Note: Zero virtio devices has BAR0 of type MMIO but not PIO which do not
+ * flow the virtio 0.95 spec due to hw limiation. We extend edk2 to support
+ * such variant.
+ */
+typedef enum {
+  VirtioCfgSpaceAcessIo = 0,
+  VirtioCfgSpaceAcessMem
+} VIRTIO_CFG_SPACE_ACCESS_MODE;
+
 ///
 ///  This protocol provides an abstraction over the VirtIo transport layer
 ///
@@ -482,6 +492,8 @@ struct _VIRTIO_DEVICE_PROTOCOL {
   //
   INT32                         SubSystemDeviceId;
 
+  VIRTIO_CFG_SPACE_ACCESS_MODE  CfgAccessMode;
+
   VIRTIO_GET_DEVICE_FEATURES    GetDeviceFeatures;
   VIRTIO_SET_GUEST_FEATURES     SetGuestFeatures;
 
diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
index fac32422..a340711d 100644
--- a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
+++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c
@@ -17,6 +17,7 @@
 STATIC CONST VIRTIO_DEVICE_PROTOCOL  mMmioDeviceProtocolTemplate = {
   0,                                       // Revision
   0,                                       // SubSystemDeviceId
+  0,                                       // CfgAccessMode
   VirtioMmioGetDeviceFeatures,             // GetDeviceFeatures
   VirtioMmioSetGuestFeatures,              // SetGuestFeatures
   VirtioMmioSetQueueAddress,               // SetQueueAddress
diff --git a/OvmfPkg/Virtio10Dxe/Virtio10.c b/OvmfPkg/Virtio10Dxe/Virtio10.c
index 970524f6..b968b016 100644
--- a/OvmfPkg/Virtio10Dxe/Virtio10.c
+++ b/OvmfPkg/Virtio10Dxe/Virtio10.c
@@ -954,6 +954,7 @@ Virtio10UnmapSharedBuffer (
 STATIC CONST VIRTIO_DEVICE_PROTOCOL  mVirtIoTemplate = {
   VIRTIO_SPEC_REVISION (1,     0, 0),
   0,                           // SubSystemDeviceId, filled in dynamically
+  0,                           // CfgAccessMode
   Virtio10GetDeviceFeatures,
   Virtio10SetGuestFeatures,
   Virtio10SetQueueAddress,
diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
index b4ac195b..61ff376d 100644
--- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
+++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c
@@ -23,6 +23,7 @@
 STATIC VIRTIO_DEVICE_PROTOCOL  mDeviceProtocolTemplate = {
   0,                                    // Revision
   0,                                    // SubSystemDeviceId
+  0,                                    // CfgAccessMode
   VirtioPciGetDeviceFeatures,           // GetDeviceFeatures
   VirtioPciSetGuestFeatures,            // SetGuestFeatures
   VirtioPciSetQueueAddress,             // SetQueueAddress
@@ -117,14 +118,25 @@ VirtioPciIoRead (
       return EFI_INVALID_PARAMETER;
   }
 
-  return PciIo->Io.Read (
-                     PciIo,
-                     Width,
-                     PCI_BAR_IDX0,
-                     FieldOffset,
-                     Count,
-                     Buffer
-                     );
+  if (Dev->VirtioDevice.CfgAccessMode == VirtioCfgSpaceAcessIo) {
+    return PciIo->Io.Read (
+                       PciIo,
+                       Width,
+                       PCI_BAR_IDX0,
+                       FieldOffset,
+                       Count,
+                       Buffer
+                       );
+  } else {
+    return PciIo->Mem.Read (
+                       PciIo,
+                       Width,
+                       PCI_BAR_IDX0,
+                       FieldOffset,
+                       Count,
+                       Buffer
+                       );
+  }
 }
 
 /**
@@ -197,14 +209,25 @@ VirtioPciIoWrite (
       return EFI_INVALID_PARAMETER;
   }
 
-  return PciIo->Io.Write (
-                     PciIo,
-                     Width,
-                     PCI_BAR_IDX0,
-                     FieldOffset,
-                     Count,
-                     &Value
-                     );
+  if (Dev->VirtioDevice.CfgAccessMode == VirtioCfgSpaceAcessIo) {
+    return PciIo->Io.Write (
+                       PciIo,
+                       Width,
+                       PCI_BAR_IDX0,
+                       FieldOffset,
+                       Count,
+                       &Value
+                       );
+  } else {
+     return PciIo->Mem.Write (
+                       PciIo,
+                       Width,
+                       PCI_BAR_IDX0,
+                       FieldOffset,
+                       Count,
+                       &Value
+                       );
+  }
 }
 
 /**
@@ -332,6 +355,7 @@ VirtioPciInit (
   EFI_STATUS           Status;
   EFI_PCI_IO_PROTOCOL  *PciIo;
   PCI_TYPE00           Pci;
+  VOID                 *Resources;
 
   ASSERT (Device != NULL);
   PciIo = Device->PciIo;
@@ -373,6 +397,27 @@ VirtioPciInit (
   Device->DeviceSpecificConfigurationOffset =
     VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;
 
+  Status = PciIo->GetBarAttributes(PciIo, PCI_BAR_IDX0, NULL, &Resources);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) {
+    EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+
+    Descriptor = Resources;
+    if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+      Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessMem;
+      DEBUG ((DEBUG_INFO, "%a: Legacy Virtio MMIO BAR used.\n", __FUNCTION__));
+    } else {
+      Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessIo;
+      DEBUG ((DEBUG_INFO, "%a: Legacy Virtio IO BAR used.\n", __FUNCTION__));
+    }
+  } else {
+    DEBUG ((DEBUG_WARN, "%a: Cannot determine BAR0 type, assume IO.\n", __FUNCTION__));
+    Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessIo;
+  }
+
   return EFI_SUCCESS;
 }
 
@@ -434,6 +479,7 @@ VirtioPciDeviceBindingStart (
 {
   VIRTIO_PCI_DEVICE  *Device;
   EFI_STATUS         Status;
+  UINT64             Attributes;
 
   Device = (VIRTIO_PCI_DEVICE *)AllocateZeroPool (sizeof *Device);
   if (Device == NULL) {
@@ -473,11 +519,18 @@ VirtioPciDeviceBindingStart (
     goto ClosePciIo;
   }
 
+  Status = Device->PciIo->Attributes (Device->PciIo,
+                         EfiPciIoAttributeOperationSupported,
+                         0, &Attributes);
+  if (EFI_ERROR (Status)) {
+    goto ClosePciIo;
+  }
+
+  Attributes &= (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_IO);
   Status = Device->PciIo->Attributes (
                             Device->PciIo,
                             EfiPciIoAttributeOperationEnable,
-                            (EFI_PCI_IO_ATTRIBUTE_IO |
-                             EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
+			    Attributes | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER,
                             NULL
                             );
   if (EFI_ERROR (Status)) {
-- 
2.43.0

