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 30a9fb1e9b42..3711fa922311 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -58,6 +58,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 52ff045a74db..e825c7c76fa5 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 cc334c086c1f..efa9bb0ccd23 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.c
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.c
@@ -234,8 +234,29 @@ XenBusDxeDriverBindingSupported (
 {
   EFI_STATUS          Status;
   EFI_PCI_IO_PROTOCOL *PciIo;
+  XENIO_PROTOCOL      *XenIo;
   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,
+                     (VOID **)&XenIo,
+                     This->DriverBindingHandle,
+                     ControllerHandle,
+                     EFI_OPEN_PROTOCOL_BY_DRIVER
+                     );
+
+  gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
+    This->DriverBindingHandle, ControllerHandle);
+
+  if (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED) {
+   return Status;
+  }
+
   Status = gBS->OpenProtocol (
                      ControllerHandle,
                      &gEfiPciIoProtocolGuid,
@@ -280,6 +301,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 Handle.
+
+  @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().
@@ -326,19 +478,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;
   }
@@ -361,6 +506,7 @@ XenBusDxeDriverBindingStart (
   Dev->This = This;
   Dev->ControllerHandle = ControllerHandle;
   Dev->PciIo = PciIo;
+  Dev->XenIo = XenIo;
   Dev->DevicePath = DevicePath;
   InitializeListHead (&Dev->ChildList);
 
@@ -376,20 +522,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"));
@@ -397,7 +529,7 @@ XenBusDxeDriverBindingStart (
     goto ErrorAllocated;
   }
 
-  XenGrantTableInit (Dev, MmioAddr);
+  XenGrantTableInit (Dev);
 
   Status = XenStoreInit (Dev);
   ASSERT_EFI_ERROR (Status);
@@ -417,8 +549,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;
 }
 
@@ -507,8 +639,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 9b7219906a69..596e5f04a03b 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.h
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.h
@@ -40,6 +40,7 @@
 // Consumed Protocols
 //
 #include <Protocol/PciIo.h>
+#include <Protocol/XenIo.h>
 
 
 //
@@ -87,6 +88,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 714607dbd6f8..8294997e20db 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.inf
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.inf
@@ -71,4 +71,5 @@
   gEfiComponentName2ProtocolGuid
   gEfiComponentNameProtocolGuid
   gXenBusProtocolGuid
+  gXenIoProtocolGuid
 
