new file mode 100644
@@ -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
@@ -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
@@ -155,7 +155,7 @@ XenBusDxeComponentNameGetControllerName (
Status = EfiTestManagedDevice (
ControllerHandle,
gXenBusDxeDriverBinding.DriverBindingHandle,
- &gEfiPciIoProtocolGuid
+ &gXenIoProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
@@ -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;
@@ -29,8 +29,7 @@
**/
VOID
XenGrantTableInit (
- IN XENBUS_DEVICE *Dev,
- IN UINT64 MmioAddr
+ IN XENBUS_DEVICE *Dev
);
/**
@@ -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)) {
@@ -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);
@@ -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;
@@ -73,4 +73,5 @@
gEfiComponentName2ProtocolGuid
gEfiComponentNameProtocolGuid
gXenBusProtocolGuid
+ gXenIoProtocolGuid
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