--- /dev/null
+/** @file\r
+\r
+ Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NonDiscoverablePciDeviceIo.h"\r
+\r
+#include <Protocol/DriverBinding.h>\r
+\r
+//\r
+// We only support the following device types\r
+//\r
+STATIC\r
+CONST EFI_GUID * CONST\r
+SupportedNonDiscoverableDevices [] = {\r
+ &gEdkiiNonDiscoverableAhciDeviceGuid,\r
+ &gEdkiiNonDiscoverableEhciDeviceGuid,\r
+ &gEdkiiNonDiscoverableNvmeDeviceGuid,\r
+ &gEdkiiNonDiscoverableOhciDeviceGuid,\r
+ &gEdkiiNonDiscoverableSdhciDeviceGuid,\r
+ &gEdkiiNonDiscoverableUfsDeviceGuid,\r
+ &gEdkiiNonDiscoverableUhciDeviceGuid,\r
+ &gEdkiiNonDiscoverableXhciDeviceGuid,\r
+};\r
+\r
+//\r
+// Probe, start and stop functions of this driver, called by the DXE core for\r
+// specific devices.\r
+//\r
+// The following specifications document these interfaces:\r
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol\r
+// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol\r
+//\r
+// The implementation follows:\r
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01\r
+// - 5.1.3.4 OpenProtocol() and CloseProtocol()\r
+// - UEFI Spec 2.3.1 + Errata C\r
+// - 6.3 Protocol Handler Services\r
+//\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonDiscoverablePciDeviceSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE DeviceHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ NON_DISCOVERABLE_DEVICE *Device;\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+ INTN Idx;\r
+\r
+ Status = gBS->OpenProtocol (DeviceHandle,\r
+ &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,\r
+ This->DriverBindingHandle, DeviceHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Restricted to DMA coherent for now\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ if (Device->DmaType != NonDiscoverableDeviceDmaTypeCoherent) {\r
+ goto CloseProtocol;\r
+ }\r
+\r
+ for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {\r
+ if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto CloseProtocol;\r
+ }\r
+\r
+ //\r
+ // We only support MMIO devices, so iterate over the resources to ensure\r
+ // that they only describe things that we can handle\r
+ //\r
+ for (Desc = Device->Resources; Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
+ if (Desc->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR ||\r
+ Desc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+ }\r
+\r
+CloseProtocol:\r
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
+ This->DriverBindingHandle, DeviceHandle);\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonDiscoverablePciDeviceStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE DeviceHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_STATUS Status;\r
+\r
+ Dev = AllocateZeroPool (sizeof *Dev);\r
+ if (Dev == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (DeviceHandle,\r
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
+ (VOID **)&Dev->Device, This->DriverBindingHandle,\r
+ DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeDev;\r
+ }\r
+\r
+ InitializePciIoProtocol (Dev);\r
+\r
+ //\r
+ // Setup complete, attempt to export the driver instance's\r
+ // EFI_PCI_IO_PROTOCOL interface.\r
+ //\r
+ Dev->Signature = NON_DISCOVERABLE_PCI_DEVICE_SIG;\r
+ Status = gBS->InstallProtocolInterface (&DeviceHandle, &gEfiPciIoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE, &Dev->PciIo);\r
+ if (EFI_ERROR (Status)) {\r
+ goto CloseProtocol;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+CloseProtocol:\r
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
+ This->DriverBindingHandle, DeviceHandle);\r
+\r
+FreeDev:\r
+ FreePool (Dev);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonDiscoverablePciDeviceStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE DeviceHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+\r
+ Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
+ (VOID **)&PciIo, This->DriverBindingHandle, DeviceHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO (PciIo);\r
+\r
+ //\r
+ // Handle Stop() requests for in-use driver instances gracefully.\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
+ &gEfiPciIoProtocolGuid, &Dev->PciIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
+ This->DriverBindingHandle, DeviceHandle);\r
+\r
+ FreePool (Dev);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+//\r
+// The static object that groups the Supported() (ie. probe), Start() and\r
+// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
+// C, 10.1 EFI Driver Binding Protocol.\r
+//\r
+STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
+ &NonDiscoverablePciDeviceSupported,\r
+ &NonDiscoverablePciDeviceStart,\r
+ &NonDiscoverablePciDeviceStop,\r
+ 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// Entry point of this driver.\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+NonDiscoverablePciDeviceDxeEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gDriverBinding,\r
+ ImageHandle,\r
+ &gComponentName,\r
+ &gComponentName2\r
+ );\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NonDiscoverablePciDeviceIo.h"\r
+\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+#include <Protocol/PciRootBridgeIo.h>\r
+\r
+typedef struct {\r
+ EFI_PHYSICAL_ADDRESS AllocAddress;\r
+ VOID *HostAddress;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION Operation;\r
+ UINTN NumberOfBytes;\r
+} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;\r
+\r
+//\r
+// Get the resource associated with BAR number 'BarIndex'.\r
+//\r
+STATIC\r
+EFI_STATUS\r
+GetBarResource (\r
+ IN NON_DISCOVERABLE_PCI_DEVICE *Dev,\r
+ IN UINT8 BarIndex,\r
+ OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor\r
+ )\r
+{\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+\r
+ if (BarIndex < Dev->BarOffset) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ BarIndex -= Dev->BarOffset;\r
+\r
+ for (Desc = Dev->Device->Resources;\r
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
+\r
+ if (BarIndex == 0) {\r
+ *Descriptor = Desc;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BarIndex -= 1;\r
+ }\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoPollMem (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINT64 Mask,\r
+ IN UINT64 Value,\r
+ IN UINT64 Delay,\r
+ OUT UINT64 *Result\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoPollIo (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINT64 Mask,\r
+ IN UINT64 Value,\r
+ IN UINT64 Delay,\r
+ OUT UINT64 *Result\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoMemRW (\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINTN Count,\r
+ IN UINTN DstStride,\r
+ IN VOID *Dst,\r
+ IN UINTN SrcStride,\r
+ OUT CONST VOID *Src\r
+ )\r
+{\r
+ volatile UINT8 *Dst8;\r
+ volatile UINT16 *Dst16;\r
+ volatile UINT32 *Dst32;\r
+ volatile CONST UINT8 *Src8;\r
+ volatile CONST UINT16 *Src16;\r
+ volatile CONST UINT32 *Src32;\r
+\r
+ //\r
+ // Loop for each iteration and move the data\r
+ //\r
+ switch (Width & 0x3) {\r
+ case EfiPciWidthUint8:\r
+ Dst8 = (UINT8 *)Dst;\r
+ Src8 = (UINT8 *)Src;\r
+ for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {\r
+ *Dst8 = *Src8;\r
+ }\r
+ break;\r
+ case EfiPciWidthUint16:\r
+ Dst16 = (UINT16 *)Dst;\r
+ Src16 = (UINT16 *)Src;\r
+ for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {\r
+ *Dst16 = *Src16;\r
+ }\r
+ break;\r
+ case EfiPciWidthUint32:\r
+ Dst32 = (UINT32 *)Dst;\r
+ Src32 = (UINT32 *)Src;\r
+ for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {\r
+ *Dst32 = *Src32;\r
+ }\r
+ break;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoMemRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ UINTN AlignMask;\r
+ VOID *Address;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ //\r
+ // Only allow accesses to the BARs we emulate\r
+ //\r
+ Status = GetBarResource (Dev, BarIndex, &Desc);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
+ AlignMask = (1 << (Width & 0x03)) - 1;\r
+ if ((UINTN)Address & AlignMask) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ case EfiPciWidthUint16:\r
+ case EfiPciWidthUint32:\r
+ case EfiPciWidthUint64:\r
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
+\r
+ case EfiPciWidthFifoUint8:\r
+ case EfiPciWidthFifoUint16:\r
+ case EfiPciWidthFifoUint32:\r
+ case EfiPciWidthFifoUint64:\r
+ return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);\r
+\r
+ case EfiPciWidthFillUint8:\r
+ case EfiPciWidthFillUint16:\r
+ case EfiPciWidthFillUint32:\r
+ case EfiPciWidthFillUint64:\r
+ return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);\r
+\r
+ default:\r
+ break;\r
+ }\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoMemWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ UINTN AlignMask;\r
+ VOID *Address;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ //\r
+ // Only allow accesses to the BARs we emulate\r
+ //\r
+ Status = GetBarResource (Dev, BarIndex, &Desc);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
+ AlignMask = (1 << (Width & 0x03)) - 1;\r
+ if ((UINTN)Address & AlignMask) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ case EfiPciWidthUint16:\r
+ case EfiPciWidthUint32:\r
+ case EfiPciWidthUint64:\r
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
+\r
+ case EfiPciWidthFifoUint8:\r
+ case EfiPciWidthFifoUint16:\r
+ case EfiPciWidthFifoUint32:\r
+ case EfiPciWidthFifoUint64:\r
+ return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);\r
+\r
+ case EfiPciWidthFillUint8:\r
+ case EfiPciWidthFillUint16:\r
+ case EfiPciWidthFillUint32:\r
+ case EfiPciWidthFillUint64:\r
+ return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);\r
+\r
+ default:\r
+ break;\r
+ }\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoIoRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoIoWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 BarIndex,\r
+ IN UINT64 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoPciRead (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ VOID *Address;\r
+ UINTN Length;\r
+\r
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
+ Length = Count << ((UINTN)Width & 0x3);\r
+\r
+ if (Offset + Length > sizeof (Dev->ConfigSpace)) {\r
+ //\r
+ // Read all zeroes for config space accesses beyond the first\r
+ // 64 bytes\r
+ //\r
+ Length -= sizeof (Dev->ConfigSpace) - Offset;\r
+ ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);\r
+\r
+ Count -= Length >> ((UINTN)Width & 0x3);\r
+ }\r
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoPciWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ VOID *Address;\r
+\r
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
+\r
+ if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoCopyMem (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT8 DestBarIndex,\r
+ IN UINT64 DestOffset,\r
+ IN UINT8 SrcBarIndex,\r
+ IN UINT64 SrcOffset,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+CoherentPciIoMap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_STATUS Status;\r
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
+\r
+ //\r
+ // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA\r
+ // addressing, we need to allocate a bounce buffer and copy over the data.\r
+ //\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
+ (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
+\r
+ //\r
+ // Bounce buffering is not possible for consistent mappings\r
+ //\r
+ if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ MapInfo = AllocatePool (sizeof *MapInfo);\r
+ if (MapInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MapInfo->AllocAddress = MAX_UINT32;\r
+ MapInfo->HostAddress = HostAddress;\r
+ MapInfo->Operation = Operation;\r
+ MapInfo->NumberOfBytes = *NumberOfBytes;\r
+\r
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
+ &MapInfo->AllocAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If we fail here, it is likely because the system has no memory below\r
+ // 4 GB to begin with. There is not much we can do about that other than\r
+ // fail the map request.\r
+ //\r
+ FreePool (MapInfo);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ if (Operation == EfiPciIoOperationBusMasterRead) {\r
+ gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,\r
+ *NumberOfBytes);\r
+ }\r
+ *DeviceAddress = MapInfo->AllocAddress;\r
+ *Mapping = MapInfo;\r
+ } else {\r
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
+ *Mapping = NULL;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+CoherentPciIoUnmap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
+\r
+ MapInfo = Mapping;\r
+ if (MapInfo != NULL) {\r
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
+ gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
+ MapInfo->NumberOfBytes);\r
+ }\r
+ gBS->FreePages (MapInfo->AllocAddress,\r
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));\r
+ FreePool (MapInfo);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+CoherentPciIoAllocateBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_PHYSICAL_ADDRESS AllocAddress;\r
+ EFI_ALLOCATE_TYPE AllocType;\r
+ EFI_STATUS Status;\r
+\r
+ if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Allocate below 4 GB if the dual address cycle attribute has not\r
+ // been set. If the system has no memory available below 4 GB, there\r
+ // is little we can do except propagate the error.\r
+ //\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
+ AllocAddress = MAX_UINT32;\r
+ AllocType = AllocateMaxAddress;\r
+ } else {\r
+ AllocType = AllocateAnyPages;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);\r
+ if (!EFI_ERROR (Status)) {\r
+ *HostAddress = (VOID *)(UINTN)AllocAddress;\r
+ }\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+CoherentPciIoFreeBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress\r
+ )\r
+{\r
+ FreePages (HostAddress, Pages);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoFlush (\r
+ IN EFI_PCI_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoGetLocation (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ OUT UINTN *SegmentNumber,\r
+ OUT UINTN *BusNumber,\r
+ OUT UINTN *DeviceNumber,\r
+ OUT UINTN *FunctionNumber\r
+ )\r
+{\r
+ if (SegmentNumber == NULL ||\r
+ BusNumber == NULL ||\r
+ DeviceNumber == NULL ||\r
+ FunctionNumber == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *SegmentNumber = 0;\r
+ *BusNumber = 0xff;\r
+ *DeviceNumber = 0;\r
+ *FunctionNumber = 0;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,\r
+ IN UINT64 Attributes,\r
+ OUT UINT64 *Result OPTIONAL\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ BOOLEAN Enable;\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ Enable = FALSE;\r
+ switch (Operation) {\r
+ case EfiPciIoAttributeOperationGet:\r
+ if (Result == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *Result = Dev->Attributes;\r
+ break;\r
+\r
+ case EfiPciIoAttributeOperationSupported:\r
+ if (Result == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
+ break;\r
+\r
+ case EfiPciIoAttributeOperationEnable:\r
+ Attributes |= Dev->Attributes;\r
+ case EfiPciIoAttributeOperationSet:\r
+ Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;\r
+ Dev->Attributes = Attributes;\r
+ break;\r
+\r
+ case EfiPciIoAttributeOperationDisable:\r
+ Dev->Attributes &= ~Attributes;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ };\r
+\r
+ //\r
+ // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform\r
+ // the device specific initialization now.\r
+ //\r
+ if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {\r
+ Dev->Device->Initialize (Dev->Device);\r
+ Dev->Enabled = TRUE;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoGetBarAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINT8 BarIndex,\r
+ OUT UINT64 *Supports OPTIONAL,\r
+ OUT VOID **Resources OPTIONAL\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;\r
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
+ EFI_STATUS Status;\r
+\r
+ if (Supports == NULL && Resources == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ Status = GetBarResource (Dev, BarIndex, &BarDesc);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Don't expose any configurable attributes for our emulated BAR\r
+ //\r
+ if (Supports != NULL) {\r
+ *Supports = 0;\r
+ }\r
+\r
+ if (Resources != NULL) {\r
+ Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
+ if (Descriptor == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CopyMem (Descriptor, BarDesc, sizeof *Descriptor);\r
+\r
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
+ End->Checksum = 0;\r
+\r
+ *Resources = Descriptor;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PciIoSetBarAttributes (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINT64 Attributes,\r
+ IN UINT8 BarIndex,\r
+ IN OUT UINT64 *Offset,\r
+ IN OUT UINT64 *Length\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =\r
+{\r
+ PciIoPollMem,\r
+ PciIoPollIo,\r
+ { PciIoMemRead, PciIoMemWrite },\r
+ { PciIoIoRead, PciIoIoWrite },\r
+ { PciIoPciRead, PciIoPciWrite },\r
+ PciIoCopyMem,\r
+ CoherentPciIoMap,\r
+ CoherentPciIoUnmap,\r
+ CoherentPciIoAllocateBuffer,\r
+ CoherentPciIoFreeBuffer,\r
+ PciIoFlush,\r
+ PciIoGetLocation,\r
+ PciIoAttributes,\r
+ PciIoGetBarAttributes,\r
+ PciIoSetBarAttributes,\r
+ 0,\r
+ 0\r
+};\r
+\r
+VOID\r
+InitializePciIoProtocol (\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev\r
+ )\r
+{\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
+ INTN Idx;\r
+\r
+ Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
+ Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
+\r
+ // Copy protocol structure\r
+ CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
+\r
+ if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
+ Dev->BarOffset = 5;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableEhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableNvmeDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableOhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableSdhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableUhciDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
+ Dev->BarOffset = 0;\r
+ } else if (CompareGuid (Dev->Device->Type,\r
+ &gEdkiiNonDiscoverableUfsDeviceGuid)) {\r
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;\r
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
+ Dev->BarOffset = 0;\r
+ } else {\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ //\r
+ // Iterate over the resources to populate the virtual BARs\r
+ //\r
+ Idx = Dev->BarOffset;\r
+ for (Desc = Dev->Device->Resources, Dev->BarCount = 0;\r
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
+\r
+ ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
+ ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);\r
+\r
+ if (Idx >= PCI_MAX_BARS ||\r
+ (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "%a: resource count exceeds number of emulated BARs\n",\r
+ __FUNCTION__));\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;\r
+ Dev->BarCount++;\r
+\r
+ if (Desc->AddrSpaceGranularity == 64) {\r
+ Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;\r
+ Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (\r
+ Desc->AddrRangeMin, 32);\r
+ }\r
+ }\r
+}\r