summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c')
-rw-r--r--MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c796
1 files changed, 796 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
new file mode 100644
index 0000000000..1e7244a129
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
@@ -0,0 +1,796 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+
+ 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.
+
+**/
+
+#include "NonDiscoverablePciDeviceIo.h"
+
+#include <IndustryStandard/Acpi.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS AllocAddress;
+ VOID *HostAddress;
+ EFI_PCI_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;
+
+//
+// Get the resource associated with BAR number 'BarIndex'.
+//
+STATIC
+EFI_STATUS
+GetBarResource (
+ IN NON_DISCOVERABLE_PCI_DEVICE *Dev,
+ IN UINT8 BarIndex,
+ OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+
+ if (BarIndex < Dev->BarOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ BarIndex -= Dev->BarOffset;
+
+ for (Desc = Dev->Device->Resources;
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
+
+ if (BarIndex == 0) {
+ *Descriptor = Desc;
+ return EFI_SUCCESS;
+ }
+
+ BarIndex -= 1;
+ }
+ return EFI_NOT_FOUND;
+}
+
+STATIC
+EFI_STATUS
+PciIoPollMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+PciIoPollIo (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+PciIoMemRW (
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINTN DstStride,
+ IN VOID *Dst,
+ IN UINTN SrcStride,
+ OUT CONST VOID *Src
+ )
+{
+ volatile UINT8 *Dst8;
+ volatile UINT16 *Dst16;
+ volatile UINT32 *Dst32;
+ volatile CONST UINT8 *Src8;
+ volatile CONST UINT16 *Src16;
+ volatile CONST UINT32 *Src32;
+
+ //
+ // Loop for each iteration and move the data
+ //
+ switch (Width & 0x3) {
+ case EfiPciWidthUint8:
+ Dst8 = (UINT8 *)Dst;
+ Src8 = (UINT8 *)Src;
+ for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
+ *Dst8 = *Src8;
+ }
+ break;
+ case EfiPciWidthUint16:
+ Dst16 = (UINT16 *)Dst;
+ Src16 = (UINT16 *)Src;
+ for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
+ *Dst16 = *Src16;
+ }
+ break;
+ case EfiPciWidthUint32:
+ Dst32 = (UINT32 *)Dst;
+ Src32 = (UINT32 *)Src;
+ for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
+ *Dst32 = *Src32;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciIoMemRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ UINTN AlignMask;
+ VOID *Address;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ //
+ // Only allow accesses to the BARs we emulate
+ //
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
+ AlignMask = (1 << (Width & 0x03)) - 1;
+ if ((UINTN)Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Width) {
+ case EfiPciWidthUint8:
+ case EfiPciWidthUint16:
+ case EfiPciWidthUint32:
+ case EfiPciWidthUint64:
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
+
+ case EfiPciWidthFifoUint8:
+ case EfiPciWidthFifoUint16:
+ case EfiPciWidthFifoUint32:
+ case EfiPciWidthFifoUint64:
+ return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);
+
+ case EfiPciWidthFillUint8:
+ case EfiPciWidthFillUint16:
+ case EfiPciWidthFillUint32:
+ case EfiPciWidthFillUint64:
+ return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);
+
+ default:
+ break;
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+STATIC
+EFI_STATUS
+PciIoMemWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ UINTN AlignMask;
+ VOID *Address;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ //
+ // Only allow accesses to the BARs we emulate
+ //
+ Status = GetBarResource (Dev, BarIndex, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
+ AlignMask = (1 << (Width & 0x03)) - 1;
+ if ((UINTN)Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Width) {
+ case EfiPciWidthUint8:
+ case EfiPciWidthUint16:
+ case EfiPciWidthUint32:
+ case EfiPciWidthUint64:
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
+
+ case EfiPciWidthFifoUint8:
+ case EfiPciWidthFifoUint16:
+ case EfiPciWidthFifoUint32:
+ case EfiPciWidthFifoUint64:
+ return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);
+
+ case EfiPciWidthFillUint8:
+ case EfiPciWidthFillUint16:
+ case EfiPciWidthFillUint32:
+ case EfiPciWidthFillUint64:
+ return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);
+
+ default:
+ break;
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+STATIC
+EFI_STATUS
+PciIoIoRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+PciIoIoWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+PciIoPciRead (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ VOID *Address;
+ UINTN Length;
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;
+ Length = Count << ((UINTN)Width & 0x3);
+
+ if (Offset + Length > sizeof (Dev->ConfigSpace)) {
+ //
+ // Read all zeroes for config space accesses beyond the first
+ // 64 bytes
+ //
+ Length -= sizeof (Dev->ConfigSpace) - Offset;
+ ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);
+
+ Count -= Length >> ((UINTN)Width & 0x3);
+ }
+ return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
+}
+
+STATIC
+EFI_STATUS
+PciIoPciWrite (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ VOID *Address;
+
+ if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ Address = (UINT8 *)&Dev->ConfigSpace + Offset;
+
+ if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
+}
+
+STATIC
+EFI_STATUS
+PciIoCopyMem (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+CoherentPciIoMap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_STATUS Status;
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+
+ //
+ // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
+ // addressing, we need to allocate a bounce buffer and copy over the data.
+ //
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
+ (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
+
+ //
+ // Bounce buffering is not possible for consistent mappings
+ //
+ if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MapInfo = AllocatePool (sizeof *MapInfo);
+ if (MapInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MapInfo->AllocAddress = MAX_UINT32;
+ MapInfo->HostAddress = HostAddress;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+ &MapInfo->AllocAddress);
+ if (EFI_ERROR (Status)) {
+ //
+ // If we fail here, it is likely because the system has no memory below
+ // 4 GB to begin with. There is not much we can do about that other than
+ // fail the map request.
+ //
+ FreePool (MapInfo);
+ return EFI_DEVICE_ERROR;
+ }
+ if (Operation == EfiPciIoOperationBusMasterRead) {
+ gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,
+ *NumberOfBytes);
+ }
+ *DeviceAddress = MapInfo->AllocAddress;
+ *Mapping = MapInfo;
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+CoherentPciIoUnmap (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
+
+ MapInfo = Mapping;
+ if (MapInfo != NULL) {
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
+ gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
+ MapInfo->NumberOfBytes);
+ }
+ gBS->FreePages (MapInfo->AllocAddress,
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));
+ FreePool (MapInfo);
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+CoherentPciIoAllocateBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_PHYSICAL_ADDRESS AllocAddress;
+ EFI_ALLOCATE_TYPE AllocType;
+ EFI_STATUS Status;
+
+ if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate below 4 GB if the dual address cycle attribute has not
+ // been set. If the system has no memory available below 4 GB, there
+ // is little we can do except propagate the error.
+ //
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+ if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+ AllocAddress = MAX_UINT32;
+ AllocType = AllocateMaxAddress;
+ } else {
+ AllocType = AllocateAnyPages;
+ }
+
+ Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);
+ if (!EFI_ERROR (Status)) {
+ *HostAddress = (VOID *)(UINTN)AllocAddress;
+ }
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+CoherentPciIoFreeBuffer (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ FreePages (HostAddress, Pages);
+ return EFI_SUCCESS;
+}
+
+
+STATIC
+EFI_STATUS
+PciIoFlush (
+ IN EFI_PCI_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciIoGetLocation (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *SegmentNumber,
+ OUT UINTN *BusNumber,
+ OUT UINTN *DeviceNumber,
+ OUT UINTN *FunctionNumber
+ )
+{
+ if (SegmentNumber == NULL ||
+ BusNumber == NULL ||
+ DeviceNumber == NULL ||
+ FunctionNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *SegmentNumber = 0;
+ *BusNumber = 0xff;
+ *DeviceNumber = 0;
+ *FunctionNumber = 0;
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciIoAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ BOOLEAN Enable;
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Enable = FALSE;
+ switch (Operation) {
+ case EfiPciIoAttributeOperationGet:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Result = Dev->Attributes;
+ break;
+
+ case EfiPciIoAttributeOperationSupported:
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
+ break;
+
+ case EfiPciIoAttributeOperationEnable:
+ Attributes |= Dev->Attributes;
+ case EfiPciIoAttributeOperationSet:
+ Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;
+ Dev->Attributes = Attributes;
+ break;
+
+ case EfiPciIoAttributeOperationDisable:
+ Dev->Attributes &= ~Attributes;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ };
+
+ //
+ // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
+ // the device specific initialization now.
+ //
+ if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
+ Dev->Device->Initialize (Dev->Device);
+ Dev->Enabled = TRUE;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciIoGetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports OPTIONAL,
+ OUT VOID **Resources OPTIONAL
+ )
+{
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ EFI_STATUS Status;
+
+ if (Supports == NULL && Resources == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
+
+ Status = GetBarResource (Dev, BarIndex, &BarDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Don't expose any configurable attributes for our emulated BAR
+ //
+ if (Supports != NULL) {
+ *Supports = 0;
+ }
+
+ if (Resources != NULL) {
+ Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Descriptor == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
+
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ *Resources = Descriptor;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+PciIoSetBarAttributes (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =
+{
+ PciIoPollMem,
+ PciIoPollIo,
+ { PciIoMemRead, PciIoMemWrite },
+ { PciIoIoRead, PciIoIoWrite },
+ { PciIoPciRead, PciIoPciWrite },
+ PciIoCopyMem,
+ CoherentPciIoMap,
+ CoherentPciIoUnmap,
+ CoherentPciIoAllocateBuffer,
+ CoherentPciIoFreeBuffer,
+ PciIoFlush,
+ PciIoGetLocation,
+ PciIoAttributes,
+ PciIoGetBarAttributes,
+ PciIoSetBarAttributes,
+ 0,
+ 0
+};
+
+VOID
+InitializePciIoProtocol (
+ NON_DISCOVERABLE_PCI_DEVICE *Dev
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
+ INTN Idx;
+
+ Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
+ Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
+
+ // Copy protocol structure
+ CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
+
+ if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 5;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableEhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableNvmeDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableOhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableSdhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableXhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableUhciDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
+ Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
+ Dev->BarOffset = 0;
+ } else if (CompareGuid (Dev->Device->Type,
+ &gEdkiiNonDiscoverableUfsDeviceGuid)) {
+ Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
+ Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
+ Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
+ Dev->BarOffset = 0;
+ } else {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Iterate over the resources to populate the virtual BARs
+ //
+ Idx = Dev->BarOffset;
+ for (Desc = Dev->Device->Resources, Dev->BarCount = 0;
+ Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
+ Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
+
+ ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
+
+ if (Idx >= PCI_MAX_BARS ||
+ (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: resource count exceeds number of emulated BARs\n",
+ __FUNCTION__));
+ ASSERT (FALSE);
+ break;
+ }
+
+ Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
+ Dev->BarCount++;
+
+ if (Desc->AddrSpaceGranularity == 64) {
+ Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
+ Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (
+ Desc->AddrRangeMin, 32);
+ }
+ }
+}