/** @file Driver for the virtual Xen PCI device Copyright (C) 2012, Red Hat, Inc. Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
Copyright (C) 2013, ARM Ltd. Copyright (C) 2015, Linaro Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 /** Device probe function for this driver. The DXE core calls this function for any given device in order to see if the driver can drive the device. @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @param[in] DeviceHandle The device to probe. @param[in] RemainingDevicePath Relevant only for bus drivers, ignored. @retval EFI_SUCCESS The driver supports the device being probed. @retval EFI_UNSUPPORTED The driver does not support the device being probed. @return Error codes from the OpenProtocol() boot service or the PciIo protocol. **/ STATIC EFI_STATUS EFIAPI XenIoPciDeviceBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; PCI_TYPE00 Pci; // // Attempt to open the device with the PciIo set of interfaces. On success, // the protocol is "instantiated" for the PCI device. Covers duplicate open // attempts (EFI_ALREADY_STARTED). // Status = gBS->OpenProtocol ( DeviceHandle, // candidate device &gEfiPciIoProtocolGuid, // for generic PCI access (VOID **)&PciIo, // handle to instantiate This->DriverBindingHandle, // requestor driver identity DeviceHandle, // ControllerHandle, according to // the UEFI Driver Model EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to // the device; to be released ); if (EFI_ERROR (Status)) { return Status; } // // Read entire PCI configuration header for more extensive check ahead. // Status = PciIo->Pci.Read ( PciIo, // (protocol, device) // handle EfiPciIoWidthUint32, // access width & copy // mode 0, // Offset sizeof Pci / sizeof (UINT32), // Count &Pci // target buffer ); if (Status == EFI_SUCCESS) { if ((Pci.Hdr.VendorId == PCI_VENDOR_ID_XEN) && (Pci.Hdr.DeviceId == PCI_DEVICE_ID_XEN_PLATFORM)) { Status = EFI_SUCCESS; } else { Status = EFI_UNSUPPORTED; } } // // We needed PCI IO access only transitorily, to see whether we support the // device or not. // gBS->CloseProtocol ( DeviceHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, DeviceHandle ); return Status; } /** After we've pronounced support for a specific device in DriverBindingSupported(), we start managing said device (passed in by the Driver Execution Environment) with the following service. See DriverBindingSupported() for specification references. @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @param[in] DeviceHandle The supported device to drive. @param[in] RemainingDevicePath Relevant only for bus drivers, ignored. @retval EFI_SUCCESS The device was started. @retval EFI_OUT_OF_RESOURCES Memory allocation failed. @return Error codes from the OpenProtocol() boot service, the PciIo protocol or the InstallProtocolInterface() boot service. **/ STATIC EFI_STATUS EFIAPI XenIoPciDeviceBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; XENIO_PROTOCOL *XenIo; EFI_PCI_IO_PROTOCOL *PciIo; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc; XenIo = (XENIO_PROTOCOL *)AllocateZeroPool (sizeof *XenIo); if (XenIo == NULL) { return EFI_OUT_OF_RESOURCES; } Status = gBS->OpenProtocol ( DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto FreeXenIo; } // // 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 ((DEBUG_INFO, "XenIoPci: BAR at %LX\n", BarDesc->AddrRangeMin)); XenIo->GrantTableAddress = BarDesc->AddrRangeMin; FreePool (BarDesc); Status = gBS->InstallProtocolInterface ( &DeviceHandle, &gXenIoProtocolGuid, EFI_NATIVE_INTERFACE, XenIo ); if (!EFI_ERROR (Status)) { return EFI_SUCCESS; } gBS->CloseProtocol ( DeviceHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, DeviceHandle ); FreeXenIo: FreePool (XenIo); return Status; } /** Stop driving the XenIo PCI device @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @param[in] DeviceHandle Stop driving this device. @param[in] NumberOfChildren Since this function belongs to a device driver only (as opposed to a bus driver), the caller environment sets NumberOfChildren to zero, and we ignore it. @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren). @retval EFI_SUCCESS Driver instance has been stopped and the PCI configuration attributes have been restored. @return Error codes from the OpenProtocol() or CloseProtocol(), UninstallProtocolInterface() boot services. **/ STATIC EFI_STATUS EFIAPI XenIoPciDeviceBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; XENIO_PROTOCOL *XenIo; Status = gBS->OpenProtocol ( DeviceHandle, // candidate device &gXenIoProtocolGuid, // retrieve the XenIo iface (VOID **)&XenIo, // target pointer This->DriverBindingHandle, // requestor driver identity DeviceHandle, // requesting lookup for dev. EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added ); if (EFI_ERROR (Status)) { return Status; } // // Handle Stop() requests for in-use driver instances gracefully. // Status = gBS->UninstallProtocolInterface ( DeviceHandle, &gXenIoProtocolGuid, XenIo ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->CloseProtocol ( DeviceHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, DeviceHandle ); FreePool (XenIo); return Status; } // // The static object that groups the Supported() (ie. probe), Start() and // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata // C, 10.1 EFI Driver Binding Protocol. // STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { &XenIoPciDeviceBindingSupported, &XenIoPciDeviceBindingStart, &XenIoPciDeviceBindingStop, 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers NULL, // ImageHandle, to be overwritten by // EfiLibInstallDriverBindingComponentName2() in XenIoPciDeviceEntryPoint() NULL // DriverBindingHandle, ditto }; // // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name // in English, for display on standard console devices. This is recommended for // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names. // STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = { { "eng;en", L"XenIo PCI Driver" }, { NULL, NULL } }; STATIC EFI_COMPONENT_NAME_PROTOCOL gComponentName; EFI_STATUS EFIAPI XenIoPciGetDriverName ( IN EFI_COMPONENT_NAME_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName ) { return LookupUnicodeString2 ( Language, This->SupportedLanguages, mDriverNameTable, DriverName, (BOOLEAN)(This == &gComponentName) // Iso639Language ); } EFI_STATUS EFIAPI XenIoPciGetDeviceName ( IN EFI_COMPONENT_NAME_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_HANDLE ChildHandle, IN CHAR8 *Language, OUT CHAR16 **ControllerName ) { return EFI_UNSUPPORTED; } STATIC EFI_COMPONENT_NAME_PROTOCOL gComponentName = { &XenIoPciGetDriverName, &XenIoPciGetDeviceName, "eng" // SupportedLanguages, ISO 639-2 language codes }; STATIC EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&XenIoPciGetDriverName, (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&XenIoPciGetDeviceName, "en" // SupportedLanguages, RFC 4646 language codes }; // // Entry point of this driver. // EFI_STATUS EFIAPI XenIoPciDeviceEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { return EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gDriverBinding, ImageHandle, &gComponentName, &gComponentName2 ); }