diff mbox

[edk2,RFC,2/5] Ovmf/Xen: allow non-PCI usage of XenBusDxe

Message ID 1420195510-22100-3-git-send-email-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel Jan. 2, 2015, 10:45 a.m. UTC
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.biesheuvel@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 mbox

Patch

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