2016-10-31 16:36:50 +01:00
|
|
|
/** @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;
|
|
|
|
}
|
|
|
|
|
2016-12-08 09:17:22 +01:00
|
|
|
BarIndex -= (UINT8)Dev->BarOffset;
|
2016-10-31 16:36:50 +01:00
|
|
|
|
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
CoherentPciIoFreeBuffer (
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *This,
|
|
|
|
IN UINTN Pages,
|
|
|
|
IN VOID *HostAddress
|
|
|
|
)
|
|
|
|
{
|
|
|
|
FreePages (HostAddress, Pages);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
PciIoFlush (
|
|
|
|
IN EFI_PCI_IO_PROTOCOL *This
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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
|
2016-12-08 09:17:22 +01:00
|
|
|
EFIAPI
|
2016-10-31 16:36:50 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|