While Xen on Intel uses a virtual PCI device to communicate the
base address of the grant table, the ARM implementation uses a DT
node, which is fundamentally incompatible with the way XenBusDxe is
implemented, i.e., as a UEFI Driver Model implementation for a PCI
device.

To allow the non-PCI implementations to use this driver anyway, this
patch introduces an abstract XENIO_PROTOCOL protocol, which contains
just the grant table base address. The Intel implementation is adapted
to allocate such a protocol on the fly based on the PCI config space
metadata, so it operates as before. Other users can invoke the driver
by installing a XENIO_PROTOCOL instance on a handle, and invoking
ConnectController()

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org>
---
 OvmfPkg/Include/Protocol/XenIo.h  |  48 ++++++++++
 OvmfPkg/OvmfPkg.dec               |   1 +
 OvmfPkg/XenBusDxe/ComponentName.c |   2 +-
 OvmfPkg/XenBusDxe/GrantTable.c    |   5 +-
 OvmfPkg/XenBusDxe/GrantTable.h    |   3 +-
 OvmfPkg/XenBusDxe/XenBus.c        |   6 +-
 OvmfPkg/XenBusDxe/XenBusDxe.c     | 185 ++++++++++++++++++++++++++++++++------
 OvmfPkg/XenBusDxe/XenBusDxe.h     |   2 +
 OvmfPkg/XenBusDxe/XenBusDxe.inf   |   1 +
 9 files changed, 215 insertions(+), 38 deletions(-)
 create mode 100644 OvmfPkg/Include/Protocol/XenIo.h

diff --git a/OvmfPkg/Include/Protocol/XenIo.h b/OvmfPkg/Include/Protocol/XenIo.h
new file mode 100644
index 000000000000..510391f3b3e8
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/XenIo.h
@@ -0,0 +1,48 @@
+/** @file
+  XenIo protocol to abstract arch specific details
+
+  The Xen implementations for the Intel and ARM archictures differ in the way
+  the base address of the grant table is communicated to the guest. The former
+  uses a virtual PCI device, while the latter uses a device tree node.
+  In order to allow the XenBusDxe UEFI driver to be reused for the non-PCI
+  Xen implementation, this abstract protocol can be installed on a handle
+  with the appropriate base address.
+
+  Copyright (C) 2014, 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 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 __PROTOCOL_XENIO_H__
+#define __PROTOCOL_XENIO_H__
+
+#include <IndustryStandard/Xen/xen.h>
+
+#define XENIO_PROTOCOL_GUID \
+  {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 
0x49}}
+
+///
+/// Forward declaration
+///
+typedef struct _XENIO_PROTOCOL XENIO_PROTOCOL;
+
+///
+/// Protocol structure
+///
+struct _XENIO_PROTOCOL {
+  //
+  // Protocol data fields
+  //
+  EFI_PHYSICAL_ADDRESS          GrantTableAddress;
+};
+
+extern EFI_GUID gXenIoProtocolGuid;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 314d97c258b3..0233ae4ca754 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -52,6 +52,7 @@
   gVirtioDeviceProtocolGuid       = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 
0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}}
   gBlockMmioProtocolGuid          = {0x6b558ce3, 0x69e5, 0x4c67, {0xa6, 0x34, 
0xf7, 0xfe, 0x72, 0xad, 0xbe, 0x84}}
   gXenBusProtocolGuid             = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 
0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}}
+  gXenIoProtocolGuid              = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 
0x85, 0x55, 0x62, 0x59, 0x04, 0x49}}
 
 [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
diff --git a/OvmfPkg/XenBusDxe/ComponentName.c 
b/OvmfPkg/XenBusDxe/ComponentName.c
index 4530509e65dc..3f2dd406c77d 100644
--- a/OvmfPkg/XenBusDxe/ComponentName.c
+++ b/OvmfPkg/XenBusDxe/ComponentName.c
@@ -155,7 +155,7 @@ XenBusDxeComponentNameGetControllerName (
   Status = EfiTestManagedDevice (
              ControllerHandle,
              gXenBusDxeDriverBinding.DriverBindingHandle,
-             &gEfiPciIoProtocolGuid
+             &gXenIoProtocolGuid
              );
   if (EFI_ERROR (Status)) {
     return Status;
diff --git a/OvmfPkg/XenBusDxe/GrantTable.c b/OvmfPkg/XenBusDxe/GrantTable.c
index 37d3bf786c64..ae9059c146f1 100644
--- a/OvmfPkg/XenBusDxe/GrantTable.c
+++ b/OvmfPkg/XenBusDxe/GrantTable.c
@@ -139,8 +139,7 @@ XenGrantTableEndAccess (
 
 VOID
 XenGrantTableInit (
-  IN XENBUS_DEVICE  *Dev,
-  IN UINT64         MmioAddr
+  IN XENBUS_DEVICE  *Dev
   )
 {
   xen_add_to_physmap_t Parameters;
@@ -155,7 +154,7 @@ XenGrantTableInit (
     XenGrantTablePutFreeEntry ((grant_ref_t)Index);
   }
 
-  GrantTable = (VOID*)(UINTN) MmioAddr;
+  GrantTable = (VOID*)(UINTN) Dev->XenIo->GrantTableAddress;
   for (Index = 0; Index < NR_GRANT_FRAMES; Index++) {
     Parameters.domid = DOMID_SELF;
     Parameters.idx = Index;
diff --git a/OvmfPkg/XenBusDxe/GrantTable.h b/OvmfPkg/XenBusDxe/GrantTable.h
index 5772c56662df..194275ba7ed5 100644
--- a/OvmfPkg/XenBusDxe/GrantTable.h
+++ b/OvmfPkg/XenBusDxe/GrantTable.h
@@ -29,8 +29,7 @@
 **/
 VOID
 XenGrantTableInit (
-  IN XENBUS_DEVICE  *Dev,
-  IN UINT64         MmioAddr
+  IN XENBUS_DEVICE  *Dev
   );
 
 /**
diff --git a/OvmfPkg/XenBusDxe/XenBus.c b/OvmfPkg/XenBusDxe/XenBus.c
index f69c27dd184a..ee9526c33252 100644
--- a/OvmfPkg/XenBusDxe/XenBus.c
+++ b/OvmfPkg/XenBusDxe/XenBus.c
@@ -138,7 +138,7 @@ XenBusAddDevice (
   XENBUS_PRIVATE_DATA *Private;
   EFI_STATUS Status;
   XENBUS_DEVICE_PATH *TempXenBusPath;
-  VOID *ChildPciIo;
+  VOID *ChildXenIo;
 
   AsciiSPrint (DevicePath, sizeof (DevicePath),
                "device/%a/%a", Type, Id);
@@ -208,8 +208,8 @@ XenBusAddDevice (
     }
 
     Status = gBS->OpenProtocol (Dev->ControllerHandle,
-               &gEfiPciIoProtocolGuid,
-               &ChildPciIo, Dev->This->DriverBindingHandle,
+               &gXenIoProtocolGuid,
+               &ChildXenIo, Dev->This->DriverBindingHandle,
                Private->Handle,
                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
     if (EFI_ERROR (Status)) {
diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.c b/OvmfPkg/XenBusDxe/XenBusDxe.c
index 07336ff15bba..a03f7cb6d8b9 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.c
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.c
@@ -194,6 +194,22 @@ XenBusDxeDriverBindingSupported (
   EFI_PCI_IO_PROTOCOL *PciIo;
   PCI_TYPE00          Pci;
 
+  //
+  // If the ControllerHandle supports the XENIO_PROTOCOL, we can use
+  // it directly without having to bother with the PCI representation.
+  //
+  Status = gBS->OpenProtocol (
+                     ControllerHandle,
+                     &gXenIoProtocolGuid,
+                     NULL,
+                     This->DriverBindingHandle,
+                     ControllerHandle,
+                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                     );
+  if (!EFI_ERROR (Status)) {
+    return Status;
+  }
+
   Status = gBS->OpenProtocol (
                      ControllerHandle,
                      &gEfiPciIoProtocolGuid,
@@ -238,6 +254,137 @@ NotifyExitBoot (
 }
 
 /**
+  Opens the XENIO_PROTOCOL on ControllerHandle.
+
+  If the protocol is not available, but the EFI_PCI_IO_PROTOCOL is, create
+  the XENIO_PROTOCOL protocol instance on the fly based on the PCI metadata
+  and install it on ControllerHandle.
+
+  @param ControllerHandle     The controller handle
+  @param DriverBindingHandle  The driver binding handle
+  @param XenIo                The XENIO_PROTOCOL return value
+  @param PciIo                The EFI_PCI_IO_PROTOCOL return value, or NULL if
+                              the XENIO_PROTOCOL already existed on Handle
+**/
+STATIC
+EFI_STATUS
+OpenOrInstallXenIoProtocolOnHandle (
+  IN  EFI_HANDLE          ControllerHandle,
+  IN  EFI_HANDLE          DriverBindingHandle,
+  OUT XENIO_PROTOCOL      **XenIo,
+  OUT EFI_PCI_IO_PROTOCOL **PciIo
+  )
+{
+  EFI_STATUS Status;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
+
+  //
+  // We support both EFI_PCI_IO_PROTOCOL and XENIO_PROTOCOL, the former only
+  // if the vendor and product IDs match up (as verified in .Supported()).
+  // The latter has precedence, and we install it on the fly if it is not
+  // supported.
+  //
+  *PciIo = NULL;
+  Status = gBS->OpenProtocol (
+                     ControllerHandle,
+                     &gXenIoProtocolGuid,
+                     (VOID**)XenIo,
+                     DriverBindingHandle,
+                     ControllerHandle,
+                     EFI_OPEN_PROTOCOL_BY_DRIVER
+                     );
+  if (EFI_ERROR (Status)) {
+    //
+    // This handle does not support XENIO_PROTOCOL yet, which implies that it
+    // does support the EFI_PCI_IO_PROTOCOL, or we wouldn't have been invoked.
+    // Get the grant table base address from the PCI config space, and allocate
+    // and install the XENIO_PROTOCOL instance on the fly.
+    //
+    Status = gBS->OpenProtocol (
+                       ControllerHandle,
+                       &gEfiPciIoProtocolGuid,
+                       (VOID**)PciIo,
+                       DriverBindingHandle,
+                       ControllerHandle,
+                       EFI_OPEN_PROTOCOL_BY_DRIVER
+                       );
+    ASSERT_EFI_ERROR (Status);
+
+    *XenIo = AllocateZeroPool (sizeof(XENIO_PROTOCOL));
+    ASSERT (*XenIo != NULL);
+
+    //
+    // The BAR1 of this PCI device is used for shared memory and is supposed to
+    // look like MMIO. The address space of the BAR1 will be used to map the
+    // Grant Table.
+    //
+    Status = (*PciIo)->GetBarAttributes (*PciIo, PCI_BAR_IDX1, NULL, (VOID**) 
&BarDesc);
+    ASSERT_EFI_ERROR (Status);
+    ASSERT (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
+
+    /* Get a Memory address for mapping the Grant Table. */
+    DEBUG ((EFI_D_INFO, "XenBus: BAR at %LX\n", BarDesc->AddrRangeMin));
+    (*XenIo)->GrantTableAddress = BarDesc->AddrRangeMin;
+    FreePool (BarDesc);
+
+    //
+    // Now install the XENIO_PROTOCOL protocol instance on Handle.
+    // This should only fail in extraordinary cases, as we have already
+    // established that the protocol does not exist yet on the handle.
+    //
+    Status = gBS->InstallProtocolInterface (ControllerHandle,
+                &gXenIoProtocolGuid, EFI_NATIVE_INTERFACE, *XenIo);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = gBS->OpenProtocol (
+                       ControllerHandle,
+                       &gXenIoProtocolGuid,
+                       (VOID**)XenIo,
+                       DriverBindingHandle,
+                       ControllerHandle,
+                       EFI_OPEN_PROTOCOL_BY_DRIVER
+                       );
+    if (EFI_ERROR (Status)) {
+      gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
+                          DriverBindingHandle, ControllerHandle);
+    }
+  }
+  return Status;
+}
+
+/**
+  Close or uninstall the XENIO_PROTOCOL instance on ControllerHandle
+
+  Close the XENIO_PROTOCOL protocol instance on ControllerHandle, and
+  in case PciIo != NULL, uninstall and deallocate it as well.
+  
+  @param ControllerHandle     The controller handle
+  @param DriverBindingHandle  The driver binding handle
+  @param XenIo                The XENIO_PROTOCOL protocol instance
+  @param PciIo                The EFI_PCI_IO_PROTOCOL protocol instance, or 
NULL
+                              if the XENIO_PROTOCOL already existed on
+                              ControllerHandle
+**/
+STATIC
+VOID
+CloseOrUninstallXenIoProtocolOnHandle (
+  IN  EFI_HANDLE          ControllerHandle,
+  IN  EFI_HANDLE          DriverBindingHandle,
+  IN  XENIO_PROTOCOL      *XenIo,
+  IN  EFI_PCI_IO_PROTOCOL *PciIo
+  )
+{
+  gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
+                      DriverBindingHandle, ControllerHandle);
+  if (PciIo != NULL) {
+    gBS->UninstallProtocolInterface (ControllerHandle, &gXenIoProtocolGuid, 
XenIo);
+    FreePool (XenIo);
+    gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
+                        DriverBindingHandle, ControllerHandle);
+  }
+}
+
+/**
   Starts a bus controller.
 
   The Start() function is designed to be invoked from the EFI boot service 
ConnectController().
@@ -284,19 +431,12 @@ XenBusDxeDriverBindingStart (
 {
   EFI_STATUS Status;
   XENBUS_DEVICE *Dev;
+  XENIO_PROTOCOL *XenIo;
   EFI_PCI_IO_PROTOCOL *PciIo;
-  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
-  UINT64 MmioAddr;
   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
 
-  Status = gBS->OpenProtocol (
-                     ControllerHandle,
-                     &gEfiPciIoProtocolGuid,
-                     (VOID **) &PciIo,
-                     This->DriverBindingHandle,
-                     ControllerHandle,
-                     EFI_OPEN_PROTOCOL_BY_DRIVER
-                     );
+  Status = OpenOrInstallXenIoProtocolOnHandle (ControllerHandle,
+             This->DriverBindingHandle, &XenIo, &PciIo);
   if (EFI_ERROR (Status)) {
     return Status;
   }
@@ -319,6 +459,7 @@ XenBusDxeDriverBindingStart (
   Dev->This = This;
   Dev->ControllerHandle = ControllerHandle;
   Dev->PciIo = PciIo;
+  Dev->XenIo = XenIo;
   Dev->DevicePath = DevicePath;
   InitializeListHead (&Dev->ChildList);
 
@@ -334,20 +475,6 @@ XenBusDxeDriverBindingStart (
   mMyDevice = Dev;
   EfiReleaseLock (&mMyDeviceLock);
 
-  //
-  // The BAR1 of this PCI device is used for shared memory and is supposed to
-  // look like MMIO. The address space of the BAR1 will be used to map the
-  // Grant Table.
-  //
-  Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX1, NULL, (VOID**) 
&BarDesc);
-  ASSERT_EFI_ERROR (Status);
-  ASSERT (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
-
-  /* Get a Memory address for mapping the Grant Table. */
-  DEBUG ((EFI_D_INFO, "XenBus: BAR at %LX\n", BarDesc->AddrRangeMin));
-  MmioAddr = BarDesc->AddrRangeMin;
-  FreePool (BarDesc);
-
   Status = XenGetSharedInfoPage (Dev);
   if (EFI_ERROR (Status)) {
     DEBUG ((EFI_D_ERROR, "XenBus: Unable to get the shared info page.\n"));
@@ -355,7 +482,7 @@ XenBusDxeDriverBindingStart (
     goto ErrorAllocated;
   }
 
-  XenGrantTableInit (Dev, MmioAddr);
+  XenGrantTableInit (Dev);
 
   Status = XenStoreInit (Dev);
   ASSERT_EFI_ERROR (Status);
@@ -375,8 +502,8 @@ ErrorAllocated:
   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
                       This->DriverBindingHandle, ControllerHandle);
 ErrorOpenningProtocol:
-  gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
-                      This->DriverBindingHandle, ControllerHandle);
+  CloseOrUninstallXenIoProtocolOnHandle (ControllerHandle,
+    This->DriverBindingHandle, XenIo, PciIo);
   return Status;
 }
 
@@ -465,8 +592,8 @@ XenBusDxeDriverBindingStop (
 
   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
          This->DriverBindingHandle, ControllerHandle);
-  gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
-         This->DriverBindingHandle, ControllerHandle);
+  CloseOrUninstallXenIoProtocolOnHandle (ControllerHandle,
+    This->DriverBindingHandle, Dev->XenIo, Dev->PciIo);
 
   mMyDevice = NULL;
   FreePool (Dev);
diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.h b/OvmfPkg/XenBusDxe/XenBusDxe.h
index 0879e9cd194f..81b73f8f1e0b 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.h
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.h
@@ -45,6 +45,7 @@
 // Consumed Protocols
 //
 #include <Protocol/PciIo.h>
+#include <Protocol/XenIo.h>
 
 
 //
@@ -92,6 +93,7 @@ struct _XENBUS_DEVICE {
   EFI_DRIVER_BINDING_PROTOCOL   *This;
   EFI_HANDLE                    ControllerHandle;
   EFI_PCI_IO_PROTOCOL           *PciIo;
+  XENIO_PROTOCOL                *XenIo;
   EFI_EVENT                     ExitBootEvent;
   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
   LIST_ENTRY                    ChildList;
diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.inf b/OvmfPkg/XenBusDxe/XenBusDxe.inf
index 2645267a1c6f..1429a85e1d12 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.inf
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.inf
@@ -73,4 +73,5 @@
   gEfiComponentName2ProtocolGuid
   gEfiComponentNameProtocolGuid
   gXenBusProtocolGuid
+  gXenIoProtocolGuid
 
-- 
1.8.3.2


------------------------------------------------------------------------------
Dive into the World of Parallel Programming! The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to