Added PCI IO to MMIO translation for Virtio case into the PCI IO 
protocol functions.
Added Virtio device type into the PCI IO protocol initialization
procedure.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Daniil Egranov <daniil.egra...@arm.com>
---
 .../NonDiscoverablePciDeviceDxe.c                  |   3 +-
 .../NonDiscoverablePciDeviceDxe.inf                |   5 +-
 .../NonDiscoverablePciDeviceIo.c                   | 240 ++++++++++++++++++++-
 3 files changed, 241 insertions(+), 7 deletions(-)

diff --git 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
index 3e9ff6620d..2c3eeca914 100644
--- 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
+++ 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
+  Copyright (C) 2016-2018, Linaro Ltd. 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
@@ -32,6 +32,7 @@ SupportedNonDiscoverableDevices[] = {
   &gEdkiiNonDiscoverableUfsDeviceGuid,
   &gEdkiiNonDiscoverableUhciDeviceGuid,
   &gEdkiiNonDiscoverableXhciDeviceGuid,
+  &gEdkiiNonDiscoverableVirtioDeviceGuid
 };
 
 //
diff --git 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
index ac551a82ab..a7bf5a5fc1 100644
--- 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+++ 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
@@ -1,7 +1,7 @@
 ## @file
 # PCI I/O driver for non-discoverable devices.
 #
-# Copyright (C) 2016, Linaro Ltd.
+# Copyright (C) 2016-2018, Linaro Ltd.
 #
 # This program and the accompanying materials are licensed and made available
 # under the terms and conditions of the BSD License which accompanies this
@@ -30,6 +30,7 @@
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
   BaseMemoryLib
@@ -54,3 +55,5 @@
   gEdkiiNonDiscoverableUfsDeviceGuid        ## CONSUMES ## GUID
   gEdkiiNonDiscoverableUhciDeviceGuid       ## CONSUMES ## GUID
   gEdkiiNonDiscoverableXhciDeviceGuid       ## CONSUMES ## GUID
+  gEdkiiNonDiscoverableVirtioDeviceGuid     ## CONSUMES ## GUID
+
diff --git 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
index 0e42ae4bf6..cb99bf0ba6 100644
--- 
a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
+++ 
b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
@@ -1,7 +1,7 @@
 /** @file
 
   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
-  Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+  Copyright (c) 2016-2018, Linaro, Ltd. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -17,8 +17,12 @@
 
 #include <Library/DxeServicesTableLib.h>
 
+#include <Library/IoLib.h>
+
 #include <IndustryStandard/Acpi.h>
 
+#include <IndustryStandard/Virtio.h>
+
 #include <Protocol/PciRootBridgeIo.h>
 
 typedef struct {
@@ -374,6 +378,82 @@ PciIoMemWrite (
 }
 
 /**
+  Translate PCI IO to MMIO for VirtIo Non-Discoverable devices.
+
+  @param  BaseAddress           A base MMIO memory address of a VirtIo device.
+  @param  PciIoOffset           PCI IO offset.
+  @param  DevConfigAddress      The address is a device specific config space.
+
+  @retval EFI_SUCCESS           The address translated successfully.
+  @retval EFI_UNSUPPORTED       The PCI IO address can not be translated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioPciIoToMemIoTranslation (
+  IN     UINTN                        BaseAddress,
+  IN     UINTN                        PciIoOffset,
+  IN OUT UINTN                        *Address,
+  IN OUT BOOLEAN                      *DevConfigAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Offset;
+  INTN        DevConfigSpaceOffset;
+
+  Status               = EFI_SUCCESS;
+  Offset               = PciIoOffset;
+  *DevConfigAddress    = FALSE;
+  DevConfigSpaceOffset = 0;
+
+  //
+  //Check if it's device specific config space
+  //
+  if (PciIoOffset >= VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI ) {
+    Offset = VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;
+    DevConfigSpaceOffset = PciIoOffset - 
VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;
+    *DevConfigAddress = TRUE;
+  }
+
+  switch (Offset) {
+  case VIRTIO_PCI_OFFSET_DEVICE_FEATURES:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_HOST_FEATURES;
+    break;
+  case VIRTIO_PCI_OFFSET_GUEST_FEATURES:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_GUEST_FEATURES;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_ADDRESS:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_PFN;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_SIZE:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_NUM_MAX;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_SELECT:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_SEL;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_NOTIFY:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_QUEUE_NOTIFY;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_DEVICE_STATUS:
+    *Address = BaseAddress + VIRTIO_MMIO_OFFSET_STATUS;
+    break;
+  case VIRTIO_PCI_OFFSET_QUEUE_DEVICE_ISR:
+    Status = EFI_UNSUPPORTED;
+    break;
+  case VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI:
+  case VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI_WITH_MSI_X:
+    *Address = BaseAddress + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_MMIO 
+ DevConfigSpaceOffset;
+    break;
+  default:
+    Status = EFI_UNSUPPORTED;
+    break;
+  }
+
+  return Status;
+}
+
+/**
   Enable a PCI driver to access PCI controller registers in the PCI memory or 
I/O space.
 
   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
@@ -398,8 +478,72 @@ PciIoIoRead (
   IN OUT VOID                         *Buffer
   )
 {
-  ASSERT (FALSE);
-  return EFI_UNSUPPORTED;
+  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
+  UINTN                               Length;
+  UINTN                               Address;
+  UINT32                              ReadData;
+  BOOLEAN                             IsDevConfigSpace;
+  EFI_STATUS                          Status;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (This);
+
+  //
+  // Only allow accesses to the BARs we emulate
+  //
+  Status = GetBarResource (Dev, BarIndex, &Desc);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Length = Count << ((UINTN)Width & 0x3);
+  if (Offset + Length > Desc->AddrLen) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Non-Discoverable devices are MMIO devices. Translate PCI IO requests to 
MMIO.
+  //
+
+  //
+  // VirtIo
+  //
+  if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableVirtioDeviceGuid)) 
{
+    //
+    // Check for a valid data size
+    //
+    if ((Length != 1) && (Length != 2) &&
+        (Length != 4) && (Length != 8)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Status = VirtioPciIoToMemIoTranslation (Desc->AddrRangeMin, Offset, 
&Address, &IsDevConfigSpace);
+    if (!EFI_ERROR (Status)) {
+      if (IsDevConfigSpace == TRUE) { // Device-specific configuration 
registers
+        //
+        // The device-specific memory area of Virtio-MMIO can only be written 
in
+        // byte accesses. This is not currently in the Virtio spec.
+        //
+        MmioReadBuffer8 (Address, Length, Buffer);
+      } else if (Length < 8) {  // 32-bit MMIO registers
+        ReadData = MmioRead32 (Address);
+        // The PCI IO register width may not be the same as MMIO register.
+        // Virtio MMIO registers are always 32-bit
+        CopyMem (Buffer, &ReadData, Length);
+      } else {
+        Status = EFI_INVALID_PARAMETER;
+      }
+    }
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  ASSERT_EFI_ERROR (Status);
+  return Status;
 }
 
 /**
@@ -427,8 +571,72 @@ PciIoIoWrite (
   IN OUT VOID                         *Buffer
   )
 {
-  ASSERT (FALSE);
-  return EFI_UNSUPPORTED;
+  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
+  UINTN                               Length;
+  UINTN                               Address;
+  UINT32                              WriteData;
+  BOOLEAN                             IsDevConfigSpace;
+  EFI_STATUS                          Status;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (This);
+
+  //
+  // Only allow accesses to the BARs we emulate
+  //
+  Status = GetBarResource (Dev, BarIndex, &Desc);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Length = Count << ((UINTN)Width & 0x3);
+  if (Offset + Length > Desc->AddrLen) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Non-Discoverable devices are MMIO devices. Translate PCI IO requests to 
MMIO.
+  //
+
+  //
+  // VirtIo
+  //
+  if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableVirtioDeviceGuid)) 
{
+    //
+    // Check for a valid data size
+    //
+    if ((Length != 1) && (Length != 2) &&
+        (Length != 4) && (Length != 8)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Status = VirtioPciIoToMemIoTranslation (Desc->AddrRangeMin, Offset, 
&Address, &IsDevConfigSpace);
+    if (!EFI_ERROR (Status)) {
+      if (IsDevConfigSpace == TRUE) { // Device-specific configuration 
registers
+        //
+        // The device-specific memory area of Virtio-MMIO can only be written 
in
+        // byte accesses. This is not currently in the Virtio spec.
+        //
+        MmioWriteBuffer8 (Address, Length, Buffer);
+      } else if (Length < 8) {  // 32-bit MMIO registers
+        // The PCI IO register width may not be the same as MMIO register.
+        // Virtio MMIO registers are always 32-bit
+        CopyMem (&WriteData, Buffer, Length);
+        MmioWrite32 (Address, WriteData);
+      } else {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  ASSERT_EFI_ERROR (Status);
+  return Status;
 }
 
 /**
@@ -1408,6 +1616,7 @@ InitializePciIoProtocol (
 {
   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
   INTN                                Idx;
+  UINT32                              VirtioMagicValue;
 
   InitializeListHead (&Dev->UncachedAllocationList);
 
@@ -1471,6 +1680,15 @@ InitializePciIoProtocol (
     Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
     Dev->BarOffset = 0;
+  } else if (CompareGuid (Dev->Device->Type,
+                          &gEdkiiNonDiscoverableVirtioDeviceGuid)) {
+    Dev->ConfigSpace.Hdr.VendorId = VIRTIO_VENDOR_ID; // Required Virtio vendor
+    Dev->ConfigSpace.Hdr.DeviceId = 0x1000; // Required Virtio device id
+    Dev->ConfigSpace.Hdr.RevisionID = 0x0;
+    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
+    Dev->ConfigSpace.Hdr.ClassCode[1] = 0x0; // don't care
+    Dev->ConfigSpace.Hdr.ClassCode[2] = 0x0; // don't care
+    Dev->BarOffset = 0;
   } else {
     ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
   }
@@ -1496,6 +1714,18 @@ InitializePciIoProtocol (
     }
 
     Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
+
+    //
+    // Initialize Virtio device Id
+    //
+    if (CompareGuid (Dev->Device->Type, 
&gEdkiiNonDiscoverableVirtioDeviceGuid)) {
+      VirtioMagicValue = MmioRead32 (Dev->ConfigSpace.Device.Bar[Idx] + 
VIRTIO_MMIO_OFFSET_MAGIC);
+      if (VirtioMagicValue == VIRTIO_MMIO_MAGIC) {
+        Dev->ConfigSpace.Device.SubsystemID = MmioRead32 
(Dev->ConfigSpace.Device.Bar[Idx] +
+                                                          
VIRTIO_MMIO_OFFSET_DEVICE_ID);
+      }
+    }
+
     Dev->BarCount++;
 
     if (Desc->AddrSpaceGranularity == 64) {
-- 
2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to