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