/** @file Copyright (C) 2016, Linaro Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "NonDiscoverablePciDeviceIo.h" #include #define MAX_NON_DISCOVERABLE_PCI_DEVICE_ID (32 * 256) STATIC UINTN mUniqueIdCounter = 0; EFI_CPU_ARCH_PROTOCOL *mCpu; // // We only support the following device types // STATIC CONST EFI_GUID * CONST SupportedNonDiscoverableDevices[] = { &gEdkiiNonDiscoverableAhciDeviceGuid, &gEdkiiNonDiscoverableEhciDeviceGuid, &gEdkiiNonDiscoverableNvmeDeviceGuid, &gEdkiiNonDiscoverableOhciDeviceGuid, &gEdkiiNonDiscoverableSdhciDeviceGuid, &gEdkiiNonDiscoverableUfsDeviceGuid, &gEdkiiNonDiscoverableUhciDeviceGuid, &gEdkiiNonDiscoverableXhciDeviceGuid, }; // // Probe, start and stop functions of this driver, called by the DXE core for // specific devices. // // The following specifications document these interfaces: // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol // // The implementation follows: // - Driver Writer's Guide for UEFI 2.3.1 v1.01 // - 5.1.3.4 OpenProtocol() and CloseProtocol() // - UEFI Spec 2.3.1 + Errata C // - 6.3 Protocol Handler Services // /** Supported function of Driver Binding protocol for this driver. Test to see if this driver supports ControllerHandle. @param This Protocol instance pointer. @param DeviceHandle Handle of device to test. @param RemainingDevicePath A pointer to the device path. it should be ignored by device driver. @retval EFI_SUCCESS This driver supports this device. @retval other This driver does not support this device. **/ STATIC EFI_STATUS EFIAPI NonDiscoverablePciDeviceSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { NON_DISCOVERABLE_DEVICE *Device; EFI_STATUS Status; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; INTN Idx; Status = gBS->OpenProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR (Status)) { return Status; } Status = EFI_UNSUPPORTED; for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) { if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) { Status = EFI_SUCCESS; break; } } if (EFI_ERROR (Status)) { goto CloseProtocol; } // // We only support MMIO devices, so iterate over the resources to ensure // that they only describe things that we can handle // for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR; Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) { if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR || Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { Status = EFI_UNSUPPORTED; break; } } CloseProtocol: gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); return Status; } /** This routine is called right after the .Supported() called and Start this driver on ControllerHandle. @param This Protocol instance pointer. @param DeviceHandle Handle of device to bind driver to. @param RemainingDevicePath A pointer to the device path. it should be ignored by device driver. @retval EFI_SUCCESS This driver is added to this device. @retval other Some error occurs when binding this driver to this device. **/ STATIC EFI_STATUS EFIAPI NonDiscoverablePciDeviceStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { NON_DISCOVERABLE_PCI_DEVICE *Dev; EFI_STATUS Status; ASSERT (mUniqueIdCounter < MAX_NON_DISCOVERABLE_PCI_DEVICE_ID); if (mUniqueIdCounter >= MAX_NON_DISCOVERABLE_PCI_DEVICE_ID) { return EFI_OUT_OF_RESOURCES; } Dev = AllocateZeroPool (sizeof *Dev); if (Dev == NULL) { return EFI_OUT_OF_RESOURCES; } Status = gBS->OpenProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Dev->Device, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR (Status)) { goto FreeDev; } InitializePciIoProtocol (Dev); // // Setup complete, attempt to export the driver instance's // EFI_PCI_IO_PROTOCOL interface. // Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG; Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid, EFI_NATIVE_INTERFACE, &Dev->PciIo); if (EFI_ERROR (Status)) { goto CloseProtocol; } Dev->UniqueId = mUniqueIdCounter++; return EFI_SUCCESS; CloseProtocol: gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreeDev: FreePool (Dev); return Status; } /** Stop this driver on ControllerHandle. @param This Protocol instance pointer. @param DeviceHandle Handle of device to stop driver on. @param NumberOfChildren Not used. @param ChildHandleBuffer Not used. @retval EFI_SUCCESS This driver is removed from this device. @retval other Some error occurs when removing this driver from this device. **/ STATIC EFI_STATUS EFIAPI NonDiscoverablePciDeviceStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; NON_DISCOVERABLE_PCI_DEVICE *Dev; Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR (Status)) { return Status; } Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo); // // Handle Stop() requests for in-use driver instances gracefully. // Status = gBS->UninstallProtocolInterface (DeviceHandle, &gEfiPciIoProtocolGuid, &Dev->PciIo); if (EFI_ERROR (Status)) { return Status; } gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreePool (Dev); return EFI_SUCCESS; } // // 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 = { &NonDiscoverablePciDeviceSupported, &NonDiscoverablePciDeviceStart, &NonDiscoverablePciDeviceStop, 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers NULL, NULL }; /** Entry point of this driver. @param ImageHandle Image handle this driver. @param SystemTable Pointer to the System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurred when executing this entry point. **/ EFI_STATUS EFIAPI NonDiscoverablePciDeviceDxeEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); ASSERT_EFI_ERROR(Status); return EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gDriverBinding, ImageHandle, &gComponentName, &gComponentName2 ); }